=
BEGIN OPEN TableBase;
ROPE: TYPE = Rope.ROPE;
indent: INTEGER ~ 4;
baseline: INTEGER ~ 16;
ToolData: TYPE = REF ToolDataRec;
ToolDataRec:
TYPE =
RECORD [
nameViewer: ViewerClasses.Viewer ← NIL,
msgViewer: ViewerClasses.Viewer ← NIL,
msgRope: ROPE ← NIL,
displayViewer: ViewerClasses.Viewer ← NIL,
selection: TableSelection.Selection ← NIL,
selectingRowOrColumn: TableSelection.KindOfSelection ← row,
callBackProc: DisplayProc ← NIL,
entry: RefTableEntry ← NIL,
beforeButton: Buttons.Button,
afterButton: Buttons.Button,
rowButton: Buttons.Button,
colButton: Buttons.Button,
rootOfTable: TextNode.Ref,
galley: TSObject.ItemList,
style: NodeStyle.Ref,
pleaseStop: BOOLEAN ← FALSE
];
DisplayProc: TYPE = PROCEDURE [dc: Imager.Context, toolData: ToolData];
TableToolInitProc: ViewerClasses.InitProc = {
toolData: ToolData ← NEW[ToolDataRec];
nextX: INTEGER;
curY: INTEGER ← 0;
NextY: PROCEDURE RETURNS [y:NAT] = {y ← curY ← curY+baseline};
button: ViewerClasses.Viewer;
rule: Rules.Rule;
menu: Menus.Menu ← Menus.CreateMenu[];
InsertMenu:
PROCEDURE [name:
ROPE, proc: Menus.ClickProc, doc:
ROPE] = {
Menus.InsertMenuEntry[menu, Menus.CreateEntry[
name: name,
proc: proc,
clientData: toolData,
documentation: doc
]];
};
LabelledTextViewer:
PROCEDURE [name:
ROPE]
RETURNS [v: ViewerClasses.Viewer] = {
v ← ViewerTools.MakeNewTextViewer[
info:[wx: button.wx+button.ww, wy: curY, ww: 50, wh: button.wh,
parent: self, scrollable: FALSE, border: FALSE],
paint: TRUE
];
button ← Labels.Create[
info: [name: name, wx: v.wx + v.ww, wy: curY+1, wh: button.wh, parent: self, scrollable: FALSE, border: FALSE],
paint: TRUE
];
};
MyButton:
PROCEDURE [name:
ROPE, x, y:
NAT, proc: Buttons.ButtonProc, doc:
ROPE ← NIL]
RETURNS [Buttons.Button] = {
RETURN [Buttons.Create[
info: [name: name, wx: x, wy: y, parent: self, border: FALSE],
clientData: toolData,
proc: proc,
fork: TRUE,
paint: TRUE,
documentation: doc
]]};
ViewerOps.AddProp[self, $TableToolData, toolData];
containerInitProc[self]; -- since I know its really a $Container, I need to init it for him
InsertMenu["DisplayNextTable", DisplayNextTableButton, "Displays the next table found in the document"];
InsertMenu["DisplaySelectedTable", DisplaySelectedTableButton, "Displays the table containing the selection"];
InsertMenu["DisplayDocument", DisplayDocumentButton, "Displays the document"];
InsertMenu["ABORT!", AbortButton, "Aborts the formatting process"];
ViewerOps.SetMenu[self, menu];
toolData.beforeButton ← MyButton[name: "Before ", x: indent, y: curY, proc: BeforeButton];
toolData.afterButton ← MyButton[name: "After ", x: toolData.beforeButton.wx+toolData.beforeButton.ww, y: curY, proc: AfterButton];
rule ← Rules.Create[info: [parent: self, wx: toolData.afterButton.wx+toolData.afterButton.ww, wy: curY, ww: 1, wh: toolData.afterButton.wh+1]];
toolData.rowButton ← MyButton[name: "Row ", x: rule.wx+rule.ww, y: curY, proc: RowButton];
toolData.colButton ← MyButton[name: "Col ", x: toolData.rowButton.wx+toolData.rowButton.ww, y: curY, proc: ColButton];
rule ← Rules.Create[info: [parent: self, wx: toolData.colButton.wx+toolData.colButton.ww, wy: curY, ww: 1, wh: toolData.colButton.wh+1]];
button ← MyButton[name: "Delete ", x: rule.wx+rule.ww, y: curY, proc: DeleteSelButton];
button ← MyButton[name: "Duplicate ", x: button.wx+button.ww, y: curY, proc: DuplicateSelButton];
button ← MyButton[name: "MakeHeader ", x: button.wx+button.ww, y: curY, proc: MakeHeaderButton];
button ← MyButton[name: "Append ", x: button.wx+button.ww, y: curY, proc: AppendButton];
button ← MyButton[name: "Transpose ", x: button.wx+button.ww, y: curY, proc: TransposeButton];
rule ← Rules.Create[info: [parent: self, wx: 0, wy: NextY[], ww: 999, wh: 1]];
Containers.ChildXBound[self, rule];
curY ← curY + 2;
button ← MyButton[name: "DocumentName: ", x: indent, y: curY, proc: DocumentNameButton, doc: "Left-click to get selected document name; Middle-click to make current name pending-delete; Right-click to clear the name viewer."];
toolData.nameViewer ← ViewerTools.MakeNewTextViewer[
info:[wx: button.wx+button.ww, wy: curY+1, ww: 50, wh: baseline,
parent: self, scrollable: TRUE, border: FALSE],
paint: TRUE
];
Containers.ChildXBound[self, toolData.nameViewer];
rule ← Rules.Create[info: [parent: self, wx: 0, wy: NextY[]+1, ww: 999, wh: 1]];
Containers.ChildXBound[self, rule];
curY ← curY + 2;
toolData.msgViewer ← ViewerTools.MakeNewTextViewer[
info:[wx: 0, wy: curY, ww: 50, wh: baseline,
parent: self, scrollable: TRUE, border: FALSE],
paint: TRUE
];
Containers.ChildXBound[self, toolData.msgViewer];
rule ← Rules.Create[info: [parent: self, wx: 0, wy: NextY[], ww: 999, wh: 1]];
Containers.ChildXBound[self, rule];
curY ← curY + 2;
toolData.displayViewer ← ViewerOps.CreateViewer[
flavor: $TSDisplay,
info: [
wx: 0, wy: curY, ww: 50, wh: baseline,
border: FALSE,
parent: self,
scrollable: FALSE],
paint: TRUE];
IF originalTSDisplayPaintProc =
NIL
THEN
originalTSDisplayPaintProc ← toolData.displayViewer.class.paint;
Containers.ChildXBound[self, toolData.displayViewer];
Containers.ChildYBound[self, toolData.displayViewer];
};
TableToolDestroyProc: ViewerClasses.DestroyProc = {
toolData: ToolData ~ ToolDataFromViewer[self];
IF toolData #
NIL
AND toolData.selection #
NIL AND toolData.selection.table #
NIL
THEN {
BreakTableLinks[toolData.selection.table];
toolData.selection ← NIL;
};
IF containerDestroyProc # NIL THEN containerDestroyProc[self];
};
TableToolPaintProc: ViewerClasses.PaintProc = {
PROC [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL];
IF containerPaintProc # NIL THEN [] ← containerPaintProc[self, context, whatChanged, clear];
IF whatChanged =
NIL
AND clear
THEN {
toolData: ToolData ← ToolDataFromViewer[self];
IF toolData #
NIL
AND toolData.galley #
NIL
THEN
TRUSTED { Process.Detach[FORK DisplayTable[toolData]]; };
};
};
AbortButton: Menus.ClickProc = {
toolData: ToolData ~ NARROW[clientData];
toolData.pleaseStop ← TRUE;
};
DisplayDocumentButton: Menus.ClickProc = {
toolData: ToolData ~ NARROW[clientData];
docName: ROPE ~ ViewerTools.GetContents[toolData.nameViewer];
v: ViewerClasses.Viewer ~ ViewerOps.FindViewer[docName];
errorMsg: ROPE ← NIL;
root: TextNode.Ref;
toolData.pleaseStop ← FALSE;
IF v #
NIL
THEN
TRUSTED { root ← LOOPHOLE[TiogaOps.ViewerDoc[v]] }
ELSE
root ← PutGet.FromFile[docName ! FS.Error => {errorMsg ← error.explanation; CONTINUE}];
IF errorMsg #
NIL
THEN
AppendLogMessage[toolData, Rope.Cat["Document \"", docName, "\" was not found for the reason: ", errorMsg]]
ELSE
IF root =
NIL
THEN
AppendLogMessage[toolData, Rope.Cat["Viewer \"", docName, "\" wasn't found."]]
ELSE {
FormatTableFromRoot[toolData, root];
DisplayTable[toolData];
};
};
DisplaySelectedTableButton: Menus.ClickProc = {
toolData: ToolData ~ NARROW[clientData];
v: ViewerClasses.Viewer;
start: TiogaOps.Location;
toolData.pleaseStop ← FALSE;
get node from selection
[v, start] ← TiogaOps.GetSelection[primary];
IF v =
NIL
THEN
AppendLogMessage[toolData, "No primary selection for a selected table."]
ELSE
TRUSTED {
node: TextNode.Ref ← LOOPHOLE[start.node];
WHILE node #
NIL
AND
NOT ATableNode[node]
DO
node ← TextNode.Parent[node];
ENDLOOP;
IF node =
NIL
THEN
AppendLogMessage[toolData, "Selected node is not in a table with ArtworkClass Table."]
ELSE {
FormatTableFromRoot[toolData, node];
DisplayTable[toolData];
ViewerTools.SetContents[toolData.nameViewer, v.name];
};
};
};
ATableNode:
PROC [node: TextNode.Ref]
RETURNS [
BOOLEAN] ~ {
IF node = NIL THEN RETURN [FALSE]
ELSE {
artworkClass: ROPE ← NARROW[NodeProps.GetProp[node, $ArtworkClass]];
RETURN[artworkClass.Equal["Table"]];
};
};
DisplayNextTableButton: Menus.ClickProc = {
toolData: ToolData ~ NARROW[clientData];
toolData.pleaseStop ← FALSE;
IF toolData.rootOfTable =
NIL
THEN
AppendLogMessage[toolData, "No table previously displayed so I can't find the next one."]
ELSE {
search from rootOfTable to end of document for the next table
node: TextNode.Ref ← TextNode.Forward[toolData.rootOfTable].nx;
WHILE node #
NIL
AND
NOT ATableNode[node]
DO
node ← TextNode.Forward[node].nx;
ENDLOOP;
IF node =
NIL
THEN {
search from the root of the document until rootOfTable for the next table
node ← TextNode.Root[toolData.rootOfTable];
WHILE node #
NIL
AND node # toolData.rootOfTable
AND
NOT ATableNode[node]
DO
node ← TextNode.Forward[node].nx;
ENDLOOP;
};
IF node =
NIL
OR node = toolData.rootOfTable
THEN
AppendLogMessage[toolData, "Sorry, no other table found in document."]
ELSE {
we have another table, so format and display it
FormatTableFromRoot[toolData, node];
DisplayTable[toolData];
};
};
};
DocumentNameButton: Buttons.ButtonProc = {
toolData: ToolData ← NARROW[clientData];
IF mouseButton = red
THEN {
selectedViewer: ViewerClasses.Viewer ← ViewerTools.GetSelectedViewer[];
sourceName:
ROPE ←
IF selectedViewer = NIL OR selectedViewer.class.get = NIL THEN NIL
ELSE NARROW[selectedViewer.class.get[selectedViewer, $SelChars]];
IF sourceName.Length <= 1
THEN {
IF (selectedViewer =
NIL)
THEN {
AppendLogMessage[toolData, "Selection not in text viewer"];
RETURN;
}
ELSE {
WHILE sourceName.Length <= 1
AND selectedViewer #
NIL
DO
sourceName ← selectedViewer.name;
selectedViewer ← selectedViewer.parent;
ENDLOOP;
};
};
IF sourceName.Length > 1
THEN {
selectedViewer ← ViewerOps.FindViewer[sourceName];
IF selectedViewer =
NIL THEN
AppendLogMessage[toolData, Rope.Cat["Viewer \"", sourceName, "\" wasn't found."]]
ELSE {
ViewerTools.SetContents[toolData.nameViewer, sourceName];
};
};
}
ELSE {
ViewerTools.SetContents[toolData.nameViewer, ""];
};
ViewerTools.SetSelection[toolData.nameViewer];
};
BeforeButton: Buttons.ButtonProc ~ {
toolData: ToolData ← NARROW[clientData];
IF toolData.selection #
NIL
THEN {
toolData.selection.insertion ← before;
Buttons.SetDisplayStyle[toolData.beforeButton, $WhiteOnBlack];
Buttons.SetDisplayStyle[toolData.afterButton, $BlackOnWhite];
};
};
AfterButton: Buttons.ButtonProc ~ {
toolData: ToolData ← NARROW[clientData];
IF toolData.selection #
NIL THEN {
toolData.selection.insertion ← after;
Buttons.SetDisplayStyle[toolData.beforeButton, $BlackOnWhite];
Buttons.SetDisplayStyle[toolData.afterButton, $WhiteOnBlack];
};
};
RowButton: Buttons.ButtonProc ~ {
toolData: ToolData ← NARROW[clientData];
toolData.selectingRowOrColumn ← row;
Buttons.SetDisplayStyle[toolData.rowButton, $WhiteOnBlack];
Buttons.SetDisplayStyle[toolData.colButton, $BlackOnWhite];
};
ColButton: Buttons.ButtonProc ~ {
toolData: ToolData ← NARROW[clientData];
toolData.selectingRowOrColumn ← column;
Buttons.SetDisplayStyle[toolData.rowButton, $BlackOnWhite];
Buttons.SetDisplayStyle[toolData.colButton, $WhiteOnBlack];
};
DeleteSelButton: Buttons.ButtonProc ~ {
toolData: ToolData ← NARROW[clientData];
IF NOT TableSelection.AnEmptySelection[toolData.selection] THEN
DoDeleteSelection[toolData, toolData.selection.startBox, toolData.selection.kind];
};
DuplicateSelButton: Buttons.ButtonProc ~ {
toolData: ToolData ← NARROW[clientData];
IF NOT TableSelection.AnEmptySelection[toolData.selection] THEN
DoDuplicateRowOrCol[toolData, toolData.selection.startBox, toolData.selection.kind];
};
TransposeButton: Buttons.ButtonProc ~ {
toolData: ToolData ← NARROW[clientData];
IF NOT TableSelection.AnEmptySelection[toolData.selection] THEN
DoTransposeTable[toolData, toolData.selection.startBox];
};
MakeHeaderButton: Buttons.ButtonProc ~ {
toolData: ToolData ← NARROW[clientData];
IF NOT TableSelection.AnEmptySelection[toolData.selection] THEN
DoMakeRowOrColHeader[toolData, toolData.selection.startBox, toolData.selection.kind];
};
AppendButton: Buttons.ButtonProc ~ {
toolData: ToolData ← NARROW[clientData];
IF NOT TableSelection.AnEmptySelection[toolData.selection] THEN
DoAppendRowOrCol[toolData, toolData.selection.startBox, toolData.selection.kind];
};
ToolDataFromViewer:
PROCEDURE [v: ViewerClasses.Viewer]
RETURNS [toolData: ToolData] = {
IF v # NIL THEN RETURN [NARROW[ViewerOps.FetchProp[v, $TableToolData]]];
};
TableFromViewer:
PROCEDURE [v: ViewerClasses.Viewer]
RETURNS [table: RefTable ←
NIL] = {
r: REF ANY ~ ViewerOps.FetchProp[v, $TableRef];
IF r #
NIL
AND
ISTYPE[r, RefTable]
THEN
table ← NARROW[r, RefTable];
};
OutputHandleForTool:
PROCEDURE [toolData: ToolData]
RETURNS [handle: TSOutput.Handle]= {
IF toolData #
NIL
AND toolData.displayViewer #
NIL
THEN
handle ← NARROW[ViewerOps.FetchProp[toolData.displayViewer, $TSDisplayHandle]];
};
FormatTableFromRoot:
PROC [toolData: ToolData, rootOfTable: TextNode.Ref] ~ {
ENABLE UNWIND => toolData.pleaseStop ← TRUE;
copyRoot: TextNode.Ref;
IF toolData.pleaseStop THEN RETURN;
copyRoot ← TextNode.Root[ -- copy the subtree for the slow TSetter to avoid locking issues
EditSpanSupport.CopySpan[ -- adds an extra root node
TextNode.MakeNodeSpan[rootOfTable, TextNode.LastWithin[rootOfTable]]].start.node];
copyRoot ← TextNode.FirstChild[copyRoot];
[toolData.galley, toolData.style] ← TSTranslate.TreeToVlist[copyRoot];
[toolData.galley, toolData.style] ← TSTranslate.TreeToVlist[rootOfTable];
toolData.rootOfTable ← rootOfTable;
};
DisplayTable:
PROCEDURE [toolData: ToolData] = {
IF toolData.pleaseStop THEN RETURN;
UnHookNotifier[toolData];
IF NOT TableSelection.AnEmptySelection[toolData.selection] THEN TakeDownSelection[toolData];
DisplayFormattedTable[toolData];
toolData.selection ← TableSelection.NewSelection[TableFromViewer[toolData.displayViewer]];
HookUpNotifier[toolData];
};
DisplayFormattedTable:
PROCEDURE [toolData: ToolData] = {
aborted: BOOLEAN ← FALSE;
isAborted: PROC RETURNS [BOOLEAN] = { RETURN[toolData.pleaseStop] };
handle: TSOutput.Handle ~ OutputHandleForTool[toolData];
aborted ← TSJaMPageBuilder.RunPageBuilder[
galley: toolData.galley,
style: toolData.style,
output: handle,
abortCheckProc: isAborted,
documentName: NIL
];
handle.finishProc[handle];
toolData.pleaseStop ← toolData.pleaseStop OR aborted;
};
AppendLogMessage:
PROCEDURE [toolData: ToolData, msg:
ROPE] = {
toolData.msgRope ← toolData.msgRope.Cat[msg, "\n"];
ViewerTools.SetContents[toolData.msgViewer, toolData.msgRope];
[] ← toolData.msgViewer.class.scroll[toolData.msgViewer, thumb, 100];
TEditSelection.InvalidateLineCache[]; -- shouldn't be needed in Cedar6.0, try without it
};
HookUpNotifier:
PROCEDURE [toolData: ToolData] = {
v: ViewerClasses.Viewer ~ toolData.displayViewer;
IF v #
NIL
THEN {
v.class.tipTable ← tableToolTIPTable;
v.tipTable ← tableToolTIPTable;
v.class.notify ← TableToolNotifier;
v.class.paint ← TableToolTSDisplayPaintProc;
};
};
UnHookNotifier:
PROCEDURE [toolData: ToolData] = {
v: ViewerClasses.Viewer ~ toolData.displayViewer;
IF v #
NIL
THEN {
v.class.notify ← NoOpNotifier;
v.class.paint ← originalTSDisplayPaintProc;
};
};
NoOpNotifier: ViewerClasses.NotifyProc = { RETURN; };
TableToolNotifier: ViewerClasses.NotifyProc = {
toolData: ToolData ← ToolDataFromViewer[self.parent];
{
mouse: TIPUser.TIPScreenCoords;
selectedBox: RefTableBox;
InputFocus.SetInputFocus[toolData.displayViewer];
FOR list:
LIST
OF
REF
ANY ← input, list.rest
UNTIL list =
NIL
DO
WITH list.first
SELECT
FROM
x:
ATOM =>
SELECT x
FROM
$InsertBefore => {
toolData.selection.insertion ← before;
};
$InsertAfter => {
toolData.selection.insertion ← after;
};
$Row => {
toolData.selectingRowOrColumn ← row;
};
$Column => {
toolData.selectingRowOrColumn ← column;
};
$SelBox => {
DoSelectBox[toolData, selectedBox];
};
$SelRow => {
DoSelectRowOrCol[toolData, selectedBox, row];
};
$SelCol => {
DoSelectRowOrCol[toolData, selectedBox, column ! CouldNotDoIt => GOTO Blink];
};
$SelUpdate => {
DoSelectUpdate[toolData, selectedBox];
};
$SelExpand => {
DoSelectExpand[toolData, selectedBox];
};
$SelReduce => {
DoSelectReduce[toolData, selectedBox];
};
$SelExtend => {
DoSelectExtend[toolData, selectedBox];
};
$DuplicateRowOrCol => {
DoDuplicateRowOrCol[toolData, selectedBox];
};
$DeleteSelection => {
DoDeleteSelection[toolData, selectedBox];
};
$TransposeTable => {
DoTransposeTable[toolData, selectedBox];
};
$MakeRowOrColHeader => {
DoMakeRowOrColHeader[toolData, selectedBox];
};
$AppendRowOrCol => {
DoAppendRowOrCol[toolData, selectedBox];
};
ENDCASE => NULL;
z: TIPUser.TIPScreenCoords => {
mouse ← z;
selectedBox ← ResolveMouseToBox[toolData, mouse];
};
ENDCASE => ERROR;
ENDLOOP;
EXITS
Blink => ViewerOps.BlinkIcon[toolData.displayViewer];
};
};
CouldNotDoIt: SIGNAL = CODE;
DoSelectBox:
PROCEDURE [toolData: ToolData, selectedBox: RefTableBox] = {
IF selectedBox #
NIL
THEN {
TakeDownSelection[toolData];
toolData.selection.list ← LIST[NEW[TableSelection.SelectedThingRec ← [box~selectedBox]]];
toolData.selection.kind ← box;
PutUpSelection[toolData];
};
};
DoSelectRowOrCol:
PROCEDURE [toolData: ToolData, selectedBox: RefTableBox,
which: TableSelection.KindOfSelection] = {
IF selectedBox #
NIL
THEN {
IF which # row AND which # column THEN SIGNAL CouldNotDoIt;
IF toolData.selection.kind # which --
OR
NOT TableSelection.WithinSelection[toolData.selection, selectedBox]--
THEN {
Update the selection
TakeDownSelection[toolData];
TableSelection.GrowSelection[toolData.selection, IF which = row THEN row ELSE column];
PutUpSelection[toolData];
};
};
};
DoSelectUpdate:
PROCEDURE [toolData: ToolData, selectedBox: RefTableBox] = {
IF selectedBox #
NIL
AND TableSelection.ASingleSelection[toolData.selection]
THEN {
SELECT toolData.selection.kind
FROM
box => {
IF toolData.selection.list.first.box # selectedBox
THEN {
TakeDownSelection[toolData];
toolData.selection.list ← LIST[NEW[TableSelection.SelectedThingRec ← [box~selectedBox]]];
PutUpSelection[toolData];
};
};
row, column => {
selectedBox ← SELECT toolData.selection.kind FROM
row => RowRootOf[selectedBox, TRUE],
column => ColRootOf[selectedBox, TRUE],
ENDCASE => ERROR;
IF toolData.selection.startBox # selectedBox THEN {
TakeDownSelection[toolData];
toolData.selection.startBox ← toolData.selection.endBox ← selectedBox;
PutUpSelection[toolData];
};
};
ENDCASE => ERROR;
};
};
DoSelectExpand :
PROCEDURE [toolData: ToolData, selectedBox: RefTableBox] = {
IF selectedBox #
NIL
AND
NOT TableSelection.AnEmptySelection[toolData.selection]
THEN {
TakeDownSelection[toolData];
SELECT toolData.selection.kind
FROM
box => TableSelection.GrowSelection[toolData.selection, row];
row => TableSelection.GrowSelection[toolData.selection, row];
column => TableSelection.GrowSelection[toolData.selection, column];
table => NULL;
ENDCASE => ERROR;
PutUpSelection[toolData];
};
};
DoSelectReduce:
PROCEDURE [toolData: ToolData, selectedBox: RefTableBox] = {
IF selectedBox #
NIL
AND
NOT TableSelection.AnEmptySelection[toolData.selection]
THEN {
currentSelection: TableSelection.SelectionRec ~ toolData.selection^;
TakeDownSelection[toolData];
SELECT currentSelection.kind
FROM
box => {
toolData.selection.startBox ← toolData.selection.endBox ← selectedBox;
};
row => {
selectedBox ← RowRootOf[selectedBox, TRUE];
IF BoxBeforeBox[selectedBox, currentSelection.startBox] THEN {
toolData.selection.startBox ← selectedBox;
toolData.selection.endBox ← currentSelection.endBox;
}
ELSE {
toolData.selection.startBox ← currentSelection.startBox;
toolData.selection.endBox ← selectedBox;
};
};
column => {
selectedBox ← ColRootOf[selectedBox, TRUE];
IF BoxBeforeBox[selectedBox, currentSelection.startBox] THEN {
toolData.selection.startBox ← selectedBox;
toolData.selection.endBox ← currentSelection.endBox;
}
ELSE {
toolData.selection.startBox ← currentSelection.startBox;
toolData.selection.endBox ← selectedBox;
};
};
ENDCASE => ERROR;
PutUpSelection[toolData];
};
};
DoSelectExtend:
PROCEDURE [toolData: ToolData, selectedBox: RefTableBox] = {
IF selectedBox #
NIL
AND
NOT TableSelection.AnEmptySelection[toolData.selection]
THEN {
currentSelection: TableSelection.SelectionRec ~ toolData.selection^;
SELECT currentSelection.kind
FROM
box => NULL;
row => {
selectedBox ← RowRootOf[selectedBox, TRUE];
IF NOT AreRowSiblings[selectedBox, currentSelection.startBox] THEN RETURN;
};
column => {
selectedBox ← ColRootOf[selectedBox, TRUE];
IF NOT AreColSiblings[selectedBox, currentSelection.startBox] THEN RETURN;
};
ENDCASE => ERROR;
TakeDownSelection[toolData];
IF BoxBeforeBox[selectedBox, currentSelection.startBox] THEN {
toolData.selection.startBox ← selectedBox;
toolData.selection.endBox ← currentSelection.endBox;
}
ELSE {
toolData.selection.startBox ← currentSelection.startBox;
toolData.selection.endBox ← selectedBox;
};
Could use optimization that paints incremental changes in the selection
PutUpSelection[toolData];
};
};
DoDeleteSelection:
PROCEDURE [toolData: ToolData, selectedBox: RefTableBox] = {
IF selectedBox #
NIL
AND
NOT TableSelection.AnEmptySelection[toolData.selection]
THEN {
currentSelection: TableSelection.SelectionRec ~ toolData.selection^;
IF toolData.selectingRowOrColumn = box THEN GOTO Blink;
selectedBox ← SELECT toolData.selectingRowOrColumn FROM
row => RowRootOf[selectedBox, TRUE],
column => ColRootOf[selectedBox, TRUE],
ENDCASE => ERROR;
IF currentSelection.kind = box AND selectedBox # currentSelection.startBox THEN
GOTO Blink;
TakeDownSelection[toolData];
SELECT toolData.selection.kind FROM
row => TableOps.DeleteRowStructure[currentSelection.startBox];
column => TableOps.DeleteColStructure[currentSelection.startBox];
ENDCASE => GOTO Blink;
RefreshTableDisplay[toolData];
};
EXITS
Blink => ViewerOps.BlinkIcon[toolData.displayViewer];
};
DoDuplicateRowOrCol:
PROCEDURE [toolData: ToolData, selectedBox: RefTableBox] = {
IF selectedBox #
NIL
AND
NOT TableSelection.AnEmptySelection[toolData.selection]
THEN {
currentSelection: TableSelection.SelectionRec ~ toolData.selection^;
IF currentSelection.kind = box THEN GOTO Blink;
selectedBox ← SELECT toolData.selectingRowOrColumn FROM
row => RowRootOf[selectedBox, TRUE],
column => ColRootOf[selectedBox, TRUE],
ENDCASE => ERROR;
TakeDownSelection[toolData];
SELECT currentSelection.kind
FROM
row => {
IF AreRowSiblings[selectedBox, currentSelection.startBox] AND
currentSelection.startBox # FirstRowChild[currentSelection.table.tableRoot] THEN
TableOps.CopyRowStructure[currentSelection.startBox, selectedBox, currentSelection.insertion, TRUE]
ELSE GOTO Blink;
};
column => {
IF AreColSiblings[selectedBox, currentSelection.startBox] AND
currentSelection.startBox # FirstColChild[currentSelection.table.tableRoot] THEN
TableOps.CopyColStructure[currentSelection.startBox, selectedBox, currentSelection.insertion, TRUE]
ELSE GOTO Blink;
};
ENDCASE => GOTO Blink;
RefreshTableDisplay[toolData];
};
EXITS
Blink => ViewerOps.BlinkIcon[toolData.displayViewer];
};
DoTransposeTable:
PROCEDURE [toolData: ToolData, selectedBox: RefTableBox] = {
IF selectedBox #
NIL
AND
NOT TableSelection.AnEmptySelection[toolData.selection]
THEN {
TakeDownSelection[toolData];
TableOps.TransposeTable[toolData.selection.table];
RefreshTableDisplay[toolData];
};
};
DoMakeRowOrColHeader:
PROCEDURE [toolData: ToolData, selectedBox: RefTableBox] = {
IF selectedBox #
NIL
AND
NOT TableSelection.AnEmptySelection[toolData.selection]
AND toolData.selection.kind = toolData.selectingRowOrColumn
THEN {
currentSelection: TableSelection.SelectionRec ~ toolData.selection^;
TakeDownSelection[toolData];
SELECT toolData.selectingRowOrColumn FROM
row =>
TableOps.MakeRowHeader[currentSelection.table, currentSelection.startBox, currentSelection.endBox];
column =>
TableOps.MakeColHeader[currentSelection.table, currentSelection.startBox, currentSelection.endBox];
ENDCASE => GOTO Blink;
RefreshTableDisplay[toolData];
};
};
DoAppendRowOrCol:
PROCEDURE [toolData: ToolData, selectedBox: RefTableBox] = {
IF selectedBox #
NIL
AND
NOT TableSelection.AnEmptySelection[toolData.selection]
THEN {
TakeDownSelection[toolData];
SELECT toolData.selectingRowOrColumn FROM
row => TableOps.AppendRow[toolData.selection.table];
column => TableOps.AppendCol[toolData.selection.table];
ENDCASE => SIGNAL CouldNotDoIt;
RefreshTableDisplay[toolData];
};
};
RefreshTableDisplay:
PROCEDURE [toolData: ToolData] = {
oldBranch, oldBranchRoot: TextNode.Ref;
newBranch: TextNode.Ref;
IF NOT TableSelection.AnEmptySelection[toolData.selection] THEN TakeDownSelection[toolData];
newBranch ← TableToBranch[toolData.selection.table];
oldBranch ← toolData.selection.table.branch;
oldBranchRoot ← TextNode.Root[oldBranch];
TRUSTED { TiogaOps.Lock[LOOPHOLE[oldBranchRoot]] };
[] ← EditSpan.MoveOnto[
destRoot: oldBranchRoot,
sourceRoot: TextNode.Root[newBranch],
dest: TextNode.MakeNodeSpan[oldBranch, TextNode.LastWithin[oldBranch]],
source: TextNode.MakeNodeSpan[newBranch, TextNode.LastWithin[newBranch]]];
TRUSTED { TiogaOps.Unlock[LOOPHOLE[oldBranchRoot]] };
BreakTableLinks[toolData.selection.table];
toolData.selection ← NIL;
DisplayTable[toolData];
};
BreakTableLinks:
PROCEDURE [table: RefTable] = {
table.tableGrid ← NIL;
table.rowGridPositions ← NIL;
table.colGridPositions ← NIL;
};
ResolveMouseToBox:
PROCEDURE [toolData: ToolData, mouse: TIPUser.TIPScreenCoords]
RETURNS [box: RefTableBox ←
NIL] = {
IF toolData.selection #
NIL
THEN {
handle: TSOutput.Handle ~ OutputHandleForTool[toolData];
table: RefTable ~ toolData.selection.table;
displayState: TSOutputDisplay.DisplayState ~ NARROW[handle.outputState];
box ← TableSelection.ResolveToBox[table: table, x: [mouse.mouseX - table.originX], y: [mouse.mouseY - (toolData.displayViewer.ch - displayState.pageHeight) - table.originY]];
};
};
BoxBeforeBox:
PROCEDURE [first, second: RefTableBox]
RETURNS [before:
BOOLEAN] = {
RETURN [(first.x.SubDimn[first.boxExtents[left]] <= second.x.SubDimn[second.boxExtents[left]]) AND
(first.y.AddDimn[first.boxExtents[up]] >= second.y.AddDimn[second.boxExtents[up]])]
};
TakeDownSelection:
PROCEDURE [toolData: ToolData] = {
IF
NOT TableSelection.AnEmptySelection[toolData.selection]
THEN
PaintSelection[toolData];
toolData.selection.list ← NIL;
};
PutUpSelection:
PROCEDURE [toolData: ToolData] = {
IF
NOT TableSelection.AnEmptySelection[toolData.selection]
THEN
PaintSelection[toolData];
};
PaintSelection:
PROCEDURE [toolData: ToolData] = {
selection: TableSelection.Selection ~ toolData.selection;
PaintSelectedBox: EnumeratedEntryProc = {
toolData.entry ← entry;
Painter[InvertTableBox, toolData];
};
FOR list:
LIST
OF TableSelection.SelectedThing ← selection.list, list.rest
WHILE list #
NIL
DO
SELECT selection.kind
FROM
box => {
[] ← PaintSelectedBox[selection.table, list.first.box];
};
row => {
EnumerateTable[table~selection.table, entryProc~PaintSelectedBox, top~list.first.grid1, bottom~list.first.grid2];
};
column => {
EnumerateTable[table~selection.table, entryProc~PaintSelectedBox, left~list.first.grid1, right~list.first.grid2];
};
ENDCASE => ERROR;
ENDLOOP;
};
InvertTableBox: DisplayProc = {
PROCEDURE [dc: Imager.Context, toolData: ToolData]
handle: TSOutput.Handle ~ OutputHandleForTool[toolData];
selection: TableSelection.Selection ~ toolData.selection;
table: RefTable ~ selection.table;
displayState: TSOutputDisplay.DisplayState ~ NARROW[handle.outputState];
xOffset: REAL ~ table.originX;
yOffset: REAL ~ table.originY + (toolData.displayViewer.ch - displayState.pageHeight);
oldColor: Imager.Color ~ ImagerBackdoor.GetColor[dc];
entry: RefTableEntry ~ toolData.entry;
llx: REAL ~ xOffset + table.colGridPositions[entry.left].texPts;
lly: REAL ~ yOffset + table.rowGridPositions[entry.bottom].texPts;
urx: REAL ~ xOffset + table.colGridPositions[entry.right].texPts;
ury: REAL ~ yOffset + table.rowGridPositions[entry.top].texPts;
Imager.SetColor[dc, ImagerBackdoor.invert];
Imager.MaskBox[dc, [llx, lly, urx, ury]];
Imager.SetColor[dc, oldColor];
};
Painter:
PROCEDURE [proc: DisplayProc, toolData: ToolData] =
{
toolData.callBackProc ← proc;
ViewerOps.PaintViewer[viewer: toolData.displayViewer, hint: client, whatChanged: toolData, clearClient: FALSE];
};
TableToolTSDisplayPaintProc: ViewerClasses.PaintProc = {
IF whatChanged #
NIL
AND
ISTYPE[whatChanged, ToolData]
THEN {
toolData: ToolData ~ NARROW[whatChanged, ToolData];
toolData.callBackProc[context, toolData];
}
ELSE
IF originalTSDisplayPaintProc #
NIL
THEN
quit ← originalTSDisplayPaintProc[self, context, whatChanged, clear];
};
TableToolExecCommand: Commander.CommandProc = {
[] ← ViewerOps.CreateViewer[flavor: $TableTool, info: [name: "TableTool", scrollable: FALSE]]
};
originalTSDisplayPaintProc: ViewerClasses.PaintProc ← NIL;
tableToolTIPTable: TIPUser.TIPTable ← TIPUser.InstantiateNewTIPTable["TableTool.TIP"];
tableToolViewerClass: ViewerClasses.ViewerClass ~
NEW[ViewerClasses.ViewerClassRec ← ViewerOps.FetchViewerClass[$Container]^];
containerInitProc: ViewerClasses.InitProc ← tableToolViewerClass.init;
containerDestroyProc: ViewerClasses.DestroyProc ← tableToolViewerClass.destroy;
containerPaintProc: ViewerClasses.PaintProc ← tableToolViewerClass.paint;
tableToolViewerClass.init ← TableToolInitProc;
tableToolViewerClass.destroy ← TableToolDestroyProc;
tableToolViewerClass.paint ← TableToolPaintProc;
tableToolViewerClass.bltH ← none;
tableToolViewerClass.bltV ← none;
tableToolViewerClass.tipTable ← tableToolTIPTable;
ViewerOps.RegisterViewerClass[$TableTool, tableToolViewerClass];
Commander.Register[key: "TableTool", proc: TableToolExecCommand, doc: "Create a table formatting tool"];