DIRECTORY Atom USING [GetPName, MakeAtom], Basics, Buttons, ChoiceButtons, Commander USING [CommandProc, Register], Containers, Icons, IndexProps, IndexTree, IndexToolViewer, IO, Labels, List, Menus, MessageWindow, NumberLabels USING [CreateNumber, NumberLabel, NumberLabelUpdate], RedBlackTree, Rope, Rules, RuntimeError USING [UNCAUGHT], TEditScrolling, TextEdit, TextNode, TiogaOps, TiogaOpsDefs, TIPUser, ViewerClasses USING [InitProc, ViewerClass, ViewerClassRec, Viewer], ViewerOps USING [AddProp, CreateViewer, FetchProp, FetchViewerClass, FindViewer, PaintViewer, RegisterViewerClass, SetMenu, SetNewVersion], ViewerSpecs, ViewerTools; IndexToolViewerImpl: CEDAR PROGRAM IMPORTS Atom, Buttons, ChoiceButtons, Commander, Containers, IndexProps, IndexTree, IO, Labels, List, Menus, MessageWindow, NumberLabels, RedBlackTree, Rope, Rules, RuntimeError, TEditScrolling, TextEdit, TextNode, TiogaOps, ViewerOps, ViewerSpecs, ViewerTools EXPORTS IndexToolViewer = BEGIN OPEN IndexToolViewer; ROPE: TYPE = Rope.ROPE; IndexEntry: TYPE ~ IndexProps.IndexEntry; Phrases: TYPE ~ IndexProps.Phrases; TextNodeRef: PROC [n: TiogaOps.Ref] RETURNS [TextNode.Ref] ~ TRUSTED { RETURN [LOOPHOLE[n]]; }; Span: PROC [s, e: TiogaOps.Location] RETURNS [TextNode.Span] ~ TRUSTED { RETURN [[LOOPHOLE[s], LOOPHOLE[e]]]; }; NewTool: PUBLIC PROCEDURE [documentName: ROPE _ NIL, kindOfIndex: ROPE _ NIL] RETURNS [indexToolHandle: IndexToolHandle] = { v: ViewerClasses.Viewer; caption: ROPE _ IF documentName.IsEmpty THEN "IndexTool" ELSE Rope.Concat["Index for ", documentName]; IF NOT kindOfIndex.IsEmpty THEN caption _ Rope.Cat[kindOfIndex, " ", caption]; v _ ViewerOps.CreateViewer[ flavor: $IndexTool, info: [name: caption, column: right, iconic: FALSE, scrollable: FALSE], paint: TRUE]; indexToolHandle _ NARROW[ViewerOps.FetchProp[v, $IndexToolHandle]]; indexToolHandle.index _ IndexTree.CreateIndex[TextNodeRef[TiogaOps.ViewerDoc[indexToolHandle.indexViewer]]]; indexToolHandle.kindOfIndex _ IF kindOfIndex.IsEmpty THEN $Index ELSE Atom.MakeAtom[Rope.Concat[kindOfIndex, "Index"]]; }; CreateIndexFromDocument: PUBLIC PROCEDURE [documentName: ROPE _ NIL, kindOfIndex: ROPE _ NIL] RETURNS [indexToolHandle: IndexToolHandle] = { IF documentName.IsEmpty THEN RETURN[NIL] ELSE { documentViewer: ViewerClasses.Viewer _ ViewerOps.FindViewer[documentName]; IF documentViewer = NIL THEN documentViewer _ ViewerOps.CreateViewer[flavor: $Text, info: [name: documentName, file: documentName] ]; indexToolHandle _ CreateIndexFromViewer[documentViewer, kindOfIndex]; }; }; CreateIndexFromViewer: PUBLIC PROCEDURE [documentViewer: ViewerClasses.Viewer, kindOfIndex: ROPE _ NIL] RETURNS [indexToolHandle: IndexToolHandle] = { indexToolHandle _ NewTool[documentViewer.name, kindOfIndex]; indexToolHandle.documentViewer _ documentViewer; ScanIndexProperties[documentViewer, indexToolHandle]; }; ScanIndexProperties: PUBLIC PROCEDURE [viewer: ViewerClasses.Viewer, indexToolHandle: IndexToolHandle] = { root: TiogaOps.Ref _ TiogaOps.ViewerDoc[viewer]; node: TiogaOps.Ref _ TiogaOps.FirstChild[root]; ScanIndexPropsOnNode: PROC [node: TextNode.Ref] ~ { SetIndexProps: TextEdit.ModifyPropsAction ~ { ixList: IndexProps.IndexEntryList _ NARROW[value]; SetIndexEntryProc: IndexProps.IndexEntryProc ~ { [] _ IndexTree.InsertNewIndexEntry[ix: ix, range: [[node, index], [node, index+nChars-1]], index: indexToolHandle.index]; }; IndexProps.MapIndexEntryList[ixList, SetIndexEntryProc]; }; [] _ TextEdit.ModifyCharProps[node, $IndexEntries, 0, INT.LAST, SetIndexProps, NIL, TextNodeRef[root]]; }; ForEachNodeWithCharProps: PROC [root: TextNode.Ref, nodeProc: PROC[node: TextNode.Ref]] ~ { node: TextNode.Ref _ root; WHILE (node _ TextNode.Next[node]) # NIL DO IF node.hascharprops THEN nodeProc[node]; ENDLOOP; }; disaster: BOOL _ FALSE; TiogaOps.Lock[root]; ForEachNodeWithCharProps[TextNodeRef[root], ScanIndexPropsOnNode ! RuntimeError.UNCAUGHT => {disaster _ TRUE; TiogaOps.Unlock[root]}]; IF NOT disaster THEN TiogaOps.Unlock[root]; TEditScrolling.ScrollToPosition[indexToolHandle.indexViewer, [indexToolHandle.index.root, 0]]; }; IndexToolViewerInit: ViewerClasses.InitProc ~ { indexToolHandle: IndexToolHandle _ NEW[IndexToolHandleRec]; firstColumn: INTEGER ~ 0; secondColumn: INTEGER ~ ViewerSpecs.openRightWidth/2; firstThird: INTEGER ~ 0; secondThird: INTEGER ~ ViewerSpecs.openRightWidth/3; thirdThird: INTEGER ~ secondThird+secondThird; columnWidth: INTEGER ~ ViewerSpecs.openRightWidth/2; numberOfPhrases: INTEGER ~ 10; phraseSize: INTEGER ~ secondColumn - 100; defaultPhraseRows: INTEGER ~ 3; h: INTEGER ~ ViewerSpecs.captionHeight; rowH: INTEGER ~ ViewerSpecs.messageWindowHeight; thisY: INTEGER _ 0; NextRow: PROCEDURE [rows: INTEGER _ 1] ~ { thisY _ thisY + rows*rowH; }; menu: Menus.Menu _ Menus.CreateMenu[2]; InsertMenuEntry: PROCEDURE [name: Rope.ROPE, proc: Menus.MenuProc, line: Menus.MenuLine] ~ { menuEntry: Menus.MenuEntry _ Menus.CreateEntry[ name: name, proc: proc, clientData: indexToolHandle, documentation: NIL, fork: TRUE, guarded: FALSE]; Menus.InsertMenuEntry[menu, menuEntry, line]; }; CreatePhraseButtons: PROCEDURE [label: ROPE, x, y: INTEGER] RETURNS [phraseContainer: ViewerClasses.Viewer] ~ { thisY _ y; NextRow[]; phraseContainer _ Containers.Create[ info: [ scrollable: TRUE, border: FALSE, parent: self, wx: x, wy: thisY, ww: columnWidth, wh: defaultPhraseRows*rowH], paint: FALSE]; FOR i: INTEGER DECREASING IN [1..numberOfPhrases] DO phraseData: PhraseButtonData _ NEW[PhraseButtonDataRec _ [indexToolHandle, i]]; button: Buttons.Button _ Buttons.Create[ info: [ name: " ", wx: 0, wy: (i-1)*rowH, ww: 0, wh: h, parent: phraseContainer, scrollable: FALSE, border: TRUE], clientData: phraseData, proc: PhraseButtonProc, paint: FALSE]; phraseData.viewer _ ViewerOps.CreateViewer[flavor: $Text, info: [ wx: button.cw + 6*i, wy: (i-1)*rowH, ww: phraseContainer.cw - (button.cw + 6*i) - 5, wh: rowH, parent: phraseContainer, scrollable: TRUE, border: TRUE], paint: FALSE]; ViewerOps.AddProp[phraseData.viewer, $IndexPhrase, $TRUE]; ENDLOOP; [] _ Buttons.Create[ info: [ name: label, wx: x, wy: y, wh: rowH, parent: self, scrollable: FALSE, border: FALSE], proc: ClearPhrasesButtonProc, clientData: phraseContainer, paint: FALSE]; thisY _ y; }; FeedbackLabel: PROCEDURE [label: ROPE, x, y: INTEGER, charsInNumber: NAT _ 4] RETURNS[v: NumberLabels.NumberLabel] ~ { v _ Labels.Create[ info: [name: label, parent: self, wx: x, wy: y, wh: rowH, border: FALSE], paint: FALSE ]; v _ NumberLabels.CreateNumber[ info: [ parent: self, wx: x + v.ww, wy: y, ww: columnWidth - v.ww - 40, wh: rowH, border: FALSE], chars: charsInNumber, initialValue: 0, paint: FALSE ]; }; Rule: PROCEDURE [h: CARDINAL] ~ { rule: Rules.Rule _ Rules.Create[info: [parent: self, wx: 0, wy: thisY, ww: 0, wh: h]]; Containers.ChildXBound[self, rule]; }; Choices: PROCEDURE [choices: Phrases, x, y: INTEGER] RETURNS [choiceRef: ChoiceButtons.EnumTypeRef] ~ { choiceRef _ ChoiceButtons.BuildEnumTypeSelection[viewer: self, x: x, y: y, buttonNames: choices, clientdata: indexToolHandle, style: menuSelection]; }; containerInitProc[self]; indexToolHandle.toolViewer _ self; InsertMenuEntry[name: "CopyIndexTo", proc: CopyIndexToButtonProc, line: 0]; InsertMenuEntry[name: "NewIndexTool", proc: NewIndexToolButtonProc, line: 0]; InsertMenuEntry[name: "DeleteEntry", proc: DeleteEntryButtonProc, line: 0]; InsertMenuEntry[name: "InsertEntry!", proc: InsertEntryButtonProc, line: 0]; InsertMenuEntry[name: "AddNewKind", proc: AddNewKindButtonProc, line: 1]; InsertMenuEntry[name: "PermutePhrases", proc: PermutePhrasesButtonProc, line: 1]; ViewerOps.SetMenu[self, menu]; indexToolHandle.kindOfEntryChoices _ Choices[LIST["Ordinary", "See", "SeeAlso"], firstColumn, thisY]; NextRow[]; indexToolHandle.indexPhrasesContainer _ CreatePhraseButtons["Index Entry Phrases:", firstColumn, thisY]; indexToolHandle.sortAsPhrasesContainer _ CreatePhraseButtons["Sort As:", secondColumn, thisY]; NextRow[4]; indexToolHandle.seePhrasesContainer _ CreatePhraseButtons["See phrases:", firstColumn, thisY]; NextRow[4]; Rule[1]; -- ============================================================== indexToolHandle.entriesLabel _ FeedbackLabel["Entries:", firstThird, thisY]; indexToolHandle.seeCountLabel _ FeedbackLabel["See refs:", secondThird, thisY]; indexToolHandle.nestingCountLabel _ FeedbackLabel["Max nesting:", thirdThird, thisY]; NextRow[]; indexToolHandle.startPositionLabel _ FeedbackLabel["Start position:", firstThird, thisY]; indexToolHandle.endPositionLabel _ FeedbackLabel["End position:", secondThird, thisY]; NextRow[]; Rule[1]; -- ============================================================== indexToolHandle.indexViewer _ ViewerOps.CreateViewer[ flavor: $TiogaButtons, info: [ wx: firstColumn, wy: thisY, parent: self, scrollable: TRUE], paint: FALSE ]; Containers.ChildXBound[self, indexToolHandle.indexViewer]; Containers.ChildYBound[self, indexToolHandle.indexViewer]; ViewerOps.AddProp[self, $IndexToolHandle, indexToolHandle]; }; CopyIndexToButtonProc: Menus.ClickProc = { indexToolHandle: IndexToolHandle _ NARROW[clientData, IndexToolHandle]; IF TiogaOps.GetSelection[primary].viewer = NIL THEN { Sorry["Make a primary selection for the destination of the index."]; RETURN; } ELSE { root: TiogaOps.Ref ~ TiogaOps.ViewerDoc[indexToolHandle.indexViewer]; TiogaOps.SelectNodes[viewer: indexToolHandle.indexViewer, start: TiogaOps.FirstChild[root], end: TiogaOps.LastLocWithin[root].node, which: secondary]; TiogaOps.ToPrimary[]; }; }; NewIndexToolButtonProc: Menus.ClickProc = { selectedViewer: ViewerClasses.Viewer _ ViewerTools.GetSelectedViewer[]; documentName: ROPE _ ViewerTools.GetSelectionContents[]; IF selectedViewer = NIL THEN { Sorry["Make a text selection of the document name (longer than 1 character)"]; documentName _ NIL; } ELSE IF documentName.IsEmpty THEN documentName _ selectedViewer.name; [] _ CreateIndexFromDocument[documentName]; }; DeleteEntryButtonProc: Menus.ClickProc = { Sorry["Not implemented"]; }; InsertEntryButtonProc: Menus.ClickProc = { indexToolHandle: IndexToolHandle _ NARROW[clientData, IndexToolHandle]; selectedViewer: ViewerClasses.Viewer _ ViewerTools.GetSelectedViewer[]; IF selectedViewer = NIL THEN { Sorry["Make a text selection in the document for this index entry"]; RETURN; } ELSE IF ViewerTools.GetContents[indexToolHandle.indexPhrasesContainer.child].IsEmpty THEN { Sorry["Supply an index phrase in the IndexTool before inserting it!"]; RETURN; } ELSE IF indexToolHandle.documentViewer = NIL THEN { indexToolHandle.documentViewer _ selectedViewer; ScanIndexProperties[selectedViewer, indexToolHandle]; indexToolHandle.toolViewer.name _ Rope.Cat["IndexTool for ", selectedViewer.name]; ViewerOps.PaintViewer[indexToolHandle.toolViewer, caption, FALSE]; } ELSE IF selectedViewer # indexToolHandle.documentViewer THEN { Sorry["Can't index that document from this index tool"]; RETURN; }; { start, end: TiogaOps.Location; [start~start, end~end] _ TiogaOps.GetSelection[primary]; IF start.node # end.node THEN { Sorry["Index entries must be within a single node"]; RETURN; } ELSE { ixList: IndexProps.IndexEntryList _ NARROW[TextEdit.GetCharProp[ node~TextNodeRef[start.node], index~start.where, name~$IndexEntries]]; selectionRoot: TiogaOps.Ref _ TiogaOps.SelectionRoot[primary]; ix: IndexEntry _ IndexEntryFromTool[indexToolHandle]; ixItem: IndexTree.IxItem _ IndexTree.InsertNewIndexEntry[ix, Span[start, end], indexToolHandle.index ! IndexTree.DuplicateKey => GOTO Duplicate]; TiogaOps.Lock[selectionRoot]; TextEdit.PutCharProp[node~TextNodeRef[start.node], index~start.where, name~$IndexEntries, value~IndexProps.AddEntryToList[ix, ixList], nChars~end.where-start.where, root~TextNodeRef[selectionRoot]]; TiogaOps.Unlock[selectionRoot]; ViewerOps.SetNewVersion[indexToolHandle.documentViewer]; NormalizeIndexViewer[indexToolHandle, ixItem]; UpdateFeedback[indexToolHandle.entriesLabel, indexToolHandle.entries _ indexToolHandle.entries + 1]; IF indexToolHandle.kindOfEntry = $See OR indexToolHandle.kindOfEntry = $SeeAlso THEN UpdateFeedback[indexToolHandle.seeCountLabel, indexToolHandle.seeCount _ indexToolHandle.seeCount + 1]; UpdateFeedback[indexToolHandle.nestingCountLabel, indexToolHandle.nestingCount _ MAX[NumberOfPhrases[ix.phrases], indexToolHandle.nestingCount]]; UpdateFeedback[indexToolHandle.startPositionLabel, TiogaOps.LocOffset[[selectionRoot, 0], start]]; UpdateFeedback[indexToolHandle.endPositionLabel, TiogaOps.LocOffset[[selectionRoot, 0], end]]; }; }; EXITS Duplicate => Sorry["Index entry duplicates an entry already in table; NOT inserted."]; }; AddNewKindButtonProc: Menus.ClickProc = { Sorry["Not implemented"]; }; PermutePhrasesButtonProc: Menus.ClickProc = { Sorry["Not implemented"]; }; atTheBeginning: ViewerTools.SelPos = NEW[ViewerTools.SelPosRec _ [0, 0, FALSE, before]]; PhraseButtonData: TYPE = REF PhraseButtonDataRec; PhraseButtonDataRec: TYPE = RECORD [ indexToolHandle: IndexToolHandle, phraseNumber: CARDINAL _ 0, viewer: ViewerClasses.Viewer _ NIL ]; PhraseButtonProc: Menus.ClickProc = { phraseData: PhraseButtonData _ NARROW[clientData, PhraseButtonData]; indexToolHandle: IndexToolHandle _ phraseData.indexToolHandle; SELECT mouseButton FROM red => { selectedViewer: ViewerClasses.Viewer _ ViewerTools.GetSelectedViewer[]; IF selectedViewer = NIL THEN Sorry["Please make a text selection of the phrase to index"] ELSE { start, end: TiogaOps.Location; pendingDelete: BOOL; level: TiogaOps.SelectionGrain; caretBefore: BOOL; root: TiogaOps.Ref _ TiogaOps.SelectionRoot[primary]; [selectedViewer, start, end, level, caretBefore, pendingDelete] _ TiogaOps.GetSelection[primary]; IF pendingDelete THEN TiogaOps.SetSelection[selectedViewer, start, end, level, caretBefore, FALSE, primary]; IF start.node # end.node THEN Sorry["Index phrases must be within a single node"] ELSE { ViewerTools.SetContents[phraseData.viewer, NIL]; TiogaOps.SelectDocument[viewer~phraseData.viewer, level~char, which~secondary]; TiogaOps.ToSecondary[]; -- copy the selected phrase TiogaOps.SetSelection[selectedViewer, start, end, level, caretBefore, FALSE, primary]; }; }; }; yellow => ViewerTools.SetSelection[phraseData.viewer, atTheBeginning]; blue => { ViewerTools.SetContents[phraseData.viewer, NIL]; ViewerTools.SetSelection[phraseData.viewer, atTheBeginning]; }; ENDCASE; }; ClearPhrasesButtonProc: Buttons.ButtonProc = { phraseContainer: ViewerClasses.Viewer _ NARROW[clientData, ViewerClasses.Viewer]; v: ViewerClasses.Viewer _ phraseContainer.child; WHILE v # NIL DO ViewerTools.SetContents[v, NIL]; v _ v.sibling; ENDLOOP; ViewerTools.SetSelection[phraseContainer.child, atTheBeginning]; }; Sorry: PROCEDURE [rope: ROPE] = { MessageWindow.Append[message: rope, clearFirst: TRUE]; MessageWindow.Blink[]; }; UpdatePhrases: PROC [phraseContainer: ViewerClasses.Viewer, phrases: Phrases] ~ { v: ViewerClasses.Viewer _ phraseContainer.child; WHILE v # NIL DO IF ViewerOps.FetchProp[v, $IndexPhrase] # NIL THEN { IF phrases # NIL AND phrases.rest # NIL THEN { contents: ViewerTools.TiogaContents _ NEW[ViewerTools.TiogaContentsRec _ [NARROW[phrases.first, ROPE], NARROW[phrases.rest.first, ROPE]]]; ViewerTools.SetTiogaContents[v, contents]; phrases _ phrases.rest.rest; } ELSE ViewerTools.SetContents[v, NIL]; }; v _ v.sibling; ENDLOOP; }; CollectPhrases: PROCEDURE [phraseContainer: ViewerClasses.Viewer] RETURNS [phrases: Phrases _ NIL] = { v: ViewerClasses.Viewer _ phraseContainer.child; phrase: ViewerTools.TiogaContents; WHILE v # NIL DO IF ViewerOps.FetchProp[v, $IndexPhrase] # NIL THEN { phrase _ ViewerTools.GetTiogaContents[v]; IF phrase = NIL OR phrase.contents.IsEmpty THEN EXIT; TRUSTED {phrases _ LOOPHOLE[List.Nconc1[LOOPHOLE[phrases], phrase.contents]]}; TRUSTED {phrases _ LOOPHOLE[List.Nconc1[LOOPHOLE[phrases], phrase.formatting]]}; }; v _ v.sibling; ENDLOOP; }; NumberOfPhrases: PROC [phrases: Phrases] RETURNS [NAT] ~ TRUSTED { RETURN [List.Length[LOOPHOLE[phrases]]/2]; }; UpdateFeedback: PROC [numberLabel: NumberLabels.NumberLabel, value: INT] ~ { IF numberLabel.destroyed THEN RETURN; NumberLabels.NumberLabelUpdate[numberLabel, value]; }; IndexEntryToTool: PROC [ix: IndexEntry, indexToolHandle: IndexToolHandle] ~ { IF ix.kindOfIndex # indexToolHandle.kindOfIndex THEN ERROR WrongIndexTool; UpdatePhrases[indexToolHandle.indexPhrasesContainer, ix.phrases]; UpdatePhrases[indexToolHandle.sortAsPhrasesContainer, ix.sortAsPhrases]; UpdatePhrases[indexToolHandle.seePhrasesContainer, ix.seePhrases]; UpdateKindOfEntry[indexToolHandle, ix]; }; WrongIndexTool: ERROR = CODE; -- an internal logic error IndexEntryFromTool: PROC [indexToolHandle: IndexToolHandle] RETURNS [ix: IndexEntry _ NEW[IndexProps.IndexEntryRec]] ~ { ix.kindOfIndex _ indexToolHandle.kindOfIndex; ix.phrases _ CollectPhrases[indexToolHandle.indexPhrasesContainer]; ix.seePhrases _ CollectPhrases[indexToolHandle.seePhrasesContainer]; IF ix.seePhrases # NIL AND ix.kindOfEntry # $See AND ix.kindOfEntry # $SeeAlso THEN { ix.kindOfEntry _ $See; UpdateKindOfEntry[indexToolHandle, ix]; }; ix.sortAsPhrases _ CollectPhrases[indexToolHandle.sortAsPhrasesContainer]; }; UpdateKindOfEntry: PROC [indexToolHandle: IndexToolHandle, ix: IndexEntry] ~ { ChoiceButtons.UpdateChoiceButtons[indexToolHandle.toolViewer, indexToolHandle.kindOfEntryChoices, Atom.GetPName[ix.kindOfEntry] ! ChoiceButtons.ChoiceDoesntExist => GOTO AddKindToChoices]; EXITS AddKindToChoices => { NULL }; }; NormalizeIndexViewer: PROCEDURE [indexToolHandle: IndexToolHandle, ixItem: IndexTree.IxItem] = { nearestEntry: IndexEntry; item: IndexTree.IxItem; leftItem, equalItem, rightItem: RedBlackTree.UserData; [leftItem, equalItem, rightItem] _ RedBlackTree.Lookup3[indexToolHandle.index.table, ixItem]; item _ NARROW[IF equalItem # NIL THEN equalItem ELSE IF leftItem # NIL THEN leftItem ELSE rightItem, IndexTree.IxItem]; nearestEntry _ item.ix; TiogaOps.SelectNodes[viewer: indexToolHandle.indexViewer, start: item.button.startLoc.node, end: item.button.endLoc.node, level: word, which: feedback]; TEditScrolling.AutoScroll[indexToolHandle.indexViewer, TRUE, FALSE, feedback]; ViewerOps.PaintViewer[indexToolHandle.indexViewer, client]; }; IndexToolCommand: Commander.CommandProc = { documentName: ROPE _ NIL; documentName _ IO.GetTokenRope[IO.RIS[cmd.commandLine], IO.IDProc ! IO.EndOfStream => CONTINUE].token; IF documentName.IsEmpty THEN [] _ NewTool[] ELSE [] _ CreateIndexFromDocument[documentName]; }; indexToolViewerClass: ViewerClasses.ViewerClass ~ NEW[ViewerClasses.ViewerClassRec _ ViewerOps.FetchViewerClass[$Container]^]; containerInitProc: ViewerClasses.InitProc ~ indexToolViewerClass.init; indexToolViewerClass.init _ IndexToolViewerInit; indexToolViewerClass.icon _ tool; ViewerOps.RegisterViewerClass[$IndexTool, indexToolViewerClass]; Commander.Register[ key: "IndexTool", proc: IndexToolCommand, doc: "Create an index tool." ]; END. ŒIndexToolViewerImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Created by Rick Beach, July 12, 1983 4:34 pm Rick Beach, April 29, 1985 5:00:44 pm PDT Creating new IndexTools PROC [value: REF, index: INT, nChars: INT] RETURNS [quit: BOOL _ FALSE, newValue: REF]; PROC [ix: IndexEntry] IndexTool Viewer Leave space for the header button above the phrase container Create the phrase viewers in reverse order since they are searched in list order by CollectPhrases initialize the container that this viewer really is indexToolHandle: IndexToolHandle _ NARROW[clientData, IndexToolHandle]; check that the selection is in the expected document indexToolHandle.documentViewer this index tool has no specific document yet change the name of this viewer by appending [" for ", document.name] to the caption set feedback selection and normalize indexViewer indexToolHandle: IndexToolHandle _ NARROW[clientData, IndexToolHandle]; Create an additional kind of index entry choice button _ ChoiceButtons.GetSelectedButton[indexToolHandle.kindOfEntryChoices]; indexToolHandle: IndexToolHandle _ NARROW[clientData, IndexToolHandle]; check that the phrase is within a single node Service Procs for the IndexTool ix.kindOfEntry _ ChoiceButtons.GetSelectedButton[indexToolHandle.kindOfEntryChoices]; someday figure out how to get ChoiceButtons to do this... IndexTool Command we should accept a document kind and create an atom with that name Initialization indexToolViewerIcon: Icons.IconFlavor; indexToolViewerClass.icon _ private; IconRegistry.RegisterIcon["IndexTool", "IndexTool.icons", 0]; indexToolViewerIcon _ IconRegistry.GetIcon["IndexTool", tool]; Ê,˜codešœ™Kšœ Ïmœ1™K˜8Kšžœ˜K˜—šœ˜K˜K˜8šžœžœ˜K˜4Kšžœ˜Jšœ˜—šžœ˜Kšœ$žœ]˜‡Kšœ>˜>Kšœ5˜5šœf˜fKšœžœ ˜*—K˜KšœÆ˜ÆK˜K˜8K™0Kšœ.˜.Kšœd˜dšžœ$žœ(ž˜TKšœg˜g—KšœQžœ=˜‘Kšœb˜bKšœ^˜^Jšœ˜—Kšœ˜—šž˜K˜V—K˜K˜—š œ˜)Kšœ#žœ™GK™6KšœG™GK˜K˜K˜—š œ˜-Kšœ#žœ™GK˜K˜K˜—Kšœ%žœ žœ ˜XKšœžœžœ˜1šœžœžœ˜$K˜!Kšœžœž˜Kšœž˜"Kšœ˜—š œ˜%Kšœžœ˜DKšœ>˜>šžœ ž˜šœ˜KšœG˜Gšžœžœž˜Kšœ<˜<—šžœ˜K˜Kšœžœ˜Kšœ˜Kšœ žœ˜Kšœ5˜5Kšœa˜ašžœž˜KšœFžœ ˜V—K™-šžœž˜K˜3—šžœ˜Kšœ+žœ˜0KšœO˜OKšœÏc˜3KšœFžœ ˜VKšœ˜—Kšœ˜—Kšœ˜—šœ ˜ Kšœ<˜<—šœ ˜ Kšœ+žœ˜0Kšœ<˜˜QKšœ0˜0šžœžœž˜šžœ(žœžœ˜4š žœ žœžœžœžœ˜.Kš œ&žœ!žœžœžœžœ˜ŠKšœ*˜*K˜Jšœ˜—Jšžœžœ˜%Kšœ˜—K˜Kšž˜—J˜J™—š œž œ)žœžœ˜fKšœ0˜0Kšœ"˜"šžœžœž˜šžœ(žœžœ˜4K˜)Kš žœ žœžœžœžœ˜5Kšžœ žœ žœ˜NKšžœ žœ žœ ˜PKšœ˜—K˜Kšž˜—K˜K˜—š  œžœžœžœžœ˜BKšžœžœ˜*K˜K™—š œžœ0žœ˜LKšžœžœžœ˜%Kšœ3˜3K˜K˜—š œžœ7˜MKšžœ.žœžœ˜JK˜AKšœH˜HKšœB˜BK˜'K˜Kšœžœžœ¡˜9K™—š œžœ$žœžœ˜xKšœ-˜-KšœU™UKšœC˜CKšœD˜Dšžœžœžœžœ˜NKšžœD˜H—KšœJ˜JK˜K™—š œžœ7˜Nšœ˜Kšœ#žœ˜:—šž˜šœ˜Jšž˜Jšœ9™9Jšœ˜——J˜J˜—š œž œA˜`Kšœ˜K˜Kšœ6˜6Kšœ]˜]Kšœžœžœ žœžœ žœžœ žœžœ žœ˜wKšœ˜šœ9˜9K˜!K˜K˜ K˜—Kšœ7žœžœ ˜NK˜;K˜K˜——™š œ˜+Kšœžœž˜š œžœžœžœžœ ˜CKšžœžœ˜"—KšœB™BKšžœžœ˜+Kšžœ,˜0K˜K˜——™˜1KšžœI˜L—K˜FKšœ&™&K˜Kšœ0˜0Kšœ!˜!Kšœ$™$K™=K™>K˜@K˜šœ˜Kšœ˜Kšœ˜Kšœ˜K˜——K˜Kšžœ˜—…—IÒfŠ