DIRECTORY Buttons, FS, Commander, Containers, EditSpan, EditSpanSupport, Graphics, InputFocus, Labels, Menus, NodeProps, NodeStyle, Process, PutGet, Rope, Rules, TableBase, TableOps, TableSelection, TEditSelection, TextNode, TiogaOps, TiogaOpsDefs, TIPUser, TSJaMPageBuilder, TSObject, TSOutput, TSOutputDisplay, TSTranslate, TSTypes, ViewerClasses, ViewerOps, ViewerTools; TableToolImpl: CEDAR PROGRAM IMPORTS Buttons, FS, Commander, Containers, EditSpan, EditSpanSupport, InputFocus, Graphics, Labels, Menus, NodeProps, Process, PutGet, Rope, Rules, TableBase, TableOps, TableSelection, TEditSelection, TextNode, TiogaOps, TIPUser, TSJaMPageBuilder, TSTranslate, TSTypes, ViewerOps, ViewerTools = 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: Graphics.Context, toolData: ToolData]; TableToolInitProc: ViewerClasses.InitProc = { toolData: ToolData _ NEW[ToolDataRec]; 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 = { 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; [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 { 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 { 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 { 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]; }; DuplicateSelButton: Buttons.ButtonProc ~ { toolData: ToolData _ NARROW[clientData]; }; TransposeButton: Buttons.ButtonProc ~ { toolData: ToolData _ NARROW[clientData]; }; MakeHeaderButton: Buttons.ButtonProc ~ { toolData: ToolData _ NARROW[clientData]; }; AppendButton: Buttons.ButtonProc ~ { toolData: ToolData _ NARROW[clientData]; }; 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; IF toolData.pleaseStop THEN RETURN; [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[]; }; 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 { 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 => { }; 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 => { }; row => { }; column => { }; 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 => { }; column => { }; ENDCASE => ERROR; TakeDownSelection[toolData]; 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; TakeDownSelection[toolData]; 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; TakeDownSelection[toolData]; SELECT currentSelection.kind FROM row => { }; column => { }; 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]; RefreshTableDisplay[toolData]; }; }; DoAppendRowOrCol: PROCEDURE [toolData: ToolData, selectedBox: RefTableBox] = { IF selectedBox # NIL AND NOT TableSelection.AnEmptySelection[toolData.selection] THEN { TakeDownSelection[toolData]; 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 = { 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); oldPaintMode: Graphics.PaintMode ~ Graphics.SetPaintMode[dc, invert]; 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; Graphics.DrawBox[dc, [llx, lly, urx, ury]]; [] _ Graphics.SetPaintMode[dc, oldPaintMode]; }; 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 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.bltContents _ none; tableToolViewerClass.tipTable _ tableToolTIPTable; ViewerOps.RegisterViewerClass[$TableTool, tableToolViewerClass]; Commander.Register[key: "TableTool", proc: TableToolExecCommand, doc: "Create a table formatting tool"]; END. žTableToolImpl.Mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Rick Beach, February 19, 1985 10:39:32 am PST nextX: INTEGER; PROC [self: Viewer, context: Graphics.Context, whatChanged: REF ANY, clear: BOOL]; get node from selection search from rootOfTable to end of document for the next table search from the root of the document until rootOfTable for the next table we have another table, so format and display it IF NOT TableSelection.AnEmptySelection[toolData.selection] THEN DoDeleteSelection[toolData, toolData.selection.startBox, toolData.selection.kind]; IF NOT TableSelection.AnEmptySelection[toolData.selection] THEN DoDuplicateRowOrCol[toolData, toolData.selection.startBox, toolData.selection.kind]; IF NOT TableSelection.AnEmptySelection[toolData.selection] THEN DoTransposeTable[toolData, toolData.selection.startBox]; IF NOT TableSelection.AnEmptySelection[toolData.selection] THEN DoMakeRowOrColHeader[toolData, toolData.selection.startBox, toolData.selection.kind]; IF NOT TableSelection.AnEmptySelection[toolData.selection] THEN DoAppendRowOrCol[toolData, toolData.selection.startBox, toolData.selection.kind]; copyRoot: TextNode.Ref; 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]; Update the selection 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]; }; toolData.selection.startBox _ toolData.selection.endBox _ selectedBox; 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; }; 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; }; selectedBox _ RowRootOf[selectedBox, TRUE]; IF NOT AreRowSiblings[selectedBox, currentSelection.startBox] THEN RETURN; selectedBox _ ColRootOf[selectedBox, TRUE]; IF NOT AreColSiblings[selectedBox, currentSelection.startBox] THEN RETURN; 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 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; SELECT toolData.selection.kind FROM row => TableOps.DeleteRowStructure[currentSelection.startBox]; column => TableOps.DeleteColStructure[currentSelection.startBox]; ENDCASE => GOTO Blink; selectedBox _ SELECT toolData.selectingRowOrColumn FROM row => RowRootOf[selectedBox, TRUE], column => ColRootOf[selectedBox, TRUE], ENDCASE => ERROR; IF AreRowSiblings[selectedBox, currentSelection.startBox] AND currentSelection.startBox # FirstRowChild[currentSelection.table.tableRoot] THEN TableOps.CopyRowStructure[currentSelection.startBox, selectedBox, currentSelection.insertion, TRUE] ELSE GOTO Blink; IF AreColSiblings[selectedBox, currentSelection.startBox] AND currentSelection.startBox # FirstColChild[currentSelection.table.tableRoot] THEN TableOps.CopyColStructure[currentSelection.startBox, selectedBox, currentSelection.insertion, TRUE] ELSE GOTO Blink; 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; SELECT toolData.selectingRowOrColumn FROM row => TableOps.AppendRow[toolData.selection.table]; column => TableOps.AppendCol[toolData.selection.table]; ENDCASE => SIGNAL CouldNotDoIt; PROCEDURE [dc: Graphics.Context, toolData: ToolData] สษ˜™Jšœ ฯmœ1™J˜J˜J˜&šŸ œž œžœžœ˜H˜.Jšœ ˜ J˜ Jšœ˜Jšœ˜J˜—J˜—šŸœž œžœžœ˜Pšœ"˜"šœ?˜?Jšœžœ žœ˜0—Jšœž˜ J˜—˜JšœYžœ žœ˜oJšœž˜ J˜—J˜—š Ÿœž œžœžœ!ž œžœ˜sšžœ˜Jšœ7žœ˜>Jšœ˜Jšœ ˜ Jšœžœ˜ Jšœžœ˜ Jšœ˜Jšœ˜——Jšœ2˜2JšœฯcB˜\J˜J˜hJ˜nJ˜NJ˜CJ˜J˜JšœZ˜ZJšœ‚˜‚Jšœ˜JšœZ˜ZJšœv˜vJšœ‰˜‰JšœW˜WJšœa˜aJšœ`˜`JšœX˜XJšœ^˜^J˜JšœN˜NJšœ#˜#J˜J˜Jšœโ˜โšœ4˜4šœ@˜@Jšœžœ žœ˜/—Jšœž˜ Jšœ˜—Jšœ2˜2J˜JšœP˜PJšœ#˜#J˜J˜šœ3˜3šœ,˜,Jšœžœ žœ˜/—Jšœž˜ Jšœ˜—Jšœ1˜1J˜JšœN˜NJšœ#˜#J˜J˜šœ0˜0˜˜Jšœ&˜&Jšœžœ˜Jšœ ˜ Jšœ žœ˜—Jšœžœ˜ ——šžœžœž˜(Jšœ@˜@—Jšœ5˜5Jšœ5˜5J˜—šŸœ˜3Jšœ.˜.š žœ žœžœžœžœžœ˜XJ˜*Jšœžœ˜Jšœ˜—Jšžœžœžœ˜>Jšœ˜—šŸœ˜/Jšžœ8žœžœ žœ™RJšžœžœžœ7˜Wšžœžœžœžœ˜%Jšœ.˜.š žœ žœžœžœžœ˜1Jšžœžœ˜9—Jšœ˜—J˜—šฯa œ˜ Jšœžœ ˜(Jšœžœ˜J˜—šกœ˜*Jšœžœ ˜(Jšœ žœ0˜=J˜8Jšœ žœžœ˜J˜Jšœžœ˜J˜šžœžœž˜Jšžœ žœ˜2—šž˜Jšœ!žœ)žœ˜WJ˜—šžœ žœž˜J˜k—šžœžœžœž˜JšœN˜N—šžœ˜J˜$Jšœ˜Jšœ˜—J˜—šกœ˜/Jšœžœ ˜(J˜J˜Jšœžœ˜J™J˜,šžœžœž˜JšœH˜H—šžœžœ˜Jšœžœ ˜*š žœžœžœžœž˜,J˜Jšž˜—šžœžœžœ˜JšœV˜V—šžœ˜Jšœ$˜$J˜Jšœ5˜5Jšœ˜—Jšœ˜—J˜—šŸ œžœžœžœ˜;J•StartOfExpansion[]š žœžœžœžœžœ˜!šžœ˜Jšœžœžœ)˜DJšžœ˜$Jšœ˜—J˜—šกœ˜+Jšœžœ ˜(Jšœžœ˜šžœžœžœ˜#JšœY˜Y—šžœ˜Jšœ ฯe œ&™=J˜?š žœžœžœžœž˜,J˜!Jšž˜—šžœžœžœ˜Jšœ+ข œ™IJ˜+š žœžœžœžœžœž˜LJ˜!Jšž˜—Jšœ˜—šžœžœžœžœ˜2JšœF˜F—šžœ˜J™/Jšœ$˜$J˜Jšœ˜—Jšœ˜—J˜—šŸœ˜*Jšœžœ ˜(šžœžœ˜J˜Gšœ žœ˜Jš žœžœžœžœžœž˜BJšžœžœ6˜A—šžœžœ˜ šžœžœžœ˜ Jšœ;˜;Jšžœ˜Jšœ˜—šžœ˜šžœžœžœž˜8Jšœ!˜!J˜'Jšž˜—Jšœ˜—J˜—šžœžœ˜J˜2šžœž˜JšœQ˜Q—šžœ˜Jšœ9˜9J˜—Jšœ˜—Jšœ˜—šžœ˜Jšœ1˜1Jšœ˜—Jšœ.˜.J˜—šŸ œ˜$Jšœžœ ˜(šžœžœžœ˜"J˜&J˜>J˜=J˜—J˜—šŸ œ˜#Jšœžœ ˜(šžœžœ˜"J˜%J˜>J˜=J˜—J˜—šŸ œ˜!Jšœžœ ˜(J˜$J˜;J˜;J˜—šŸ œ˜!Jšœžœ ˜(J˜'J˜;J˜;J˜—šŸœ˜'Jšœžœ ˜(šžœžœ4žœ™@JšœR™R—J˜—šŸœ˜*Jšœžœ ˜(šžœžœ4žœ™@JšœT™T—J˜—šŸœ˜'Jšœžœ ˜(šžœžœ4žœ™@Jšœ8™8—J˜—šŸœ˜(Jšœžœ ˜(šžœžœ4žœ™@JšœU™U—J˜—šŸ œ˜$Jšœžœ ˜(šžœžœ4žœ™@JšœQ™Q—J˜—šŸœž œžœ˜XJš žœžœžœžœžœ*˜HJ˜—šŸœž œžœžœ˜XJšœžœžœ%˜/š žœžœžœžœž˜'Jšœžœ˜—J˜—šŸœž œžœ˜Xš žœ žœžœžœžœ˜8Jšœ žœ@˜O—J˜—šŸœžœ4˜MJšžœžœžœ˜,J™Jšžœžœžœ˜#™[šœ ™4J™R——Jšœ)™)JšœF™FJšœI˜IJ˜#J˜—šŸ œž œ˜0Jšžœžœžœ˜#J˜Jšžœžœ5žœ˜\Jšœ ˜ JšœZ˜ZJšœ˜J˜—šŸœž œ˜9Jšœ žœžœ˜Jš Ÿ œžœžœžœžœ˜DJšœ8˜8˜*Jšœ˜Jšœ˜J˜J˜Jšœž˜J˜—J˜Jšœ*žœ ˜5J˜—šŸœž œžœ˜?Jšœ3˜3Jšœ>˜>JšœE˜EJ˜%J˜—šŸœž œ˜2J˜1šžœžœžœ˜J˜%J˜J˜#Jšœ,˜,Jšœ˜—Jšœ˜—šŸœž œ˜2J˜1šžœžœž˜Jšœ˜J˜+Jšœ˜—Jšœ˜—KšŸ œžœ˜5šŸœ˜/Jšœ5˜5šœ˜Jšœ˜Jšœ˜Jšœ1˜1šžœžœžœžœžœžœžœž˜@šžœ žœž˜šœžœžœž˜šœ˜Jšœ&˜&Jšœ˜—šœ˜Jšœ%˜%Jšœ˜—šœ ˜ Jšœ$˜$Jšœ˜—šœ ˜ Jšœ'˜'Jšœ˜—šœ ˜ Jšœ#˜#Jšœ˜—šœ ˜ Jšœ-˜-Jšœ˜—šœ ˜ JšœAžœ˜MJšœ˜—šœ˜Jšœ&˜&Jšœ˜—šœ˜Jšœ&˜&Jšœ˜—šœ˜Jšœ&˜&Jšœ˜—šœ˜Jšœ&˜&Jšœ˜—šœ˜Jšœ+˜+Jšœ˜—šœ˜Jšœ)˜)Jšœ˜—šœ˜Jšœ(˜(Jšœ˜—šœ˜Jšœ,˜,Jšœ˜—šœ˜Jšœ(˜(Jšœ˜—Jšžœžœ˜—šœ˜Jšœ ˜ Jšœ1˜1Jšœ˜—Jšžœžœ˜—Jšžœ˜—šž˜Jšœ5˜5—Jšœ˜—J˜Kšœžœžœ˜—šŸ œž œ3˜Išžœžœžœ˜Jšœ˜Jšœžœžœ7˜YJšœ˜Jšœ˜Jšœ˜—J˜—šŸœž œZ˜ušžœžœžœ˜Jšžœ žœžœžœ˜;šžœ#žœžœCžœ˜tJ™Jšœ˜Jšœ1žœ žœžœ ˜VJšœ˜Jšœ˜—Jšœ˜—J˜—šŸœž œ3˜Lšžœžœžœ5žœ˜Sšžœž˜#šœ˜šžœ1žœ˜9Jšœ˜Jšœžœžœ7˜YJšœ˜Jšœ˜—Jšœ˜—šœ˜šœžœž™1Jšœžœ™$Jšœ!žœ™'Jšžœžœ™—šžœ+žœ™3Jšœ™JšœG™GJšœ™Jšœ™—Jšœ˜—Jšžœžœ˜—Jšœ˜—J˜—šŸœž œ3˜Mš žœžœžœžœ5žœ˜WJšœ˜šžœž˜#Jšœ=˜=Jšœ=˜=JšœC˜CJšœ žœ˜Jšžœžœ˜—Jšœ˜Jšœ˜—Jšœ˜—šŸœž œ3˜Lš žœžœžœžœ5žœ˜WJšœD˜DJšœ˜šžœž˜!šœ˜JšœF™FJšœ˜—šœ˜Jšœ%žœ™+šžœ5ž™>Jšœ*™*Jšœ4™4Jšœ™—šžœ™Jšœ8™8Jšœ(™(Jšœ™—Jšœ˜—šœ ˜ Jšœ%žœ™+šžœ5ž™>Jšœ*™*Jšœ4™4Jšœ™—šžœ™Jšœ8™8Jšœ(™(Jšœ™—Jšœ˜—Jšžœžœ˜—Jšœ˜J˜—J˜—šŸœž œ3˜Lš žœžœžœžœ5žœ˜WJšœD˜Dšžœž˜!Jšœžœ˜ šœ˜Jšœ%žœ™+Jšžœžœ8žœžœ™JJšœ˜—šœ ˜ Jšœ%žœ™+Jšžœžœ8žœžœ™JJšœ˜—Jšžœžœ˜—Jšœ˜šžœ5ž™>Jšœ*™*Jšœ4™4Jšœ™—šž™Jšœ8™8Jšœ(™(Jšœ™—J™GJšœ˜Jšœ˜—Jšœ˜—šŸœž œ3˜Oš žœžœžœžœ5žœ˜WJšœD˜DJšžœ%žœžœ˜7šœžœž™7Jšœžœ™$Jšœ!žœ™'Jšžœžœ™—šžœžœ)ž™OJšžœ™ —Jšœ˜šžœž™#Jšœ>™>JšœA™AJšžœžœ™—Jšœ˜J˜—šž˜Jšœ5˜5—J˜—šŸœž œ3˜Qš žœžœžœžœ5žœ˜WJšœD˜DJšžœžœžœ˜/šœžœž™7Jšœžœ™$Jšœ!žœ™'Jšžœ™—Jšœ˜šžœž˜!šœ˜šžœ8žœMž™ŽJšœ^žœ™c—Jšžœžœ™Jšœ˜—šœ ˜ šžœ8žœLž™ŽJšœ^žœ™c—Jšžœžœ™Jšœ˜—Jšžœžœ˜—Jšœ˜J˜—šž˜Jšœ5˜5—J˜—šŸœž œ3˜Nš žœžœžœžœ5žœ˜WJšœ˜Jšœ2˜2Jšœ˜J˜—J˜—šŸœž œ3˜Rš žœžœžœžœ5žœ9žœ˜“JšœD˜DJšœ˜šžœž™)šœ™Jšœc™c—šœ ™ Jšœc™c—Jšžœžœ™—Jšœ˜J˜—J˜—šŸœž œ3˜Nš žœžœžœžœ5žœ˜WJšœ˜šžœž™)Jšœ4™4Jšœ7™7Jšžœžœ™—Jšœ˜J˜—J˜—šŸœž œ˜7J˜'J˜Jšžœžœ5žœ˜\J˜4J˜,J˜)Jšžœžœ˜3˜J˜J˜%J˜GJ˜J—Jšžœžœ˜5J˜*Jšœžœ˜J˜J˜—šŸœž œ˜0Jšœžœ˜Jšœžœ˜Jšœžœ˜J˜—šŸœž œ6žœžœ˜všžœžœžœ˜"Jšœ8˜8J˜+Jšœ-žœ˜HJšœฎ˜ฎJšœ˜—J˜—šŸ œž œžœ žœ˜RJšžœYžœU˜ทJ˜—šŸœž œ˜5šžœžœ5ž˜?J˜—Jšœžœ˜J˜—šŸœž œ˜2šžœžœ5ž˜?J˜—J˜—šŸœž œ˜2J˜9šŸœ˜)J˜J˜"J˜—š žœžœžœ:žœžœž˜^šžœž˜šœ˜Jšœ7˜7Jšœ˜—šœ˜J˜qJšœ˜—šœ ˜ J˜qJšœ˜—Jšžœžœ˜—Jšž˜—J˜—šŸœ˜Jšž œ+™4Jšœ8˜8J˜9Jšœ"˜"Jšœ-žœ˜HJšœ žœ˜Jšœ žœI˜VJ˜EJ˜&Jšœžœ7˜@Jšœžœ9˜BJšœžœ8˜AJšœžœ6˜?Jšœ+˜+J˜-J˜—šŸœž œ+žœ˜?Jšœ˜Jšœhžœ˜oJ˜—šŸœ˜8š žœžœžœžœžœ˜=Jšœžœ˜3Jšœ)˜)Jšœ˜—šžœžœžœž˜-Jšœ>˜>—J˜—šŸœ˜/Jšœ]˜]J˜—Kšœ6žœ˜:KšœV˜Všœ1˜1JšžœI˜L—KšœF˜FJšœO˜OJšœI˜IKšœ.˜.Jšœ4˜4Jšœ0˜0Jšœ(˜(Jšœ2˜2K˜@J˜hšžœ˜J˜——…—a^Žล