LoganBerryBrowserImpl.mesa
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reserved.
Doug Terry, July 17, 1992 2:32 pm PDT
Brian Oki, June 19, 1990 1:00 pm PDT
A tool for interactively browsing LoganBerry databases.
DIRECTORY
Atom USING [GetPName, MakeAtom],
Buttons USING [Button, ButtonProc, Create, SetDisplayStyle],
ChoiceButtons USING [ChoiceDoesntExist, EnumTypeRef, BuildEnumTypeSelection, GetSelectedButton, UpdateChoiceButtons],
Containers USING [ ChildXBound, ChildYBound, Container, Create ],
Icons USING [ IconFlavor, NewIconFromFile ],
IO USING [atom, STREAM, PutRope, PutFR, real, RIS, RopeFromROS, rope, ROS],
Labels USING [Create, Label, Set],
LoganBerry USING [AttributeType, AttributeValue, BuildIndices, Close, CompactLogs, DeleteEntry, Describe, Entry, Error, ErrorCode, IndexInfo, nullDB, Open, OpenDB, SchemaInfo, WriteEntry],
LoganQuery USING [AbortQuery, AttributePattern, AttributePatternRec, AttributePatterns, BooleanFilterEntries, Cursor, EndGenerate, NextEntry, ParseBooleanQuery, ParseTree, PatternsToEntry, QueryEntries, QueryPlan, ReadAttributePatterns, WriteAttributePatterns, SyntaxError],
LoganQueryClass USING [MergeEntries],
Menus USING [AppendMenuEntry, ChangeNumberOfLines, ClickProc, CreateEntry, CreateMenu, GetNumberOfLines, Menu, MenuLine],
MessageWindow USING [Append, Blink],
PatternMatch USING [EachPairAction, Pairs],
RefTab USING [Ref, EachPairAction, Fetch, Pairs, Create, Store],
Rope USING [Concat, Equal, IsEmpty, Length, SkipTo, Substr, ROPE],
Rules USING [ Create, Rule ],
TiogaButtons USING [CreateButton, CreateViewer, TiogaButtonProc],
TypeScript USING [ Create, ChangeLooks, PutChar, PutRope ],
ViewerBLT USING [ChangeNumberOfLines],
ViewerClasses USING [ Viewer, <<ViewerClassRec,>> ViewerFlavor, ViewerRec ],
ViewerEvents USING [ EventProc, RegisterEventProc ],
ViewerOps USING [AddProp, CreateViewer, MoveViewer, PaintViewer],
ViewerTools USING [GetContents, MakeNewTextViewer, SetContents, SetSelection],
LoganBerryBrowser;
LoganBerryBrowserImpl: CEDAR PROGRAM     
IMPORTS Atom, Buttons, ChoiceButtons, Containers, Icons, IO, Labels, LoganBerry, LoganQuery, LoganQueryClass, Menus, MessageWindow, PatternMatch, RefTab, Rope, Rules, TiogaButtons, TypeScript, ViewerBLT, ViewerEvents, ViewerOps, ViewerTools
EXPORTS LoganBerryBrowser
= BEGIN
Types
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
Viewer: TYPE = ViewerClasses.Viewer;
BrowserTool: TYPE = LoganBerryBrowser.Tool;
DBList: TYPE = LIST OF LoganBerryBrowser.DBInfo;
DisplayProc: TYPE = LoganBerryBrowser.DisplayProc;
FormField: TYPE = REF FormFieldRec;
FormFieldRec: TYPE = RECORD [
textViewer: Viewer,
patternButton: ChoiceButtons.EnumTypeRef,
feedbackArea: Labels.Label
];
HistoryData: TYPE = REF HistoryDataRec;
HistoryDataRec: TYPE = RECORD [
tool: BrowserTool,
cmd: ROPE,
form: LoganQuery.AttributePatterns,
other: ROPE
];
Viewer layout
browserIcon: Icons.IconFlavor ¬ tool;
itemHeight: CARDINAL = 14;
interItemHeight: CARDINAL = 3;
ruleHeight: CARDINAL = 1;
patternButtonWidth: CARDINAL = 100;
patternHSpace: CARDINAL = 5;
feedbackHSpace: CARDINAL = 350;
historyHeight: CARDINAL = 100;
defaultPattern: ROPE ¬ "DWIM";
Entry form
MakeEntryForm: PROC [tool: BrowserTool] RETURNS [] ~ {
AddPattern: PatternMatch.EachPairAction ~ {
patternChoices ¬ CONS[name, patternChoices];
};
patternChoices: LIST OF ROPE ¬ LIST["DWIM"];
prompt: Viewer;
[] ¬ PatternMatch.Pairs[AddPattern];
tool.entryform ¬ RefTab.Create[];
FOR k: LIST OF LoganBerry.AttributeType ¬ tool.fields, k.rest WHILE k # NIL DO
field: FormField ¬ NEW[FormFieldRec];
field.patternButton ¬ ChoiceButtons.BuildEnumTypeSelection[viewer: tool.details, x: patternHSpace, y: tool.height, buttonNames: patternChoices, default: defaultPattern, style: flipThru, maxWidth: patternButtonWidth];
prompt ¬ Buttons.Create[info: [name: Rope.Concat[Atom.GetPName[k.first], ":"], wx: field.patternButton.nextx, wy: tool.height, parent: tool.outer, scrollable: FALSE, border: FALSE], proc: SelectTextField, clientData: field];
field.textViewer ¬ ViewerTools.MakeNewTextViewer[info: [wx: prompt.wx + prompt.ww + patternHSpace, wy: tool.height, wh: itemHeight, ww: 9999, parent: tool.outer, scrollable: FALSE, border: FALSE]];
Containers.ChildXBound[container: tool.outer, child: field.textViewer];
field.feedbackArea ¬ Labels.Create[info: [parent: tool.details, wx: feedbackHSpace, wy: tool.height, ww: 9999, wh: 0, border: FALSE, scrollable: FALSE]];
tool.height ¬ tool.height + itemHeight + interItemHeight;
[] ¬ RefTab.Store[tool.entryform, k.first, field];
ENDLOOP;
IF tool.wantInputArea THEN {
prompt ¬ Buttons.Create[info: [name: "other attributes:", wx: patternHSpace, wy: tool.height, parent: tool.outer, scrollable: TRUE, border: FALSE], proc: SelectInputArea, clientData: tool];
tool.inputArea ¬ ViewerTools.MakeNewTextViewer[info: [wx: prompt.wx + prompt.ww + patternHSpace, wy: tool.height, wh: itemHeight, ww: 9999, parent: tool.outer, border: FALSE]];
Containers.ChildXBound[container: tool.outer, child: tool.inputArea];
tool.height ¬ tool.height + itemHeight + interItemHeight;
};
};
SelectTextField: Buttons.ButtonProc = {
[parent: ViewerClasses.Viewer, clientData: REF ANYNIL, mouseButton: ViewerClasses.MouseButton ← red, shift: BOOLFALSE, control: BOOLFALSE]
field: FormField = NARROW[clientData];
ViewerTools.SetSelection[field.textViewer, NIL];
};
SelectInputArea: Buttons.ButtonProc = {
[parent: ViewerClasses.Viewer, clientData: REF ANYNIL, mouseButton: ViewerClasses.MouseButton ← red, shift: BOOLFALSE, control: BOOLFALSE]
tool: BrowserTool = NARROW[clientData];
ViewerTools.SetSelection[tool.inputArea, NIL];
};
MakeDatabaseButton: PROC [tool: BrowserTool] RETURNS [] ~ {
button: Buttons.Button;
xpos: INT ¬ 0;
IF tool.databases.rest = NIL THEN RETURN; -- only a single database to choose from so don't need selection buttons
button ¬ Labels.Create[info: [name: "Databases: ", wx: xpos, wy: tool.height, parent: tool.details, scrollable: FALSE, border: FALSE]];
FOR d: DBList ¬ tool.databases, d.rest WHILE d#NIL DO
xpos ¬ xpos + button.ww;
button ¬ Buttons.Create[
info: [name: d.first.shortname, wx: xpos, wy: tool.height, parent: tool.details, border: TRUE],
proc: ToggleDatabaseButton,
fork: FALSE,
paint: FALSE,
clientData: d.first
];
Buttons.SetDisplayStyle[button, IF d.first.selected THEN $WhiteOnBlack ELSE $BlackOnWhite];
ENDLOOP;
tool.height ¬ tool.height + itemHeight + interItemHeight;
};
ToggleDatabaseButton: Buttons.ButtonProc ~ {
[parent: ViewerClasses.Viewer, clientData: REF ANYNIL, mouseButton: ViewerClasses.MouseButton ← red, shift: BOOLFALSE, control: BOOLFALSE]
db: LoganBerryBrowser.DBInfo = NARROW [clientData];
db.selected ¬ NOT db.selected;
Buttons.SetDisplayStyle[parent, IF db.selected THEN $WhiteOnBlack ELSE $BlackOnWhite];
};
MakeSortButton: PROC [tool: BrowserTool] RETURNS [] ~ {
choices: LIST OF ROPE ¬ NIL;
IF NOT tool.wantSortButton THEN RETURN;
FOR i: LIST OF LoganBerry.IndexInfo ¬ tool.databases.first.schema.indices, i.rest WHILE i#NIL DO
choices ¬ CONS[Atom.GetPName[i.first.key], choices];
ENDLOOP;
choices ¬ CONS["ANY", choices];
tool.height ¬ tool.height + interItemHeight;
tool.sortButton ¬ ChoiceButtons.BuildEnumTypeSelection[viewer: tool.details, x: patternHSpace, y: tool.height, title: "Order by:", buttonNames: choices, default: "ANY", style: menuSelection --vs. flipThru--];
tool.queryFeedback ¬ Labels.Create[info: [parent: tool.details, wx: MAX[tool.sortButton.nextx, feedbackHSpace], wy: tool.height, ww: 9999, wh: 0, border: FALSE, scrollable: FALSE]];
tool.height ¬ tool.height + itemHeight + interItemHeight;
};
ReadEntryForm: PUBLIC PROC [tool: BrowserTool] RETURNS [form: LoganQuery.AttributePatterns, other: Rope.ROPE, orderBy: LoganBerry.AttributeType] ~ {
NextField: RefTab.EachPairAction = {
[key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN]
text: ROPE;
label: ATOM = NARROW[key];
field: FormField = NARROW[val];
text ¬ ViewerTools.GetContents[field.textViewer];
IF NOT Rope.Equal[text, ""] THEN {
fv: LoganQuery.AttributePattern ¬ NEW[LoganQuery.AttributePatternRec];
fv.attr.type ¬ label;
fv.attr.value ¬ text;
fv.ptype ¬ ChoiceButtons.GetSelectedButton[field.patternButton];
IF form=NIL
THEN form ¬ end ¬ LIST[fv]
ELSE {end.rest ¬ LIST[fv]; end ¬ end.rest;};
};
Labels.Set[field.feedbackArea, NIL];
RETURN[quit: FALSE];
};
end, otherPatterns: LoganQuery.AttributePatterns;
form ¬ NIL;
[] ¬ RefTab.Pairs[tool.entryform, NextField];
other ¬ ViewerTools.GetContents[tool.inputArea];
AddToHistory[tool, form, other];
The following 2 lines are commented out since the other field may contain a boolean query:
otherPatterns ¬ LoganQuery.ReadAttributePatterns[IO.RIS[other]];
form ¬ AppendPatterns[form, otherPatterns];
orderBy ¬ Atom.MakeAtom[ChoiceButtons.GetSelectedButton[tool.sortButton]];
IF orderBy = $ANY THEN orderBy ¬ NIL;
Labels.Set[tool.queryFeedback, NIL];
};
RestoreEntryForm: PUBLIC PROC [tool: BrowserTool, form: LoganQuery.AttributePatterns, other: ROPE] RETURNS [] ~ {
RestoreField: RefTab.EachPairAction = {
[key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN]
label: ATOM = NARROW[key];
field: FormField = NARROW[val];
f: LoganQuery.AttributePatterns;
FOR f ¬ form, f.rest WHILE f # NIL DO
IF f.first.attr.type = label THEN EXIT;
ENDLOOP;
IF f # NIL THEN {
ChoiceButtons.UpdateChoiceButtons[tool.details, field.patternButton, f.first.ptype ! ChoiceButtons.ChoiceDoesntExist => CONTINUE];
ViewerTools.SetContents[field.textViewer, f.first.attr.value, FALSE];
}
ELSE {
ViewerTools.SetContents[field.textViewer, "", FALSE];
};
Labels.Set[field.feedbackArea, NIL, FALSE];
RETURN[quit: FALSE];
};
ChoiceButtons.UpdateChoiceButtons[tool.details, tool.sortButton, Atom.GetPName[form.first.attr.type] ! ChoiceButtons.ChoiceDoesntExist => CONTINUE];
Labels.Set[tool.queryFeedback, NIL, FALSE];
[] ¬ RefTab.Pairs[tool.entryform, RestoreField];
ViewerTools.SetContents[tool.inputArea, other, FALSE];
ViewerOps.PaintViewer[viewer: tool.outer, hint: all];
};
ReportFeedback: PUBLIC PROC [plan: LoganQuery.QueryPlan, tool: BrowserTool] RETURNS [] ~ {
Labels.Set[tool.queryFeedback, IO.PutFR["(%g - %3.2f)", IO.atom[plan.first.attr.type], IO.real[plan.first.cost]]];
FOR p: LoganQuery.QueryPlan ¬ plan, p.rest WHILE p # NIL DO
ff: FormField ¬ NARROW[RefTab.Fetch[tool.entryform, p.first.attr.type].val];
IF ff#NIL THEN Labels.Set[ff.feedbackArea, IO.PutFR["%g(%g)", IO.rope[p.first.errMsg], IO.rope[p.first.infoMsg]]];
ENDLOOP;
};
AppendPatterns: PROC [p1, p2: LoganQuery.AttributePatterns] RETURNS [LoganQuery.AttributePatterns] ~ {
temp: LoganQuery.AttributePatterns ¬ p1;
IF p1 = NIL THEN RETURN[p2];
UNTIL temp.rest = NIL DO temp ¬ temp.rest ENDLOOP;
temp.rest ¬ p2;
RETURN[p1];
};
History viewer
The History viewer contains lines representing commands that could have been typed to a commandTool to achieve the same result as the operations invoked via the browser tool.
Each of these lines is a TiogaButton that, when buttoned, causes the entry form to be filled in with the various values.
AddToHistory: PUBLIC PROC [tool: BrowserTool, form: LoganQuery.AttributePatterns, other: ROPE] RETURNS [] ~ {
data: HistoryData = NEW[HistoryDataRec ¬ [tool, NIL, form, other]];
line: STREAM ¬ IO.ROS[];
LoganQuery.WriteAttributePatterns[line, form];
IO.PutRope[line, " "];
IO.PutRope[line, other];
[] ¬ TiogaButtons.CreateButton[viewer: tool.history, rope: IO.RopeFromROS[line], proc: HistoryButtonProc, clientData: data];
};
HistoryButtonProc: TiogaButtons.TiogaButtonProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
Left mouse button => restore the entry form; Middle => restore form and re-execute (not currently implemented).
data: HistoryData ¬ NARROW[clientData];
RestoreEntryForm[data.tool, data.form, data.other];
};
Misc. viewer stuff
DividingLine: PROC [tool: BrowserTool] RETURNS [] ~ {
rule: Rules.Rule;
rule ¬ Rules.Create[info: [parent: tool.outer, wx: 0, wy: tool.height, ww: 9999, wh: ruleHeight]];
Containers.ChildXBound[tool.outer, rule]; -- constrain rule to be width of parent
tool.height ¬ tool.height + ruleHeight;
};
HideViewer: PROC [v: Viewer] RETURNS [] ~ {
ViewerOps.MoveViewer[viewer: v, x: 2000, y: v.wy, w: v.ww, h: v.wh];
};
UnHideViewer: PROC [v: Viewer] RETURNS [] ~ {
ViewerOps.MoveViewer[viewer: v, x: 0, y: v.wy, w: v.ww, h: v.wh];
};
ResetViewer: PROC [v: Viewer] RETURNS [] ~ {
v.class.init[v];
};
Create main tool
CreateTool: PUBLIC PROC [db: LoganBerry.OpenDB ¬ LoganBerry.nullDB, tool: BrowserTool] = {
innerInfo: ViewerClasses.ViewerRec;
Get database info
IF db#LoganBerry.nullDB THEN
tool.databases ¬ LIST[NEW[LoganBerryBrowser.DBInfoRec ¬ [db: db]]];
IF tool.databases = NIL THEN {
MessageWindow.Append[message: "No LoganBerry database specified to browse!", clearFirst: TRUE];
RETURN;
};
FOR d: DBList ¬ tool.databases, d.rest WHILE d#NIL DO
prev, loc: INT ¬ 1;
d.first.schema ¬ LoganBerry.Describe[db: d.first.db];
WHILE loc < Rope.Length[d.first.schema.dbName] DO
prev ¬ loc;
loc ¬ Rope.SkipTo[s: d.first.schema.dbName, pos: prev+1, skip: "/>]"];
ENDLOOP; 
d.first.shortname ¬ Rope.Substr[base: d.first.schema.dbName, start: prev+1];
ENDLOOP;
FOR d: DBList ← tool.databases, d.rest WHILE d#NIL DO
name: PFS.PATH;
comp: PFSNames.Component;
d.first.schema ← LoganBerry.Describe[db: d.first.db];
name ← PFSNames.ExpandName[PFS.PathFromRope[d.first.schema.dbName]];
d.first.schema.dbName ← PFS.RopeFromPath[name];
comp ← PFSNames.ShortName[name];
d.first.shortname ← comp.name.base;
ENDLOOP;
Initialize tool
SetDefaults[tool];
create command section
tool.outer ¬ Containers.Create[info: [
name: tool.name,
icon: tool.icon,
label: tool.databases.first.shortname,
iconic: FALSE,
column: left,
menu: tool.menu,
scrollable: FALSE]];
Menus.ChangeNumberOfLines[tool.menu, 1];
ViewerBLT.ChangeNumberOfLines[tool.outer, 1];
ViewerOps.AddProp[viewer: tool.outer, prop: $BrowserTool, val: tool];
[] ¬ ViewerEvents.RegisterEventProc[proc: DestroyProc, event: destroy, filter: tool.outer];
create input form
tool.details ¬ Containers.Create[info: [
parent: tool.outer,
ww: 9999,
wh: 9999,
scrollable: FALSE,
border: FALSE]];
Containers.ChildXBound[container: tool.outer, child: tool.details];
Containers.ChildYBound[container: tool.outer, child: tool.details];
tool.height ¬ interItemHeight;
MakeDatabaseButton[tool];
MakeEntryForm[tool];
MakeSortButton[tool];
DividingLine[tool];
create history viewer
tool.history ¬ TiogaButtons.CreateViewer[info: [
parent: tool.outer,
wy: tool.height,
ww: 9999,
wh: historyHeight,
border: TRUE]];
Containers.ChildXBound[tool.outer, tool.history]; -- constrain rule to be width of parent
HideViewer[tool.history];
create output browser
innerInfo ¬ [
name: "LoganBerry Browser output",
parent: tool.outer,
wx: 0,
wy: tool.height,
ww: 9999,
wh: 9999,
border: FALSE];
tool.inner ¬ SELECT tool.innerFlavor FROM
$Typescript => TypeScript.Create[info: innerInfo],
ENDCASE => ViewerOps.CreateViewer[flavor: tool.innerFlavor, info: innerInfo];
Containers.ChildXBound[tool.outer, tool.inner]; -- constrain rule to be width of parent
Containers.ChildYBound[tool.outer, tool.inner]; -- constrain rule to be height of parent
};
PrintEntry: PUBLIC PROC [entry: LoganBerry.Entry, tool: BrowserTool] = {
Write entry in browser's typescript viewer.
IF tool.innerFlavor#$TypeScript THEN {
MessageWindow.Append[message: "Wrong flavor of browser's output viewer", clearFirst: TRUE];
MessageWindow.Blink[];
RETURN;
};
FOR e: LoganBerry.Entry ¬ entry, e.rest UNTIL e = NIL DO
IF e.first.type#NIL THEN {
TypeScript.ChangeLooks[tool.inner, 'b]; -- print atribute type in bold
TypeScript.PutRope[tool.inner, Atom.GetPName[e.first.type]];
TypeScript.ChangeLooks[tool.inner, ' ]; -- restore normal looks
TypeScript.PutRope[tool.inner, ": "];
};
TypeScript.PutRope[tool.inner, e.first.value];
TypeScript.PutChar[tool.inner, '\n];
ENDLOOP;
TypeScript.PutChar[tool.inner, '\n];
};
PrintEntryAsButton: PUBLIC PROC [entry: LoganBerry.Entry, tool: BrowserTool, proc: TiogaButtons.TiogaButtonProc, clientData: REF ANY ¬ NIL] = {
Builds a tioga button in the browser's inner viewer.
EntryToRope: PROC [entry: LoganBerry.Entry] RETURNS [rope: ROPE] ~ {
rope ¬ NIL;
FOR l: LoganBerry.Entry ¬ entry, l.rest WHILE l # NIL DO
IF l.first.type#NIL THEN
rope ¬ IO.PutFR["%g%g: ", IO.rope[rope], IO.atom[l.first.type]];
rope ¬ IO.PutFR["%g%g\n", IO.rope[rope], IO.rope[l.first.value]];
ENDLOOP;
};
IF tool.innerFlavor#$TiogaButtons THEN {
MessageWindow.Append[message: "Wrong flavor of browser's output viewer", clearFirst: TRUE];
MessageWindow.Blink[];
RETURN;
};
[] ¬ TiogaButtons.CreateButton[viewer: tool.inner, rope: EntryToRope[entry], proc: proc, clientData: clientData];
};
Command menu
StopProc: PUBLIC Menus.ClickProc = TRUSTED {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
tool: BrowserTool ¬ NARROW[clientData];
put: DisplayProc ¬ GetDisplayProc[tool];
LoganQuery.AbortQuery[tool.cursor];
put[LIST[[NIL, "-- Aborted"]], tool];
};
warningThreshold: REAL = 0.75; -- give warning if 3/4 of the database must be searched
BrowseProc: PUBLIC Menus.ClickProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
ENABLE {
LoganBerry.Error => {ReportLBError[ec, explanation, NARROW[clientData]]; CONTINUE};
LoganQuery.SyntaxError => {ReportLBError[$BadQuery, explanation, NARROW[clientData]]; CONTINUE};
};
tool: BrowserTool ¬ NARROW[clientData];
put: DisplayProc ¬ GetDisplayProc[tool];
form: LoganQuery.AttributePatterns;
base: LoganBerry.AttributeType;
other: ROPE;
queryTree: LoganQuery.ParseTree ¬ NIL;
newcursor: LoganQuery.Cursor;
plan: LoganQuery.QueryPlan;
entry: LoganBerry.Entry;
IF mouseButton # blue THEN
ResetViewer[tool.inner];
[form, other, base] ¬ ReadEntryForm[tool];
IF NOT Rope.IsEmpty[other] THEN {
queryTree ¬ LoganQuery.ParseBooleanQuery[IO.RIS[other]];
};
tool.cursor.class ¬ NIL;
FOR d: DBList ¬ tool.databases, d.rest WHILE d#NIL DO
IF d.first.selected THEN {
[newcursor, plan] ¬ LoganQuery.QueryEntries[db: d.first.db, patterns: form, baseIndex: base];
IF queryTree # NIL THEN
newcursor ¬ LoganQuery.BooleanFilterEntries[input: newcursor, query: queryTree, inputOrder: plan.first.attr.type, primaryKey: d.first.schema.indices.first.key];
IF tool.cursor.class=NIL
THEN tool.cursor ¬ newcursor
ELSE tool.cursor ¬ LoganQueryClass.MergeEntries[input1: newcursor, input2: tool.cursor, atype: plan.first.attr.type];
};
ENDLOOP;
IF tool.cursor.class=NIL THEN {
ReportLBError[$NoOp, "No database selected", tool];
RETURN;
};
ReportFeedback[plan, tool];
IF plan.first.cost > warningThreshold THEN
MessageWindow.Append[message: "Browsing complete database...", clearFirst: TRUE];
entry ¬ LoganQuery.NextEntry[tool.cursor];
WHILE entry # NIL DO
put[entry, tool];
entry ¬ LoganQuery.NextEntry[tool.cursor];
ENDLOOP;
put[LIST[[NIL, "-- Done."]], tool];
LoganQuery.EndGenerate[tool.cursor];
};
UpdateProc: PUBLIC Menus.ClickProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
DoUpdateOrReplace[tool: NARROW[clientData], replace: FALSE, reset: mouseButton # blue];
};
ReplaceProc: PUBLIC Menus.ClickProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
DoUpdateOrReplace[tool: NARROW[clientData], replace: TRUE, reset: mouseButton # blue];
};
DoUpdateOrReplace: PROC [tool: BrowserTool, replace: BOOLEAN ¬ FALSE, reset: BOOLEAN ¬ FALSE] ~ {
ENABLE {
LoganBerry.Error => {ReportLBError[ec, explanation, tool]; CONTINUE};
LoganQuery.SyntaxError => {ReportLBError[$MalformedAttribute, explanation, tool]; CONTINUE};
};
put: DisplayProc ¬ GetDisplayProc[tool];
form: LoganQuery.AttributePatterns;
other: ROPE;
entry: LoganBerry.Entry;
dbinfo: LoganBerryBrowser.DBInfo ¬ NIL;
IF reset THEN
ResetViewer[tool.inner];
[form, other,] ¬ ReadEntryForm[tool];
IF NOT Rope.IsEmpty[other] THEN {
otherPatterns: LoganQuery.AttributePatterns ¬ LoganQuery.ReadAttributePatterns[IO.RIS[other]];
form ¬ AppendPatterns[form, otherPatterns];
};
entry ¬ LoganQuery.PatternsToEntry[form];
FOR d: DBList ¬ tool.databases, d.rest WHILE d#NIL DO
IF d.first.selected THEN
IF dbinfo=NIL THEN dbinfo ¬ d.first
ELSE {ReportLBError[$Update, "Please select a single database", tool]; RETURN;};
ENDLOOP;
IF dbinfo=NIL THEN {
ReportLBError[$NoOp, "No database selected", tool];
RETURN;
};
LoganBerry.WriteEntry[db: dbinfo.db, entry: entry, replace: replace];
put[entry, tool];
put[LIST[[NIL, "-- Done."]], tool];
};
DeleteProc: PUBLIC Menus.ClickProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
ENABLE {
LoganBerry.Error => {ReportLBError[ec, explanation, NARROW[clientData]]; CONTINUE};
LoganQuery.SyntaxError => {ReportLBError[$BadQuery, explanation, NARROW[clientData]]; CONTINUE};
};
tool: BrowserTool ¬ NARROW[clientData];
put: DisplayProc ¬ GetDisplayProc[tool];
form: LoganQuery.AttributePatterns;
base: LoganBerry.AttributeType;
other: ROPE;
queryTree: LoganQuery.ParseTree ¬ NIL;
entry: LoganBerry.Entry;
primaryKey: LoganBerry.AttributeType = tool.databases.first.schema.indices.first.key;
plan: LoganQuery.QueryPlan;
dbinfo: LoganBerryBrowser.DBInfo ¬ NIL;
IF mouseButton # blue THEN
ResetViewer[tool.inner];
[form, other, base] ¬ ReadEntryForm[tool];
FOR d: DBList ¬ tool.databases, d.rest WHILE d#NIL DO
IF d.first.selected THEN
IF dbinfo=NIL THEN dbinfo ¬ d.first
ELSE {ReportLBError[$Delete, "Please select a single database", tool]; RETURN;};
ENDLOOP;
IF dbinfo=NIL THEN {
ReportLBError[$NoOp, "No database selected", tool];
RETURN;
};
[tool.cursor, plan] ¬ LoganQuery.QueryEntries[db: dbinfo.db, patterns: form, baseIndex: base];
IF NOT Rope.IsEmpty[other] THEN {
queryTree ¬ LoganQuery.ParseBooleanQuery[IO.RIS[other]];
tool.cursor ¬ LoganQuery.BooleanFilterEntries[input: tool.cursor, query: queryTree, inputOrder: plan.first.attr.type, primaryKey: dbinfo.schema.indices.first.key];
};
ReportFeedback[plan, tool];
put[LIST[[NIL, "-- Deleting..."]], tool];
tool.lastDeletes ¬ NIL;
entry ¬ LoganQuery.NextEntry[tool.cursor];
WHILE entry # NIL DO
LoganBerry.DeleteEntry[db: dbinfo.db, key: primaryKey, value: GetAttributeValue[entry, primaryKey]];
tool.lastDeletes ¬ CONS[entry, tool.lastDeletes];
put[entry, tool];
entry ¬ LoganQuery.NextEntry[tool.cursor];
ENDLOOP;
put[LIST[[NIL, "-- Done."]], tool];
LoganQuery.EndGenerate[tool.cursor];
};
UnDeleteProc: PUBLIC Menus.ClickProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
ENABLE LoganBerry.Error => {ReportLBError[ec, explanation, NARROW[clientData]]; CONTINUE};
tool: BrowserTool ¬ NARROW[clientData];
put: DisplayProc ¬ GetDisplayProc[tool];
dbinfo: LoganBerryBrowser.DBInfo ¬ NIL;
IF mouseButton # blue THEN
ResetViewer[tool.inner];
FOR d: DBList ¬ tool.databases, d.rest WHILE d#NIL DO
IF d.first.selected THEN
IF dbinfo=NIL THEN dbinfo ¬ d.first
ELSE {ReportLBError[$UnDelete, "Please select a single database", tool]; RETURN;};
ENDLOOP;
IF dbinfo=NIL THEN {
ReportLBError[$NoOp, "No database selected", tool];
RETURN;
};
put[LIST[[NIL, "-- UnDeleting..."]], tool];
FOR l: LIST OF LoganBerry.Entry ¬ tool.lastDeletes, l.rest WHILE l#NIL DO
LoganBerry.WriteEntry[db: dbinfo.db, entry: l.first ! LoganBerry.Error => {ReportLBError[ec, explanation, tool]; CONTINUE};];
put[l.first, tool];
ENDLOOP;
tool.lastDeletes ¬ NIL; -- can't undo an undelete
put[LIST[[NIL, "-- Done."]], tool];
};
DetailsProc: PUBLIC Menus.ClickProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
tool: BrowserTool ¬ NARROW[clientData];
IF tool.details.wx = 0 THEN
HideViewer[tool.details]
ELSE
UnHideViewer[tool.details];
};
HistoryProc: PUBLIC Menus.ClickProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
tool: BrowserTool ¬ NARROW[clientData];
IF tool.history.wx = 0 THEN {
HideViewer[tool.history];
ViewerOps.MoveViewer[viewer: tool.inner, x: tool.inner.wx, y: tool.inner.wy - historyHeight, w: tool.inner.ww, h: tool.inner.wh];
tool.height ¬ tool.height - historyHeight;
}
ELSE {
ViewerOps.MoveViewer[viewer: tool.inner, x: tool.inner.wx, y: tool.inner.wy + historyHeight, w: tool.inner.ww, h: tool.inner.wh];
UnHideViewer[tool.history];
tool.height ¬ tool.height + historyHeight;
};
};
DestroyProc: ViewerEvents.EventProc = {
[viewer: ViewerClasses.Viewer, event: ViewerEvents.ViewerEvent, before: BOOL] RETURNS [abort: BOOL ← FALSE]
-- Does nothing at the moment
tool: BrowserTool ← NARROW[ViewerOps.FetchProp[viewer: viewer, prop: $BrowserTool]];
LoganBerry.Close[db: tool.databases.first.db ! LoganBerry.Error => {ReportLBError[ec, explanation, tool]; CONTINUE}];
};
Default browser operations
SetDefaults: PROC [tool: BrowserTool] RETURNS [] ~ {
IF tool.name = NIL THEN
tool.name ¬ Rope.Concat["LoganBerry Browser: ", tool.databases.first.schema.dbName];
IF tool.menu = NIL THEN {
tool.menu ¬ StandardMainMenu[tool];
};
IF tool.innerFlavor = NIL THEN
tool.innerFlavor ¬ $TypeScript;
IF tool.icon = unInit THEN
tool.icon ¬ browserIcon;
IF tool.fields = NIL THEN
tool.fields ¬ IndexKeys[tool];
};
IndexKeys: PROC [tool: BrowserTool] RETURNS [fields: LIST OF LoganBerry.AttributeType] ~ {
tail: LIST OF LoganBerry.AttributeType ¬ NIL;
FOR i: LIST OF LoganBerry.IndexInfo ¬ tool.databases.first.schema.indices, i.rest WHILE i#NIL DO
IF tail#NIL
THEN {tail.rest ¬ LIST[i.first.key]; tail ¬ tail.rest;}
ELSE {fields ¬ tail ¬ LIST[i.first.key];}
ENDLOOP;
};
StandardMainMenu: PROC [tool: BrowserTool] RETURNS [menu: Menus.Menu] ~ {
AppendMenu: PROC[menu: Menus.Menu, name: ROPE, proc: Menus.ClickProc, line: Menus.MenuLine ¬ 0, guarded: BOOL ¬ FALSE] = {
Menus.AppendMenuEntry[ 
menu: menu,
entry: Menus.CreateEntry[name: name, proc: proc, clientData: tool, guarded: guarded],
line: line
];
};
menu ¬ Menus.CreateMenu[lines: 2];
--first line--
AppendMenu[menu, "STOP!", StopProc];
AppendMenu[menu, "Browse", BrowseProc];
AppendMenu[menu, "Update", UpdateProc];
AppendMenu[menu, "Replace", ReplaceProc];
AppendMenu[menu, "Delete", DeleteProc, 0, TRUE];
AppendMenu[menu, "UnDelete", UnDeleteProc, 0, TRUE];
AppendMenu[menu, "History", HistoryProc];
AppendMenu[menu, "Details", DetailsProc];
AppendMenu[menu, "AdminOps", AdminOpsProc];
--second line--
AppendMenu[menu, "Open", OpenProc, 1];
AppendMenu[menu, "Close", CloseProc, 1, TRUE];
AppendMenu[menu, "BuildIndices", BuildIndicesProc, 1, TRUE];
AppendMenu[menu, "CompactLogs", CompactLogsProc, 1, TRUE];
};
AdminOpsProc: PUBLIC Menus.ClickProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
tool: BrowserTool ¬ NARROW[clientData];
newCount: CARDINAL ¬ IF Menus.GetNumberOfLines[tool.menu] = 1 THEN 2 ELSE 1;
Menus.ChangeNumberOfLines[tool.menu, newCount];
ViewerBLT.ChangeNumberOfLines[tool.outer, newCount];
};
OpenProc: PUBLIC Menus.ClickProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
tool: BrowserTool ¬ NARROW[clientData];
FOR d: DBList ¬ tool.databases, d.rest WHILE d#NIL DO
IF d.first.selected THEN
d.first.db ¬ LoganBerry.Open[dbName: d.first.schema.dbName ! LoganBerry.Error => {ReportLBError[ec, explanation, tool]; CONTINUE}];
ENDLOOP;
};
CloseProc: PUBLIC Menus.ClickProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
tool: BrowserTool ¬ NARROW[clientData];
FOR d: DBList ¬ tool.databases, d.rest WHILE d#NIL DO
IF d.first.selected THEN
LoganBerry.Close[db: d.first.db ! LoganBerry.Error => {ReportLBError[ec, explanation, tool]; CONTINUE}];
ENDLOOP;
};
BuildIndicesProc: PUBLIC Menus.ClickProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
tool: BrowserTool ¬ NARROW[clientData];
FOR d: DBList ¬ tool.databases, d.rest WHILE d#NIL DO
IF d.first.selected THEN
LoganBerry.BuildIndices[db: d.first.db ! LoganBerry.Error => {ReportLBError[ec, explanation, tool]; CONTINUE}];
ENDLOOP;
};
CompactLogsProc: PUBLIC Menus.ClickProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
tool: BrowserTool ¬ NARROW[clientData];
FOR d: DBList ¬ tool.databases, d.rest WHILE d#NIL DO
IF d.first.selected THEN
LoganBerry.CompactLogs[db: d.first.db ! LoganBerry.Error => {ReportLBError[ec, explanation, tool]; CONTINUE}];
ENDLOOP;
};
GetAttributeValue: PROC [entry: LoganBerry.Entry, type: LoganBerry.AttributeType] RETURNS [LoganBerry.AttributeValue] ~ {
FOR e: LoganBerry.Entry ¬ entry, e.rest WHILE e # NIL DO
IF e.first.type = type THEN
RETURN[e.first.value];
ENDLOOP;
RETURN[NIL];
};
ReportLBError: PROC [ec: LoganBerry.ErrorCode, explanation: ROPE, tool: BrowserTool] RETURNS [] ~ {
put: DisplayProc ¬ GetDisplayProc[tool];
put[LIST[[$ERROR, IO.PutFR["%g - %g", IO.atom[ec], IO.rope[explanation]]]], tool];
};
GetDisplayProc: PROC [tool: BrowserTool] RETURNS [proc: DisplayProc] ~ {
Looks up the display proc associated with the specified browser.
RETURN[IF tool.display=NIL THEN PrintEntry ELSE tool.display];
};
Initialization
browserIcon ¬ Icons.NewIconFromFile[file: "LoganBerry.icons", n: 0 ! ANY => CONTINUE];
END.
Doug Terry, November 27, 1985 3:22:06 pm PST
taken from WPBrowserToolImpl.mesa
changes to: DIRECTORY, LoganBerryBrowserTool, browserIcon, db, dbFileName, NamedFilter, Commander, END, BrowseProc, DetailsProc, HistoryProc, MakeMainMenu, BrowserToolRec, MakeBrowserTool, itemHeight, interItemHeight, ruleHeight, patternButtonWidth, patternHSpace, historyHeight, AppendMenu (local of MakeMainMenu), MakeEntryForm, AppendEntry (local of MakeEntryForm), MakeSortButton, DividingLine, FormFieldRec, AddToSortList (local of MakeSortButton), StopProc, BrowseProc, DoQuery, PutEntry (local of DoQuery), NewFilter (local of DoQuery), ROPE, STREAM
Doug Terry, November 27, 1985 4:05:43 pm PST
changes to: PutEntry (local of DoQuery), MakeSortButton, DIRECTORY
Doug Terry, November 27, 1985 5:56:01 pm PST
changes to: MakeSortButton, AddToSortList (local of MakeSortButton), DIRECTORY, DestroyProc, MakeMainMenu, MakeBrowserTool, browserIcon, Commander, LoganBerryBrowserTool
Doug Terry, November 27, 1985 6:18:58 pm PST
changes to: MakeBrowserTool
Doug Terry, January 23, 1986 8:41:38 pm PST
changes to: DestroyProc, MakeBrowserTool
Doug Terry, January 31, 1986 2:46:52 pm PST
changes to: AdminOpsProc, OpenProc, CloseProc, BuildIndiciesProc, CompactLogsProc, DestroyProc, MakeMainMenu, DIRECTORY, AppendMenu (local of MakeMainMenu), MakeBrowserTool, LoganBerryBrowserTool
Doug Terry, January 31, 1986 2:53:26 pm PST
changes to: AdminOpsProc, MakeMainMenu, MakeBrowserTool, AppendMenu (local of MakeMainMenu)
Doug Terry, January 31, 1986 5:21:25 pm PST
changes to: AppendMenu (local of MakeMainMenu), MakeMainMenu, MakeBrowserTool, BrowseProc, DIRECTORY
Doug Terry, March 5, 1986 6:18:08 pm PST
Now calls LoganBerry.Describe to obtain the list of available indices and catches LoganBerry.Errors.
changes to: DIRECTORY, MakeEntryForm, OpenProc, CloseProc, BuildIndiciesProc, CompactLogsProc, DestroyProc, MakeBrowserTool, PutEntry (local of DoQuery)
Doug Terry, April 24, 1986 9:47:20 am PST
Changed to use LoganBerryStub.
changes to: DIRECTORY, LoganBerryBrowserTool, BrowserToolRec, OpenProc, MakeBrowserTool, DoQuery, ReportLBError
Doug Terry, April 24, 1986 9:51:16 am PST
changes to: DIRECTORY, LoganBerryBrowserTool, BrowserToolRec, OpenProc, MakeBrowserTool, DoQuery, ReportLBError
Doug Terry, July 1, 1986 6:00:40 pm PDT
Added History facility.
changes to: FormFieldRec, FormValue, FormValueRec, FormContents, MakeSortButton, ReadEntryForm, NextField (local of ReadEntryForm), AddToHistory, AddToLine (local of AddToHistory), RestoreFromHistory, HistoryButtonProc, DoQuery, BrowseProc, RestoreEntryForm, PutEntry, GetAttributeValue, DIRECTORY, LoganBerryBrowserTool, ROPE, STREAM, HistoryData, HistoryDataRec, RestoreField (local of RestoreEntryForm), HistoryProc, DetailsProc, UnHideViewer, HideViewer, MakeBrowserTool
Doug Terry, July 1, 1986 9:04:42 pm PDT
changes to: BuildIndicesProc, MakeMainMenu
Doug Terry, October 16, 1986 5:58:19 pm PDT
changes to: DoQuery
Doug Terry, October 22, 1986 4:10:21 pm PDT
Changed to use LoganBerryCommands and provide a similar model of operation; added support for updates and deletes.
changes to: BrowserToolRec, UpdateProc, DeleteProc, DetailsProc, MakeMainMenu, MakeInputArea, MakeSortButton, MakeBrowserTool, FormContents, BrowseProc, AddToHistory, HistoryButtonProc, NextField (local of ReadEntryForm), RestoreField (local of RestoreEntryForm), RestoreEntryForm, DoQuery, AttributePattern, AttributePatternRec, HistoryDataRec, MakeEntryForm, ReadEntryForm, DoQuery, DIRECTORY, LoganBerryBrowserTool, PutEntry (local of DoOp), DeleteEntry (local of DoOp)
Doug Terry, October 31, 1986 4:56:08 pm PST
Exports and uses CreateTool operation.
changes to: DIRECTORY, LoganBerryBrowserImpl, BrowserToolRec, AttributePattern, AttributePatternRec, AttributePatterns, MakeEntryForm, AddToHistory, CreateTool, DoOp, PutEntry (local of DoOp), MakeBrowserTool, browserIcon
Doug Terry, November 2, 1986 7:00:17 pm PST
Added support for subrange filtering and UnDelete.
changes to: BrowserToolRec, UnDeleteProc, DetailsProc, MakeEntryForm, DeleteEntry (local of DoOp), DoOp
Doug Terry, November 23, 1986 9:29:41 pm PST
Moved support for filtered queries to this module; removed any command registrations.
changes to: LoganBerryBrowserImpl, HistoryDataRec, historyHeight, MakeMainMenu, HistoryButtonProc, UnHideViewer, CreateTool, SyntaxError, Read, LoganQuery, FilteredQuery, Subrange, ReportLBError, browserIcon, DIRECTORY, BrowserToolRec, PrintEntry, PutEntry (local of DoOp), DoOp
Doug Terry, November 24, 1986 4:58:48 pm PST
Added new filters: DWIM, NumSubrange, DateSubrange, DateAndTime.
changes to: OptimalStart, NamedFilter, subrangeCache, ParseSubrange, ToDash (local of ParseSubrange), Subrange, NumSubrange, DateSubrange, srCache, nsrCache, dsrCache, DateSubrange, DIRECTORY, LoganBerryBrowserImpl, FilteredQuery, NamedFilter, MakeEntryForm
Doug Terry, December 4, 1986 6:59:04 pm PST
Changed CreateTool to create inner (output) viewers of various flavors.
changes to: DIRECTORY, CreateTool
Doug Terry, December 15, 1986 6:31:17 pm PST
Stop! now calls Process.Abort, which raises ABORTED, which is caught in DoOp.
changes to: OptimalStart, BaseStartEnd, DIRECTORY, LoganBerryBrowserImpl, BrowserToolRec, StopProc, DoOp, PutEntry (local of DoOp), DeleteEntry (local of DoOp)
Doug Terry, December 22, 1986 5:12:02 pm PST
changes to: historyHeight, patternChoices, defaultPattern, MakeEntryForm
Doug Terry, December 23, 1986 4:11:02 pm PST
changes to: ReadEntryForm, NextField (local of ReadEntryForm), SyntaxError, QueryWarning, FilteredQuery, DoOp
Doug Terry, December 29, 1986 3:04:30 pm PST
Added computation of start and end for various types of base indices; uses estimated query cost to select the optimal base index if one is not specified.
changes to: BaseStartEnd, Bump (local of BaseStartEnd), Upper (local of BaseStartEnd), Lower (local of BaseStartEnd), MakeEntryForm, ReadEntryForm, CreateTool, FilteredQuery, GetIndexType, QueryCost
changes to: Bump (local of BaseStartEnd), warningThreshold, QueryWarning, FilteredQuery
Doug Terry, December 29, 1986 4:36:38 pm PST
changes to: warningThreshold, QueryWarning, FilteredQuery, Bump (local of BaseStartEnd), Feedback, RegisterFeedbackArea
Doug Terry, January 27, 1987 5:57:51 pm PST
changes to: DIRECTORY, LoganBerryBrowserImpl, DoOp, BrowserToolRec, UnDeleteProc, MakeEntryForm, MakeSortButton, CreateTool
Doug Terry, January 28, 1987 10:58:00 am PST
Added calls to LoganBerryExtras to get the ordering of indices; reduced assumptions about the flavor of the inner viewer (used to assume it was a typescript in various places); made Delete and UnDelete call the client-provided DisplayProc; added calls to the OpProc for $LBUnDelete and $LBStop.
changes to: MakeEntryForm
changes to: DIRECTORY, LoganBerryBrowserImpl, EntryToPatterns, AppendPatterns, DoOp
changes to: BrowseProc, DeleteProc, UnDeleteProc, UnHideViewer, ResetViewer, ReportLBError
Doug Terry, January 28, 1987 9:26:14 pm PST
changes to: BrowseProc, UpdateProc, DeleteProc, UnDeleteProc, OpenProc, CloseProc, BuildIndicesProc, CompactLogsProc, DestroyProc, UnHideViewer, ResetViewer, DoOp, DeleteEntry (local of DoOp), UnDeleteEntry (local of DoOp), ReportLBError
Doug Terry, January 29, 1987 1:47:06 pm PST
changes to: BrowserToolRec, MakeSortButton, DIRECTORY, LoganBerryBrowserImpl, FilteredQuery, DeleteEntry (local of DoOp), DoOp, ClearFeedback, ReportFeedback, ReportLBError
Doug Terry, January 29, 1987 3:42:53 pm PST
changes to: patternHSpace, feedbackHSpace, MakeSortButton, DIRECTORY, FormFieldRec, MakeEntryForm, NextField (local of ReadEntryForm), ReadEntryForm, RestoreField (local of RestoreEntryForm), RestoreEntryForm, DeleteEntry (local of DoOp), ReportFeedback (local of DoOp), DoOp, FilteredQuery, AnalyzePattern
Doug Terry, February 24, 1987 2:04:02 pm PST
Changed the way browsers are customized; clients are now responsible for providing the main menu and operations (see "Default browser operations")
changes to: BrowserTool, DetailsProc, CreateTool, SetDefaults, StandardMainMenu, BrowseProc, DoOp, MakeEntryForm, StandardMainMenu, ReadEntryForm, RestoreEntryForm, ReportFeedback, AddToHistory, PrintEntry, PutEntry (local of DoOp), DeleteEntry (local of DoOp), Feedback (local of DoOp), DataRec, SetDefaults, ReportLBError, DIRECTORY
Doug Terry, February 24, 1987 2:30:23 pm PST
changes to: StandardMainMenu, CreateTool, SetDefaults, DIRECTORY
Doug Terry, March 4, 1987 10:48:08 am PST
changes to: defaultPattern
Doug Terry, April 15, 1987 11:45:33 am PDT
Moved query facilities to LoganQueryImpl; this module should mainly be concerned with the user interface.
changes to: defaultPattern, CreateTool, PrintEntry, StopProc, BrowseProc, UpdateProc, DeleteProc, UnDeleteProc, DetailsProc, HistoryProc, SetDefaults, StandardMainMenu
Doug Terry, June 15, 1987 8:24:25 pm PDT
Added facilities for browsing several LoganBerry databases with the same browser tool, e.g. merged queries.
changes to: DIRECTORY, BrowserTool, DBList, MakeDatabaseButton, ToggleDatabaseButton, MakeSortButton, CreateTool, BrowseProc, UpdateProc, DeleteProc, UnDeleteProc, DestroyProc, SetDefaults, IndexKeys, OpenProc, CloseProc, BuildIndicesProc, CompactLogsProc, MakeEntryForm, RestoreEntryForm
Doug Terry, July 27, 1987 7:07:28 pm PDT
Changed to support LoganBerryBrowserExtras interface; removed all reliance on typescripts in standard menu procs.
changes to: DIRECTORY, LoganBerryBrowserImpl, AdminOpsProc, OpenProc, CloseProc, BuildIndicesProc, CompactLogsProc, DBList, DisplayProc, PrintEntry, StopProc, DeleteProc, UnDeleteProc, ReportLBError, GetDisplayProc, PrintEntryAsButton, DisplayTable, RegisterDisplayProc, EntryToRope (local of PrintEntryAsButton), BrowserTool
Doug Terry, July 17, 1992 11:37:07 am PDT
Changed "other" field of browser to be parsed as a boolean query for Browse and Delete operations.