IndexToolViewerInit: ViewerClasses.InitProc ~ {
indexToolHandle: IndexToolHandle ← NEW[IndexToolHandleRec];
firstColumn: INTEGER ~ 0;
secondColumn: INTEGER ~ ViewerSpecs.openRightWidth/2;
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: FALSE,
guarded: FALSE];
Menus.InsertMenuEntry[menu, menuEntry, line];
};
CreatePhraseButtons:
PROCEDURE [label:
ROPE, x, y:
INTEGER]
RETURNS [phraseContainer: ViewerClasses.Viewer] ~ {
Leave space for the header button above the phrase container
thisY ← y;
NextRow[];
phraseContainer ← Containers.Create[
info: [
scrollable: TRUE,
border: FALSE,
parent: self,
wx: x,
wy: thisY,
ww: columnWidth,
wh: defaultPhraseRows*rowH],
paint: FALSE];
Create the phrase viewers in reverse order since they are searched in list order by CollectPhrases
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];
};
initialize the container that this viewer really is
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:", firstColumn, thisY];
indexToolHandle.seeCountLabel ← FeedbackLabel["# See references:", secondColumn, thisY];
NextRow[];
indexToolHandle.startPositionLabel ← FeedbackLabel["Start position:", firstColumn, thisY];
indexToolHandle.endPositionLabel ← FeedbackLabel["End position:", secondColumn, 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];
};
InsertEntryButtonProc: Menus.ClickProc = {
indexToolHandle: IndexToolHandle ← NARROW[clientData, IndexToolHandle];
selectedViewer: ViewerClasses.Viewer ← ViewerTools.GetSelectedViewer[];
check that the selection is in the expected document indexToolHandle.documentViewer
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 {
this index tool has no specific document yet
indexToolHandle.documentViewer ← selectedViewer;
ScanIndexProperties[selectedViewer, indexToolHandle];
change the name of this viewer by appending [" for ", document.name] to the caption
}
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~Node[start.node], index~start.where, name~$IndexEntries]];
selectionRoot: TiogaOps.Ref ← TiogaOps.SelectionRoot[primary];
ix: IndexEntry ← IndexEntryFromTool[indexToolHandle];
IndexTree.InsertNewIndexEntry[ix, Span[start, end], indexToolHandle.index !
IndexTree.DuplicateKey => GOTO Duplicate];
TiogaOps.Lock[selectionRoot];
TextEdit.PutCharProp[node~Node[start.node], index~start.where,
name~$IndexEntries, value~IndexProps.AddEntryToList[ix, ixList],
nChars~end.where-start.where, root~Node[selectionRoot]];
TiogaOps.Unlock[selectionRoot];
ViewerOps.SetNewVersion[indexToolHandle.documentViewer];
set feedback selection and normalize indexViewer
NormalizeIndexViewer[indexToolHandle, ix];
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]];
};
};
EXITS
Duplicate => Sorry["Index entry duplicates an entry already in table; NOT inserted."];
};