MODULE WMSearchTool;
IMPORT Files, Modules, WMGraphics, WMSystemComponents, WMComponents, WMStandardComponents,
WMWindowManager, WMEditors, WMRectangles, WMMessages, WMRestorable, Strings, Inputs;
CONST
RListSize = 1000;
TYPE
KillerMsg = OBJECT
END KillerMsg;
Editor = OBJECT (WMEditors.Editor)
VAR
nextFocus, prevFocus: WMComponents.VisualComponent;
withShift: BOOLEAN;
PROCEDURE FocusNext;
BEGIN
IF withShift THEN
FocusPrev;
ELSE
IF nextFocus # NIL THEN
nextFocus.SetFocus;
IF (nextFocus IS WMEditors.Editor) THEN
WITH nextFocus: WMEditors.Editor DO
SELF.tv.selection.SetFromTo(0, 0);
nextFocus.tv.SelectAll();
END;
END;
END;
END;
END FocusNext;
PROCEDURE FocusPrev;
BEGIN
IF prevFocus # NIL THEN
prevFocus.SetFocus;
IF (prevFocus IS WMEditors.Editor) THEN
WITH prevFocus: WMEditors.Editor DO
SELF.tv.selection.SetFromTo(0, 0);
prevFocus.tv.SelectAll();
END;
END;
END;
END FocusPrev;
PROCEDURE KeyPressed(ucs : LONGINT; flags : SET; VAR keySym : LONGINT; VAR handled : BOOLEAN);
BEGIN
IF (flags # {}) & (flags - Inputs.Shift = {}) THEN
withShift := TRUE;
ELSE
withShift := FALSE;
END;
IF (keySym = Inputs.KsTab) & (flags - Inputs.Shift = {}) THEN
keySym := 0FF0DH;
END;
KeyPressed^(ucs, flags, keySym, handled);
END KeyPressed;
PROCEDURE SetDoubleLinkedNextFocus(next: Editor);
BEGIN
SELF.nextFocus := next;
next.prevFocus := SELF;
END SetDoubleLinkedNextFocus;
END Editor;
Window = OBJECT(WMComponents.FormWindow)
VAR
status : WMStandardComponents.Panel;
statusLabel : WMStandardComponents.Label;
pathEdit, fmaskEdit, contentEdit : Editor;
searchBtn, stopBtn : WMStandardComponents.Button;
filelist : WMSystemComponents.FileList;
lb : ListBuffer;
s : Searcher;
d : GridDisplayer;
PROCEDURE &New*(c : WMRestorable.Context);
VAR vc : WMComponents.VisualComponent;
BEGIN
IncCount;
vc := CreateForm();
Init(vc.bounds.GetWidth(), vc.bounds.GetHeight(), FALSE);
SetContent(vc);
SetTitle(Strings.NewString("Search Tool"));
SetIcon(WMGraphics.LoadImage("WMIcons.tar://WMSearchTool.png", TRUE));
pathEdit.tv.SelectAll();
pathEdit.SetFocus();
form.Invalidate();
IF c # NIL THEN
WMRestorable.AddByContext(SELF, c);
ELSE
WMWindowManager.DefaultAddWindow(SELF);
END;
NEW(lb);
NEW(s, lb);
NEW(d, lb, filelist.DisplayGrid, SearchStartHandler, SearchDoneHandler)
END New;
PROCEDURE Close;
BEGIN
Close^;
DecCount
END Close;
PROCEDURE CreateForm(): WMComponents.VisualComponent;
VAR panel : WMStandardComponents.Panel;
toolbarPath, toolbarFMask, toolbar, toolbarSearch : WMStandardComponents.Panel;
pathLabel, fmaskLabel, contentLabel : WMStandardComponents.Label;
filledPathString : ARRAY 1024 OF CHAR;
BEGIN
NEW(panel); panel.bounds.SetExtents(700, 500); panel.fillColor.Set(LONGINT(0FFFFFFFFH)); panel.takesFocus.Set(TRUE);
NEW(toolbarPath); toolbarPath.fillColor.Set(LONGINT(0FFFFFFFFH)); toolbarPath.bounds.SetHeight(25);
toolbarPath.alignment.Set(WMComponents.AlignTop);
panel.AddContent(toolbarPath);
NEW(toolbarFMask); toolbarFMask.fillColor.Set(LONGINT(0FFFFFFFFH)); toolbarFMask.bounds.SetHeight(25);
toolbarFMask.alignment.Set(WMComponents.AlignTop);
panel.AddContent(toolbarFMask);
NEW(toolbar); toolbar.fillColor.Set(LONGINT(0FFFFFFFFH)); toolbar.bounds.SetHeight(25);
toolbar.alignment.Set(WMComponents.AlignTop);
panel.AddContent(toolbar);
NEW(toolbarSearch); toolbarSearch.fillColor.Set(LONGINT(0FFFFFFFFH)); toolbarSearch.bounds.SetHeight(20);
toolbarSearch.alignment.Set(WMComponents.AlignTop);
panel.AddContent(toolbarSearch);
NEW(pathLabel); pathLabel.alignment.Set(WMComponents.AlignLeft);
pathLabel.bounds.SetWidth(70); pathLabel.fillColor.Set(LONGINT(0FFFFFFFFH));
pathLabel.SetCaption(" Path:");
toolbarPath.AddContent(pathLabel);
FillFirstMountedFS(filledPathString);
NEW(pathEdit); pathEdit.SetAsString(filledPathString); pathEdit.alignment.Set(WMComponents.AlignLeft);
pathEdit.bounds.SetWidth(300); pathEdit.multiLine.Set(FALSE);
pathEdit.tv.borders.Set(WMRectangles.MakeRect(3, 3, 1, 1));
pathEdit.tv.showBorder.Set(TRUE);
pathEdit.fillColor.Set(LONGINT(0FFFFFFFFH));
toolbarPath.AddContent(pathEdit);
NEW(pathLabel); pathLabel.alignment.Set(WMComponents.AlignLeft);
pathLabel.bounds.SetWidth(300); pathLabel.fillColor.Set(LONGINT(0FFFFFFFFH));
pathLabel.SetCaption(" e.g. FS:, FS:/subDir, FS:/subDir/subSubDir, etc.");
toolbarPath.AddContent(pathLabel);
NEW(fmaskLabel); fmaskLabel.alignment.Set(WMComponents.AlignLeft);
fmaskLabel.bounds.SetWidth(70); fmaskLabel.fillColor.Set(LONGINT(0FFFFFFFFH));
fmaskLabel.SetCaption(" Files:");
toolbarFMask.AddContent(fmaskLabel);
NEW(fmaskEdit); fmaskEdit.alignment.Set(WMComponents.AlignLeft);
fmaskEdit.bounds.SetWidth(300); fmaskEdit.multiLine.Set(FALSE);
fmaskEdit.tv.borders.Set(WMRectangles.MakeRect(3, 3, 1, 1));
fmaskEdit.tv.showBorder.Set(TRUE);
fmaskEdit.fillColor.Set(LONGINT(0FFFFFFFFH));
toolbarFMask.AddContent(fmaskEdit);
NEW(contentLabel); contentLabel.alignment.Set(WMComponents.AlignLeft);
contentLabel.bounds.SetWidth(70); contentLabel.fillColor.Set(LONGINT(0FFFFFFFFH));
contentLabel.SetCaption(" Content:");
toolbar.AddContent(contentLabel);
NEW(contentEdit); contentEdit.alignment.Set(WMComponents.AlignLeft);
contentEdit.bounds.SetWidth(300); contentEdit.multiLine.Set(FALSE);
contentEdit.tv.borders.Set(WMRectangles.MakeRect(3, 3, 1, 1));
contentEdit.tv.showBorder.Set(TRUE);
contentEdit.fillColor.Set(LONGINT(0FFFFFFFFH));
toolbar.AddContent(contentEdit);
NEW(searchBtn);
searchBtn.caption.SetAOC("Go");
searchBtn.alignment.Set(WMComponents.AlignLeft);
searchBtn.bounds.SetWidth(80);
searchBtn.onClick.Add(SearchHandler);
toolbarSearch.AddContent(searchBtn);
NEW(stopBtn);
stopBtn.caption.SetAOC("Stop");
stopBtn.alignment.Set(WMComponents.AlignLeft);
stopBtn.bounds.SetWidth(80);
stopBtn.onClick.Add(StopHandler);
toolbarSearch.AddContent(stopBtn);
NEW(status); status.alignment.Set(WMComponents.AlignBottom); status.bounds.SetHeight(20);
panel.AddContent(status); status.fillColor.Set(LONGINT(0CCCCCCFFH));
NEW(statusLabel); statusLabel.bounds.SetWidth(panel.bounds.GetWidth());
statusLabel.caption.SetAOC("Status : Ready"); statusLabel.alignment.Set(WMComponents.AlignLeft);
status.AddContent(statusLabel);
NEW(filelist);
filelist.SetSearchReqFlag;
filelist.alignment.Set(WMComponents.AlignClient);
panel.AddContent(filelist);
pathEdit.SetDoubleLinkedNextFocus(fmaskEdit);
fmaskEdit.SetDoubleLinkedNextFocus(contentEdit);
pathEdit.onEnter.Add(OnEnterHandler);
fmaskEdit.onEnter.Add(OnEnterHandler);
contentEdit.onEnter.Add(OnEnterHandler);
pathEdit.onEscape.Add(OnEscapeHandler);
fmaskEdit.onEscape.Add(OnEscapeHandler);
contentEdit.onEscape.Add(OnEscapeHandler);
RETURN panel
END CreateForm;
PROCEDURE OnEnterHandler(sender, data: ANY);
BEGIN
IF sender = pathEdit THEN
pathEdit.FocusNext();
ELSIF sender = fmaskEdit THEN
fmaskEdit.FocusNext();
ELSIF sender = contentEdit THEN
IF contentEdit.withShift THEN
contentEdit.FocusPrev();
ELSE
stopBtn.onClick.Call(NIL);
searchBtn.onClick.Call(NIL);
END;
END;
END OnEnterHandler;
PROCEDURE OnEscapeHandler(sender, data: ANY);
BEGIN
stopBtn.onClick.Call(NIL);
END OnEscapeHandler;
PROCEDURE FillFirstMountedFS(VAR s : ARRAY OF CHAR);
VAR list: Files.FileSystemTable;
BEGIN
Files.GetList(list);
IF LEN(list) > 0 THEN
COPY(list[0].prefix, s); Strings.Append(s, ":")
ELSE
s := "";
END
END FillFirstMountedFS;
PROCEDURE SearchDoneHandler;
BEGIN
statusLabel.caption.SetAOC("Status : Ready");
END SearchDoneHandler;
PROCEDURE SearchStartHandler;
BEGIN
statusLabel.caption.SetAOC("Status : Processing ...")
END SearchStartHandler;
PROCEDURE SearchHandler(sender, data : ANY);
VAR
searchPar : SearchPar;
BEGIN
pathEdit.GetAsString(searchPar.path); fmaskEdit.GetAsString(searchPar.fmask); contentEdit.GetAsString(searchPar.content);
StopSearcherAndDisplayer();
filelist.ResetGrid;
s.Start(searchPar);
d.Start()
END SearchHandler;
PROCEDURE StopHandler(sender, data : ANY);
BEGIN
StopSearcherAndDisplayer()
END StopHandler;
PROCEDURE StopSearcherAndDisplayer;
BEGIN
s.Stop();
d.Stop()
END StopSearcherAndDisplayer;
PROCEDURE Handle(VAR x: WMMessages.Message);
BEGIN
IF (x.msgType = WMMessages.MsgExt) & (x.ext # NIL) THEN
IF (x.ext IS KillerMsg) THEN Close
ELSIF (x.ext IS WMRestorable.Storage) THEN
x.ext(WMRestorable.Storage).Add("WMSearchTool", "WMSearchTool.Restore", SELF, NIL)
ELSE Handle^(x)
END
ELSE Handle^(x)
END
END Handle;
END Window;
TYPE
SearchPar = RECORD
path, fmask, content : ARRAY 256 OF CHAR
END;
Searcher = OBJECT
VAR
newlyStarted, stopped : BOOLEAN;
currentPar, newPar : SearchPar;
lb : ListBuffer;
PROCEDURE &Init*(lb : ListBuffer);
BEGIN
newlyStarted := FALSE;
stopped := FALSE;
SELF.lb := lb;
END Init;
PROCEDURE Start(searchPar : SearchPar);
BEGIN {EXCLUSIVE}
newPar := searchPar;
newlyStarted := TRUE;
END Start;
PROCEDURE AwaitNewStart;
BEGIN {EXCLUSIVE}
AWAIT(newlyStarted = TRUE);
newlyStarted := FALSE;
stopped := FALSE;
END AwaitNewStart;
PROCEDURE CopySearchParams;
BEGIN {EXCLUSIVE}
currentPar := newPar
END CopySearchParams;
PROCEDURE Stop;
BEGIN {EXCLUSIVE}
stopped := TRUE;
END Stop;
PROCEDURE IsStopped() : BOOLEAN;
BEGIN {EXCLUSIVE}
RETURN stopped;
END IsStopped;
PROCEDURE ContainsStr(CONST filename, content : ARRAY OF CHAR) : BOOLEAN;
VAR r : Files.Reader;
f : Files.File;
d : ARRAY 256 OF LONGINT;
cb : Strings.String;
cpos, i, j, k, m, shift : LONGINT;
BEGIN
m := Strings.Length(content);
f := Files.Old(filename);
IF f # NIL THEN
Files.OpenReader(r, f, 0);
NEW(cb, m);
WHILE (r.res # 0) & (cpos < m) DO
cb[cpos] := r.Get();
INC(cpos);
END;
IF r.res = 0 THEN
FOR i := 0 TO 255 DO d[i] := m END;
FOR i := 0 TO m-2 DO d[ORD(content[i])] := m - i - 1 END;
i := m;
REPEAT j := m; k := i;
REPEAT DEC(k); DEC(j);
UNTIL (j < 0) OR (content[j] # cb[k MOD m]);
shift := d[ORD(cb[(i-1) MOD m])];
i := i + shift;
WHILE (cpos < i) & (r.res = 0) DO
cb[cpos MOD m] := r.Get();
INC(cpos);
END;
IF IsStopped() THEN RETURN FALSE END
UNTIL (j < 0) OR (r.res # 0);
IF j < 0 THEN RETURN TRUE END
END;
RETURN FALSE
ELSE RETURN FALSE
END
END ContainsStr;
PROCEDURE Match(CONST name : ARRAY OF CHAR);
VAR d : WMSystemComponents.DirEntry;
p, filename : ARRAY 1024 OF CHAR;
l : LONGINT;
BEGIN
IF (currentPar.content = "") OR ContainsStr(name, currentPar.content) THEN
Files.SplitPath(name, p, filename);
l := Strings.Length(p);
p[l] := Files.PathDelimiter; p[l + 1] := 0X;
NEW(d, Strings.NewString(filename), Strings.NewString(p), 0, 0, 0, {});
lb.Put(d)
END;
END Match;
PROCEDURE SearchPath;
VAR mask, name : ARRAY 1024 OF CHAR;
flags : SET;
time, date, size, len : LONGINT;
e : Files.Enumerator;
BEGIN
COPY(currentPar.path, mask);
len := Strings.Length(mask);
IF (mask[len-1] = ':') OR (mask[len-1] = '/') THEN
Strings.Append(mask, currentPar.fmask)
ELSE
Strings.Append(mask, '/'); Strings.Append(mask, currentPar.fmask)
END;
NEW(e);
e.Open(mask, {});
WHILE e.HasMoreEntries() DO
IF IsStopped() THEN RETURN END;
IF e.GetEntry(name, flags, time, date, size) THEN
IF ~(Files.Directory IN flags) THEN
Match(name)
END;
END
END
END SearchPath;
BEGIN {ACTIVE}
LOOP
AwaitNewStart;
CopySearchParams;
lb.Reset;
SearchPath;
lb.Finished;
END
END Searcher;
GridDisplayHandler = PROCEDURE {DELEGATE} (CONST data : ARRAY OF WMSystemComponents.DirEntry; noEl : LONGINT);
SearchStatusHandler = PROCEDURE {DELEGATE};
GridDisplayer= OBJECT
VAR rl : RetrievedList;
display : GridDisplayHandler;
startHandler, stopHandler : SearchStatusHandler;
newlyStarted, stopped : BOOLEAN;
lb : ListBuffer;
PROCEDURE &Init*(lb : ListBuffer; display : GridDisplayHandler; sh, dh : SearchStatusHandler);
BEGIN
SELF.lb := lb;
SELF.display := display;
startHandler := sh;
stopHandler := dh;
newlyStarted := FALSE;
stopped := FALSE
END Init;
PROCEDURE Start;
BEGIN {EXCLUSIVE}
newlyStarted := TRUE;
END Start;
PROCEDURE AwaitNewStart;
BEGIN {EXCLUSIVE}
AWAIT(newlyStarted);
newlyStarted := FALSE;
stopped := FALSE
END AwaitNewStart;
PROCEDURE Stop;
BEGIN {EXCLUSIVE}
stopped := TRUE
END Stop;
BEGIN {ACTIVE}
LOOP
AwaitNewStart;
startHandler;
LOOP
lb.Get(rl);
IF (rl.noEl = 0) OR stopped THEN EXIT END; (* either done or stopped *)
display(rl.data, rl.noEl)
END;
stopHandler;
END
END GridDisplayer;
TYPE
RetrievedList = RECORD
data : ARRAY RListSize OF WMSystemComponents.DirEntry;
noEl : INTEGER;
END;
ListBuffer = OBJECT
VAR
data : ARRAY RListSize OF WMSystemComponents.DirEntry;
in, out, maxNoEl : INTEGER;
finished : BOOLEAN;
PROCEDURE &Init*;
BEGIN
Reset
END Init;
PROCEDURE Reset;
BEGIN {EXCLUSIVE}
in := 0; out := 0; maxNoEl := 1;
finished := FALSE
END Reset;
PROCEDURE Put(d : WMSystemComponents.DirEntry);
BEGIN {EXCLUSIVE}
AWAIT(((in + 1) MOD RListSize) # (out MOD RListSize));
data[in MOD RListSize] := d;
INC(in)
END Put;
PROCEDURE Finished;
BEGIN {EXCLUSIVE}
finished := TRUE;
END Finished;
PROCEDURE Get(VAR rlist : RetrievedList);
VAR i, j : INTEGER;
BEGIN {EXCLUSIVE}
AWAIT((in - out >= maxNoEl) OR finished);
i := 0;
FOR j := out TO in -1 DO
rlist.data[i] := data[j MOD RListSize];
INC(i);
END;
rlist.noEl := i;
IF i > maxNoEl THEN maxNoEl := i END;
out := in
END Get;
END ListBuffer;
VAR
nofWindows : LONGINT;
PROCEDURE Restore*(context : WMRestorable.Context);
VAR w : Window;
BEGIN
NEW(w, context)
END Restore;
PROCEDURE Open*;
VAR inst : Window;
BEGIN
NEW(inst, NIL);
END Open;
PROCEDURE IncCount;
BEGIN {EXCLUSIVE}
INC(nofWindows);
END IncCount;
PROCEDURE DecCount;
BEGIN {EXCLUSIVE}
DEC(nofWindows);
END DecCount;
PROCEDURE Cleanup;
VAR die : KillerMsg; msg : WMMessages.Message; m : WMWindowManager.WindowManager;
BEGIN {EXCLUSIVE}
NEW(die); msg.ext := die; msg.msgType := WMMessages.MsgExt;
m := WMWindowManager.GetDefaultManager();
m.Broadcast(msg);
AWAIT(nofWindows = 0)
END Cleanup;
BEGIN
Modules.InstallTermHandler(Cleanup)
END WMSearchTool.
SystemTools.Free WMSystemComponents WMSearchTool WMFileManager~
WMSearchTool.Open ~