WMSystemComponents.Mod 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183
  1. MODULE WMSystemComponents; (** AUTHOR "TF/UG"; PURPOSE "Components for File-Listings etc"; *)
  2. IMPORT
  3. Files, Dates, Strings, XML, XMLObjects, WMProperties, WMEvents, WMComponents, WMTrees, WMGrids, WMStringGrids,
  4. WMRectangles, WMGraphics, Raster,
  5. KernelLog, Configuration,
  6. WMDropTarget, Texts, TextUtilities, Streams, WMPopups, WMDialogs, FileHandlers, Commands,
  7. Archives, UTF8Strings,
  8. Notepad,
  9. WM := WMWindowManager;
  10. CONST
  11. BufSize = 16*1024; (* internal buffer size, used for copy *)
  12. (*FileNameLength = 256;*)
  13. FileNameLength=Files.NameLength;
  14. TraceCopy = 0;
  15. TraceDragging = 1;
  16. Trace = {0};
  17. FilenamePlaceholder = "@filename";
  18. TYPE
  19. FilesDropInterface = OBJECT(WMDropTarget.DropFiles)
  20. VAR
  21. path : Files.FileName;
  22. f : Files.File;
  23. w : Files.Writer;
  24. refresh : WMEvents.EventSource;
  25. overwriteOnce, overwriteAll, overwriteNever, abort : BOOLEAN;
  26. PROCEDURE &New*(CONST str : ARRAY OF CHAR);
  27. BEGIN
  28. COPY(str, path);
  29. NEW(refresh, SELF, NIL, NIL, NIL);
  30. overwriteAll := FALSE; overwriteNever := FALSE; abort := FALSE;
  31. END New;
  32. PROCEDURE OpenPut*(CONST remoteName : ARRAY OF CHAR; VAR outw : Streams.Writer; VAR res : WORD);
  33. VAR oldFile : Files.File; name : ARRAY 1024 OF CHAR;
  34. BEGIN
  35. res := -1;
  36. IF abort THEN RETURN; END;
  37. COPY(path, name); Strings.Append(name, remoteName);
  38. overwriteOnce := FALSE;
  39. oldFile := Files.Old(name);
  40. IF (oldFile # NIL) & ~overwriteAll & ~overwriteNever THEN
  41. res := WMDialogs.Message(WMDialogs.TConfirmation, "Confirm overwriting", remoteName, {WMDialogs.ResNo, WMDialogs.ResYes, WMDialogs.ResAll, WMDialogs.ResAbort, WMDialogs.ResNever});
  42. CASE res OF
  43. |WMDialogs.ResYes: overwriteOnce := TRUE;
  44. |WMDialogs.ResNo: overwriteOnce := FALSE;
  45. |WMDialogs.ResAll: overwriteAll := TRUE;
  46. |WMDialogs.ResAbort: abort := TRUE;
  47. |WMDialogs.ResNever: overwriteNever := TRUE;
  48. ELSE
  49. KernelLog.String("WMSystemComponents: Implementation error, unexpected WMDialog result type."); KernelLog.Ln;
  50. END;
  51. END;
  52. IF TraceCopy IN Trace THEN KernelLog.String(name); KernelLog.String(" ... "); END;
  53. IF (oldFile = NIL) OR overwriteOnce OR overwriteAll THEN
  54. f := Files.New(name);
  55. IF f # NIL THEN
  56. Files.OpenWriter(w, f, 0);
  57. outw := w;
  58. res := Files.Ok;
  59. IF TraceCopy IN Trace THEN
  60. KernelLog.String(" done");
  61. IF (oldFile # NIL) THEN KernelLog.String(" (overwritten)"); END;
  62. KernelLog.String(".");
  63. END;
  64. ELSE
  65. KernelLog.String("Error: Could not create file "); KernelLog.String(name); KernelLog.Ln;
  66. END;
  67. ELSE
  68. IF (TraceCopy IN Trace) & (oldFile # NIL) THEN KernelLog.String("skipped."); KernelLog.Ln; END;
  69. END;
  70. IF TraceCopy IN Trace THEN KernelLog.Ln; END;
  71. END OpenPut;
  72. PROCEDURE ClosePut*(VAR res : WORD);
  73. BEGIN
  74. IF (f # NIL) & (w # NIL) THEN
  75. w.Update;
  76. f.Update;
  77. Files.Register(f);
  78. refresh.Call(NIL)
  79. END
  80. END ClosePut;
  81. END FilesDropInterface;
  82. FilesDropTarget = OBJECT(WMDropTarget.DropTarget)
  83. VAR path : Files.FileName; eh : WMEvents.EventListener;
  84. PROCEDURE &New*(str : Strings.String; e : WMEvents.EventListener);
  85. BEGIN
  86. IF str # NIL THEN COPY(str^, path) END;
  87. MakePathString(path);
  88. eh := e
  89. END New;
  90. PROCEDURE GetInterface*(type : LONGINT) : WMDropTarget.DropInterface;
  91. VAR di : FilesDropInterface;
  92. BEGIN
  93. IF type = WMDropTarget.TypeFiles THEN
  94. NEW(di, path);
  95. IF eh # NIL THEN di.refresh.Add(eh) END;
  96. RETURN di
  97. ELSE RETURN NIL
  98. END
  99. END GetInterface;
  100. END FilesDropTarget;
  101. TYPE
  102. TreeData = OBJECT
  103. VAR
  104. path, name : Strings.String;
  105. END TreeData;
  106. DirectoryTree* = OBJECT(WMTrees.TreeView)
  107. VAR
  108. enumerator : Files.Enumerator;
  109. tree : WMTrees.Tree;
  110. currentPath* : WMProperties.StringProperty;
  111. onPathChanged* : WMEvents.EventSource;
  112. tr : WMTrees.TreeNode;
  113. PROCEDURE &Init*;
  114. BEGIN
  115. Init^;
  116. SetNameAsString(GSDirectoryTree);
  117. SetGenerator("WMSystemComponents.GenDirectoryTree");
  118. (* new properties *)
  119. NEW(currentPath, DirTreePathProt, NIL, NIL); properties.Add(currentPath);
  120. (* new events *)
  121. NEW(onPathChanged, SELF, GSonPathChanged, GSonPathChangedInfo, SELF.StringToCompCommand);
  122. events.Add(onPathChanged);
  123. tree := GetTree();
  124. NEW(enumerator);
  125. onSelectNode.Add(NodeSelected);
  126. onExpandNode.Add(NodeExpanded);
  127. tree.Acquire;
  128. NEW(tr);
  129. tree.SetRoot(tr);
  130. tree.SetNodeCaption(tr, WMComponents.NewString("FileSystems"));
  131. tree.InclNodeState(tr, WMTrees.NodeAlwaysExpanded);
  132. FillMountedFS(tree, tr);
  133. tree.Release;
  134. END Init;
  135. PROCEDURE Refresh*;
  136. BEGIN
  137. tree.Acquire;
  138. FillMountedFS(tree, tr);
  139. tree.Release;
  140. END Refresh;
  141. PROCEDURE NodeExpanded(sender, data : ANY);
  142. VAR p : ANY;
  143. BEGIN
  144. IF (data = NIL) OR ~(data IS WMTrees.TreeNode) THEN RETURN END;
  145. tree.Acquire;
  146. p := tree.GetNodeData(data(WMTrees.TreeNode));
  147. IF (p # NIL) & (p IS TreeData) THEN
  148. IF WMTrees.NodeSubnodesUnknown IN tree.GetNodeState(data(WMTrees.TreeNode)) THEN
  149. EnumerateSubDirectories(tree, data(WMTrees.TreeNode), p(TreeData).path)
  150. END
  151. END;
  152. tree.Release
  153. END NodeExpanded;
  154. PROCEDURE NodeSelected(sender, data : ANY);
  155. VAR p : ANY;
  156. BEGIN
  157. IF (data = NIL) OR ~(data IS WMTrees.TreeNode) THEN RETURN END;
  158. tree.Acquire;
  159. p := tree.GetNodeData(data(WMTrees.TreeNode));
  160. IF (p # NIL) & (p IS TreeData) THEN
  161. EnumerateSubDirectories(tree, data(WMTrees.TreeNode), p(TreeData).path);
  162. currentPath.Set(p(TreeData).path);
  163. onPathChanged.Call(p(TreeData).path)
  164. END;
  165. tree.Release
  166. END NodeSelected;
  167. PROCEDURE DragDropped*(x, y : LONGINT; dragInfo : WM.DragInfo);
  168. VAR node : WMTrees.TreeNode;
  169. dropTarget : FilesDropTarget;
  170. p : ANY;
  171. BEGIN
  172. tree.Acquire;
  173. node := GetNodeAtPos(x, y);
  174. p := tree.GetNodeData(node);
  175. tree.Release;
  176. IF (p # NIL) & (p IS TreeData) THEN
  177. NEW(dropTarget, p(TreeData).path, NIL);
  178. dragInfo.data := dropTarget;
  179. ConfirmDrag(TRUE, dragInfo)
  180. END
  181. END DragDropped;
  182. PROCEDURE PropertyChanged*(sender, property : ANY);
  183. BEGIN
  184. IF (property = currentPath) THEN (*SetPath(currentPath.Get()) *)
  185. ELSE PropertyChanged^(sender, property)
  186. END;
  187. END PropertyChanged;
  188. (* binary insertion algorithm from "Algorithms and Data Structures" by N. Wirth *)
  189. PROCEDURE SortDirs(VAR dir: ARRAY OF TreeData);
  190. VAR i, j, m, L, R : LONGINT;
  191. x : TreeData;
  192. dirName, xName: Strings.String;
  193. BEGIN
  194. FOR i := 1 TO LEN(dir) - 1 DO
  195. x := dir[i]; L := 0; R := i; xName := Strings.NewString(x.name^); Strings.UpperCase(xName^);
  196. WHILE L < R DO
  197. m := (L + R) DIV 2;
  198. dirName := Strings.NewString(dir[m].name^); Strings.UpperCase(dirName^);
  199. IF UTF8Strings.Compare(dirName^, xName^) = UTF8Strings.CmpGreater THEN
  200. R := m
  201. ELSE
  202. L := m + 1
  203. END
  204. END;
  205. FOR j := i TO R + 1 BY -1 DO dir[j] := dir[j - 1] END;
  206. dir[R] := x
  207. END
  208. END SortDirs;
  209. PROCEDURE EnumerateSubDirectories(tree : WMTrees.Tree; node : WMTrees.TreeNode; dir : Strings.String);
  210. VAR name, path, filename, mask : Files.FileName; flags : SET; time, date, size : LONGINT;
  211. dirNode : WMTrees.TreeNode;
  212. td : TreeData; has : BOOLEAN;
  213. dirArray: POINTER TO ARRAY OF TreeData;
  214. i, sz: LONGINT;
  215. BEGIN
  216. tree.Acquire;
  217. IF tree.GetChildren(node) # NIL THEN tree.Release; RETURN END; (* assuming there will be no changes in the structures *)
  218. WHILE tree.GetChildren(node) # NIL DO tree.RemoveNode(tree.GetChildren(node)) END;
  219. COPY(dir^, mask);
  220. IF Strings.Length(mask) >= 1 THEN
  221. IF mask[Strings.Length(mask) - 1] = ':' THEN Strings.Append(mask, '*')
  222. ELSE Strings.Append(mask, '/*')
  223. END
  224. ELSE mask := '*'
  225. END;
  226. enumerator.Open(mask, {});
  227. has := FALSE;
  228. WHILE enumerator.HasMoreEntries() DO
  229. IF enumerator.GetEntry(name, flags, time, date, size) THEN
  230. IF Files.Directory IN flags THEN
  231. has := TRUE; INC(sz)
  232. END
  233. END
  234. END;
  235. enumerator.Reset();
  236. IF has THEN
  237. NEW(dirArray, sz);
  238. WHILE enumerator.HasMoreEntries() DO
  239. IF enumerator.GetEntry(name, flags, time, date, size) THEN
  240. IF Files.Directory IN flags THEN
  241. has := TRUE;
  242. Files.SplitPath(name, path, filename);
  243. NEW(td); td.path := WMComponents.NewString(name); td.name := WMComponents.NewString(filename);
  244. dirArray[i] := td; INC(i)
  245. END
  246. END
  247. END;
  248. SortDirs(dirArray^);
  249. FOR i := 0 TO sz-1 DO
  250. NEW(dirNode); td := dirArray[i];
  251. tree.SetNodeData(dirNode, td);
  252. tree.SetNodeCaption(dirNode, td.name);
  253. tree.InclNodeState(dirNode, WMTrees.NodeSubnodesUnknown);
  254. tree.AddChildNode(node, dirNode)
  255. END
  256. END;
  257. IF has THEN tree.SetNodeState(node, {WMTrees.NodeExpanded})
  258. ELSE tree.SetNodeState(node, {})
  259. END;
  260. enumerator.Close;
  261. tree.Release
  262. END EnumerateSubDirectories;
  263. PROCEDURE FillMountedFS(tree : WMTrees.Tree; node : WMTrees.TreeNode);
  264. VAR list: Files.FileSystemTable;
  265. prefixNode : WMTrees.TreeNode;
  266. td : TreeData;
  267. i : LONGINT;
  268. prefix : Files.Prefix;
  269. BEGIN
  270. Files.GetList(list);
  271. tree.Acquire;
  272. WHILE tree.GetChildren(node) # NIL DO tree.RemoveNode(tree.GetChildren(node)) END;
  273. FOR i := 0 TO LEN(list) - 1 DO
  274. NEW(prefixNode);
  275. tree.SetNodeCaption(prefixNode, WMComponents.NewString(list[i].prefix));
  276. COPY(list[i].prefix, prefix); Strings.Append(prefix, ":");
  277. NEW(td); td.path := WMComponents.NewString(prefix);
  278. tree.SetNodeData(prefixNode, td);
  279. tree.SetNodeState(prefixNode, {WMTrees.NodeSubnodesUnknown});
  280. tree.AddChildNode(node, prefixNode);
  281. END;
  282. tree.Release;
  283. END FillMountedFS;
  284. END DirectoryTree;
  285. TYPE
  286. DirEntry* = OBJECT
  287. VAR
  288. name*, path- : Strings.String;
  289. time, date, size*: LONGINT;
  290. flags : SET;
  291. visible : BOOLEAN;
  292. node* : WMTrees.TreeNode;
  293. PROCEDURE &Init*(name, path : Strings.String; time, date, size : LONGINT; flags : SET);
  294. BEGIN
  295. SELF.name := name;
  296. SELF.path := path;
  297. SELF.time := time;
  298. SELF.date := date;
  299. SELF.size := size;
  300. SELF.flags := flags;
  301. visible := FALSE;
  302. NEW(node)
  303. END Init;
  304. END DirEntry;
  305. DirEntries* = POINTER TO ARRAY OF DirEntry;
  306. SelectionWrapper* = POINTER TO RECORD
  307. sel* : DirEntries;
  308. user* : ANY;
  309. END;
  310. StringWrapper* = POINTER TO RECORD
  311. string* : Strings.String;
  312. END;
  313. FileList* = OBJECT(WMComponents.VisualComponent)
  314. VAR
  315. grid : WMStringGrids.StringGrid;
  316. prefixSearch : WMProperties.BooleanProperty;
  317. path, filter : Strings.String;
  318. fullView, fromSearchReq : BOOLEAN;
  319. popup: WMPopups.Popup;
  320. enumerator : Files.Enumerator;
  321. dir : DirEntries;
  322. selection : DirEntries;
  323. nfiles, nofRows : LONGINT;
  324. px, py : LONGINT;
  325. colWidths : WMGrids.Spacings;
  326. PROCEDURE &Init*;
  327. BEGIN
  328. Init^;
  329. SetNameAsString(GSFileList);
  330. SetGenerator("WMSystemComponents.GenFileList");
  331. (* new properties *) (* it is not possible to change this property at any time but we leave it for the moment *)
  332. NEW(prefixSearch, FileListPrefixSearchProt, NIL, NIL); properties.Add(prefixSearch);
  333. fullView := FALSE;
  334. fromSearchReq := FALSE;
  335. NEW(grid);
  336. grid.alignment.Set(WMComponents.AlignClient);
  337. AddContent(grid);
  338. grid.SetExtDragDroppedHandler(MyDragDropped);
  339. grid.onClickSelected.Add(ClickSelected);
  340. grid.SetExtContextMenuHandler(ContextMenu);
  341. grid.onStartDrag.Add(MyStartDrag);
  342. grid.model.Acquire;
  343. grid.model.SetNofCols(1);
  344. grid.model.SetNofRows(1);
  345. grid.fixedRows.Set(1);
  346. NEW(colWidths, 3);
  347. grid.model.SetCellText(0, 0, Strings.NewString("Filename"));
  348. grid.model.SetCellText(1, 0, Strings.NewString("Size"));
  349. grid.model.SetCellText(2, 0, Strings.NewString("Modified"));
  350. grid.SetSelectionMode(WMGrids.GridSelectRows);
  351. grid.model.Release;
  352. NEW(enumerator);
  353. SELF.path := Strings.NewString("");
  354. SELF.filter := Strings.NewString("");
  355. END Init;
  356. PROCEDURE SetSearchReqFlag*;
  357. BEGIN
  358. fromSearchReq := TRUE
  359. END SetSearchReqFlag;
  360. PROCEDURE GetSelection*() : DirEntries;
  361. VAR selection : DirEntries;
  362. l, t, r, b, i, j : LONGINT;
  363. p : ANY;
  364. BEGIN
  365. grid.model.Acquire;
  366. grid.GetSelection(l, t, r, b);
  367. NEW(selection, b- t + 1);
  368. j := 0;
  369. FOR i := t TO b DO
  370. p := grid.model.GetCellData(0, i);
  371. IF (p # NIL) & (p IS DirEntry) THEN
  372. selection[j] := p(DirEntry);
  373. INC(j)
  374. END
  375. END;
  376. grid.model.Release;
  377. RETURN selection
  378. END GetSelection;
  379. PROCEDURE ClickSelected(sender, data : ANY);
  380. VAR curSel : DirEntries;
  381. w : SelectionWrapper;
  382. p : Files.FileName;
  383. BEGIN
  384. IF (data # NIL) & (data IS DirEntry) THEN
  385. NEW(curSel, 1);
  386. curSel[0] := data(DirEntry);
  387. IF Files.Directory IN curSel[0].flags THEN
  388. COPY(curSel[0].path^, p); Strings.Append(p, curSel[0].name^);
  389. MakePathString(p);
  390. StartNewPath(Strings.NewString(p));
  391. ELSE
  392. NEW(w); w.sel := curSel; w.user := NIL;
  393. Open(sender, w)
  394. END
  395. END
  396. END ClickSelected;
  397. PROCEDURE HandleCommands(sender, data : ANY);
  398. VAR
  399. w : SelectionWrapper;
  400. filename : Files.FileName;
  401. command : ARRAY 1024 OF CHAR;
  402. position: SIZE; res: WORD;
  403. msg : ARRAY 256 OF CHAR;
  404. BEGIN
  405. IF (data # NIL) & (data IS SelectionWrapper) THEN
  406. w := data (SelectionWrapper);
  407. IF (w.user # NIL) & (w.user IS StringWrapper) & (w.user(StringWrapper).string # NIL) THEN
  408. IF (w.sel[0].path # NIL) THEN
  409. COPY(w.sel[0].path^, filename);
  410. Strings.Append(filename, w.sel[0].name^);
  411. ELSE
  412. COPY(w.sel[0].name^, filename);
  413. END;
  414. COPY(w.user(StringWrapper).string^, command);
  415. position := Strings.Pos(FilenamePlaceholder, command);
  416. IF (position # -1) THEN
  417. ASSERT(w.sel[0].name^ # FilenamePlaceholder);
  418. REPEAT
  419. Strings.Delete(command, position, Strings.Length(FilenamePlaceholder));
  420. Strings.Insert(filename, command, position);
  421. position := Strings.Pos(FilenamePlaceholder, command);
  422. UNTIL (position = -1);
  423. ELSE
  424. Strings.Append(command, " ");
  425. Strings.Append(command, w.sel[0].name^);
  426. END;
  427. Commands.Call(command, {}, res, msg);
  428. IF (res # Commands.Ok) THEN
  429. KernelLog.String("WMSystemComponents: Execution of command '");
  430. KernelLog.String(command); KernelLog.String("' failed, res: ");
  431. KernelLog.Int(res, 0);
  432. KernelLog.String(" ("); KernelLog.String(msg); KernelLog.String(")");
  433. KernelLog.Ln;
  434. END;
  435. END;
  436. END;
  437. END HandleCommands;
  438. PROCEDURE ContextMenu(sender : ANY; x, y: LONGINT);
  439. VAR wmx, wmy : LONGINT;
  440. curSel : DirEntries;
  441. w : SelectionWrapper;
  442. sw : StringWrapper;
  443. filename, extension : Files.FileName;
  444. config : ARRAY 256 OF CHAR;
  445. ptr : ANY;
  446. element : XML.Element;
  447. enumerator : XMLObjects.Enumerator;
  448. name, value : XML.String;
  449. BEGIN
  450. px := x; py := y;
  451. NEW(popup);
  452. curSel := GetSelection();
  453. NEW(w); w.sel := curSel; w.user := NIL;
  454. IF ~fromSearchReq THEN
  455. (* allow operations on files such as renaming, duplicating, deleting, etc. only in not content-based search lists *)
  456. IF LEN(curSel) = 1 THEN
  457. popup.AddParButton("Open", Open, w);
  458. popup.AddParButton("Rename", Rename, w);
  459. popup.AddParButton("Duplicate", Duplicate, w);
  460. popup.AddParButton("EditText", EditText, w);
  461. END;
  462. popup.AddParButton("Tar", Tar, w);
  463. popup.AddParButton("Delete", Delete, w);
  464. IF (LEN(curSel) = 1) & (curSel[0] # NIL) & (curSel[0].name # NIL) THEN
  465. Files.SplitExtension(curSel[0].name^, filename, extension);
  466. Strings.LowerCase(extension);
  467. config := "Filehandlers.";
  468. Strings.Append(config, extension);
  469. element := Configuration.GetSection(config);
  470. IF (element # NIL) THEN
  471. enumerator := element.GetContents();
  472. WHILE (enumerator.HasMoreElements()) DO
  473. ptr := enumerator.GetNext();
  474. IF (ptr # NIL) & (ptr IS XML.Element) THEN
  475. element := ptr (XML.Element);
  476. name := element.GetAttributeValue("name");
  477. IF (name # NIL) & (name^ # "Open") THEN
  478. value := element.GetAttributeValue("value");
  479. IF (value # NIL) THEN
  480. NEW(sw); sw.string := value;
  481. w.user := sw;
  482. popup.AddParButton(name^, HandleCommands, w);
  483. ELSE
  484. KernelLog.String("WMSystemComponents: No value attribute in section ");
  485. KernelLog.String(config); KernelLog.Ln;
  486. END;
  487. END;
  488. END;
  489. END;
  490. END;
  491. END;
  492. ELSE
  493. IF LEN(curSel) = 1 THEN
  494. (* only allow opening of files in this case *)
  495. popup.AddParButton("Open", Open, w);
  496. END
  497. END;
  498. grid.Acquire; grid.ToWMCoordinates(x, y, wmx, wmy); grid.Release;
  499. popup.Popup(wmx, wmy)
  500. END ContextMenu;
  501. PROCEDURE Rename(sender, data : ANY);
  502. VAR d : DirEntry; rename : WMDialogs.MiniStringInput;
  503. wmx, wmy: LONGINT; res: WORD;
  504. name, op, np : ARRAY FileNameLength (* was 128*) OF CHAR;
  505. BEGIN
  506. IF popup # NIL THEN popup.Close; popup := NIL END;
  507. IF (data # NIL) & (data IS SelectionWrapper) THEN
  508. d := data(SelectionWrapper).sel[0];
  509. IF d # NIL THEN
  510. grid.Acquire; grid.ToWMCoordinates(px, py, wmx, wmy); grid.Release;
  511. NEW(rename);
  512. COPY(d.name^, name);
  513. IF rename.Show(wmx, wmy, name) = WMDialogs.ResOk THEN
  514. IF name # d.name^ THEN
  515. COPY(d.path^, op); Strings.Append(op, d.name^);
  516. COPY(d.path^, np); Strings.Append(np, name);
  517. IF ~FileExists(np) OR
  518. (WMDialogs.Confirmation("Confirm overwriting existing file", np) = WMDialogs.ResYes) THEN
  519. Files.Rename(op, np, res);
  520. IF res # 0 THEN
  521. KernelLog.Int(res, 0); KernelLog.Ln;
  522. WMDialogs.Error("Renaming failed", np);
  523. END;
  524. Refresh(NIL, NIL)
  525. END
  526. END
  527. END
  528. END
  529. END
  530. END Rename;
  531. PROCEDURE Delete(sender, data : ANY);
  532. VAR d : DirEntry;
  533. dr, i : LONGINT; res: WORD;
  534. dp : Files.FileName;
  535. delete, always, never : BOOLEAN;
  536. BEGIN
  537. IF popup # NIL THEN popup.Close; popup := NIL END;
  538. IF (data # NIL) & (data IS SelectionWrapper) THEN
  539. always := FALSE; never := FALSE;
  540. FOR i := 0 TO LEN(data(SelectionWrapper).sel) - 1 DO
  541. d := data(SelectionWrapper).sel[i];
  542. delete := FALSE;
  543. IF d # NIL THEN
  544. COPY(d.path^, dp); Strings.Append(dp, d.name^);
  545. IF ~always & ~never THEN
  546. dr := WMDialogs.Message(WMDialogs.TConfirmation, "Confirm deleting file", dp,
  547. {WMDialogs.ResNo, WMDialogs.ResAbort, WMDialogs.ResYes, WMDialogs.ResAll});
  548. IF dr IN {WMDialogs.ResYes, WMDialogs.ResAll} THEN delete := TRUE END;
  549. IF dr = WMDialogs.ResAll THEN always := TRUE END;
  550. IF dr = WMDialogs.ResAbort THEN never := TRUE END;
  551. END;
  552. IF ~never & (delete OR always) THEN
  553. Files.Delete(dp, res);
  554. IF res # 0 THEN
  555. WMDialogs.Error("Deleting failed", dp)
  556. END;
  557. (* if the dialog was shown then visually update *)
  558. IF delete THEN Refresh(NIL, NIL) END
  559. END
  560. END
  561. END;
  562. (* end of the operation refresh list *)
  563. Refresh(NIL, NIL)
  564. END
  565. END Delete;
  566. PROCEDURE Duplicate(sender, data : ANY);
  567. VAR d : DirEntry;
  568. name : ARRAY FileNameLength (* was 128*) OF CHAR;
  569. res : WORD;
  570. BEGIN
  571. IF popup # NIL THEN popup.Close; popup := NIL END;
  572. IF (data # NIL) & (data IS SelectionWrapper) THEN
  573. d := data(SelectionWrapper).sel[0];
  574. IF d # NIL THEN
  575. COPY(d.path^, name);
  576. Strings.Append(name, d.name^);
  577. Files.Copy(name, res);
  578. IF res = 0 THEN
  579. Strings.Append(name, ".COPY");
  580. Files.Paste(name, res);
  581. WHILE res # 0 DO
  582. IF res = 2908 THEN
  583. IF WMDialogs.QueryString("File already exists. Enter a new Name", name) = WMDialogs.ResOk THEN
  584. Files.Paste(name, res);
  585. ELSE
  586. res := 0;
  587. END;
  588. ELSIF res = 2909 THEN
  589. IF WMDialogs.QueryString("FileName too long. Enter a new Name", name) = WMDialogs.ResOk THEN
  590. Files.Paste(name, res);
  591. ELSE
  592. res := 0;
  593. END;
  594. ELSE
  595. WMDialogs.Error("Error", "Some Error occoured while duplicating");
  596. END;
  597. END;
  598. END;
  599. END;
  600. Refresh(NIL, NIL);
  601. END;
  602. END Duplicate;
  603. PROCEDURE Tar(sender, data : ANY);
  604. VAR
  605. d : DirEntry; i, len : LONGINT;
  606. filename, format, temp : Files.FileName;
  607. buf: ARRAY BufSize OF CHAR;
  608. arc : Archives.Archive;
  609. file : Files.File; reader : Files.Reader;
  610. writer : Streams.Writer;
  611. PROCEDURE GetFormatFromFilename(CONST filename : ARRAY OF CHAR; VAR format : ARRAY OF CHAR);
  612. VAR file : ARRAY FileNameLength (* was 128*) OF CHAR;
  613. BEGIN
  614. IF filename = "" THEN COPY("tar", format);
  615. ELSE
  616. Strings.GetExtension(filename, file, format);
  617. Strings.LowerCase(format);
  618. END
  619. END GetFormatFromFilename;
  620. BEGIN
  621. IF popup # NIL THEN popup.Close; popup := NIL END;
  622. IF (data # NIL) & (data IS SelectionWrapper) THEN
  623. IF (WMDialogs.QueryString("Enter Name of Archive: ", filename) = WMDialogs.ResOk) THEN
  624. GetFormatFromFilename(filename, format);
  625. arc := Archives.Old(filename, format);
  626. IF arc = NIL THEN
  627. arc := Archives.New(filename, format)
  628. END;
  629. KernelLog.String("File Manager: building "); KernelLog.String(filename);
  630. FOR i := 0 TO LEN(data(SelectionWrapper).sel) - 1 DO
  631. d := data(SelectionWrapper).sel[i];
  632. COPY(d.path^, temp); Strings.Append(temp, d.name^);
  633. file := Files.Old(temp);
  634. IF file # NIL THEN
  635. Files.OpenReader(reader, file, 0);
  636. arc.Acquire;
  637. Streams.OpenWriter(writer, arc.OpenSender(d.name^));
  638. REPEAT
  639. reader.Bytes(buf, 0, LEN(buf), len); writer.Bytes(buf, 0, len);
  640. UNTIL reader.res # 0;
  641. IF writer # NIL THEN writer.Update END;
  642. arc.Release;
  643. END;
  644. END;
  645. KernelLog.String(" - done!"); KernelLog.Ln;
  646. (* end of the operation refresh list *)
  647. Refresh(NIL, NIL)
  648. END
  649. END
  650. END Tar;
  651. PROCEDURE Open(sender, data : ANY);
  652. VAR d : DirEntry; filename : Files.FileName;
  653. BEGIN
  654. IF popup # NIL THEN popup.Close; popup := NIL END;
  655. IF (data # NIL) & (data IS SelectionWrapper) THEN
  656. d := data(SelectionWrapper).sel[0];
  657. IF d # NIL THEN
  658. COPY(d.path^, filename);
  659. Strings.Append(filename, d.name^);
  660. FileHandlers.OpenFile(filename, NIL, NIL)
  661. END
  662. END
  663. END Open;
  664. PROCEDURE EditText(sender, data : ANY);
  665. VAR d : DirEntry; filename : Files.FileName; window : Notepad.Window; format : ARRAY 32 OF CHAR;
  666. BEGIN
  667. IF popup # NIL THEN popup.Close; popup := NIL END;
  668. IF (data # NIL) & (data IS SelectionWrapper) THEN
  669. d := data(SelectionWrapper).sel[0];
  670. IF d # NIL THEN
  671. COPY(d.path^, filename);
  672. Strings.Append(filename, d.name^);
  673. format := "AUTO";
  674. NEW(window, NIL);
  675. window.editor.Load(filename, format);
  676. END
  677. END
  678. END EditText;
  679. (*
  680. PROCEDURE Open*(sender, data : ANY);
  681. VAR options : Options.Options; window : Window; filename : Files.FileName; format : ARRAY 32 OF CHAR;
  682. BEGIN
  683. NEW(options);
  684. options.Add("f", "format", Options.String);
  685. IF options.Parse(context.arg, context.error) THEN
  686. IF ~options.GetString("format", format) THEN format := "AUTO"; END;
  687. NEW(window, NIL);
  688. IF context.arg.GetString(filename) THEN
  689. window.editor.Load(filename, format);
  690. END;
  691. END;
  692. END Open;
  693. *)
  694. PROCEDURE MyDragDropped(x, y : LONGINT; dragInfo : WM.DragInfo; VAR handled : BOOLEAN);
  695. BEGIN
  696. handled := TRUE;
  697. DragDropped(x, y, dragInfo)
  698. END MyDragDropped;
  699. PROCEDURE DragDropped*(x, y : LONGINT; dragInfo : WM.DragInfo);
  700. VAR dropTarget : FilesDropTarget;
  701. BEGIN
  702. NEW(dropTarget, path, Refresh);
  703. dragInfo.data := dropTarget;
  704. ConfirmDrag(TRUE, dragInfo)
  705. END DragDropped;
  706. PROCEDURE MyStartDrag(sender, data : ANY);
  707. VAR img : WMGraphics.Image;
  708. c : WMGraphics.BufferCanvas;
  709. top, i : LONGINT;
  710. BEGIN
  711. selection := GetSelection();
  712. (* render to bitmap *)
  713. NEW(img); Raster.Create(img, 100, 200, Raster.BGRA8888);
  714. NEW(c, img);
  715. c.SetColor(LONGINT(0FFFF00FFH));
  716. top := 0;
  717. FOR i := 0 TO LEN(selection) - 1 DO
  718. IF selection[i] # NIL THEN
  719. c.Fill(WMRectangles.MakeRect(0, top, 100, top + 25), 0FF80H, WMGraphics.ModeCopy);
  720. c.DrawString(3, top + 20, selection[i].name^);
  721. INC(top, 25)
  722. END
  723. END;
  724. IF grid.StartDrag(NIL, img, 0,0,DragArrived, NIL) THEN
  725. IF TraceDragging IN Trace THEN KernelLog.String("WMSystemComponents: DraggingStarted"); END;
  726. ELSE
  727. IF TraceDragging IN Trace THEN KernelLog.String("WMSystemComponents: Drag could not be started"); END;
  728. END;
  729. END MyStartDrag;
  730. PROCEDURE CopyFile(target : WMDropTarget.DropFiles; CONST local, remote : ARRAY OF CHAR; VAR res : WORD);
  731. VAR w : Streams.Writer;
  732. f : Files.File;
  733. r : Files.Reader;
  734. buf: ARRAY BufSize OF CHAR; len: LONGINT;
  735. BEGIN
  736. res := -1;
  737. f := Files.Old(local);
  738. IF f # NIL THEN
  739. Files.OpenReader(r, f, 0);
  740. target.OpenPut(remote, w, res);
  741. IF res = 0 THEN
  742. REPEAT
  743. r.Bytes(buf, 0, BufSize, len); w.Bytes(buf, 0, len);
  744. UNTIL r.res # 0;
  745. target.ClosePut(res)
  746. END;
  747. END
  748. END CopyFile;
  749. PROCEDURE Refresh(sender, data : ANY);
  750. BEGIN
  751. IF ~IsCallFromSequencer() THEN sequencer.ScheduleEvent(SELF.Refresh, sender, data)
  752. ELSE
  753. ScanPath; PrepareList;
  754. grid.Acquire;
  755. grid.SetSelection(-1, -1, -1, -1);
  756. selection := NIL;
  757. grid.Release;
  758. END
  759. END Refresh;
  760. PROCEDURE Resized*;
  761. BEGIN
  762. grid.model.Acquire;
  763. IF fullView THEN
  764. colWidths[0] := (bounds.GetWidth() DIV 3)*2 - 20;
  765. colWidths[1] := bounds.GetWidth() DIV 6;
  766. colWidths[2] := bounds.GetWidth() DIV 6;
  767. ELSE
  768. colWidths[0] := bounds.GetWidth();
  769. END;
  770. grid.SetColSpacings(colWidths);
  771. grid.model.Release;
  772. Resized^;
  773. END Resized;
  774. PROCEDURE DragArrived(sender, data : ANY);
  775. VAR di : WM.DragInfo;
  776. dt : WMDropTarget.DropTarget;
  777. itf : WMDropTarget.DropInterface;
  778. i : LONGINT; res: WORD;
  779. sel : DirEntries;
  780. url : ARRAY 1024 OF CHAR;
  781. text : Texts.Text;
  782. textPos : Texts.TextPosition;
  783. nl: ARRAY 2 OF CHAR;
  784. BEGIN
  785. sel := selection;
  786. IF sel = NIL THEN RETURN END;
  787. IF (data # NIL) & (data IS WM.DragInfo) THEN
  788. di := data(WM.DragInfo);
  789. IF (di.data # NIL) & (di.data IS WMDropTarget.DropTarget) THEN
  790. dt := di.data(WMDropTarget.DropTarget)
  791. ELSE RETURN
  792. END
  793. ELSE RETURN
  794. END;
  795. itf := dt.GetInterface(WMDropTarget.TypeFiles);
  796. IF itf # NIL THEN
  797. FOR i := 0 TO LEN(selection) - 1 DO
  798. IF selection[i] # NIL THEN
  799. COPY(selection[i].path^, url);
  800. Strings.Append(url, selection[i].name^);
  801. CopyFile(itf(WMDropTarget.DropFiles), url, selection[i].name^, res);
  802. END
  803. END;
  804. RETURN
  805. END;
  806. itf := dt.GetInterface(WMDropTarget.TypeURL);
  807. IF itf # NIL THEN
  808. FOR i := 0 TO LEN(selection) - 1 DO
  809. IF selection[i] # NIL THEN
  810. COPY(selection[i].path^, url);
  811. Strings.Append(url, selection[i].name^);
  812. itf(WMDropTarget.DropURLs).URL(url, res)
  813. END
  814. END;
  815. RETURN
  816. END;
  817. itf := dt.GetInterface(WMDropTarget.TypeText);
  818. IF itf # NIL THEN
  819. text := itf(WMDropTarget.DropText).text;
  820. textPos := itf(WMDropTarget.DropText).pos;
  821. IF (text # NIL) & (textPos # NIL) THEN
  822. text.AcquireWrite;
  823. FOR i := 0 TO LEN(selection) - 1 DO
  824. IF selection[i] # NIL THEN
  825. COPY(selection[i].path^, url);
  826. Strings.Append(url, selection[i].name^);
  827. nl[0] := CHR(Texts.NewLineChar);
  828. nl[1] := 0X;
  829. Strings.Append(url, nl);
  830. TextUtilities.StrToText(text, textPos.GetPosition(), url)
  831. END
  832. END;
  833. text.ReleaseWrite
  834. END;
  835. RETURN
  836. END;
  837. END DragArrived;
  838. PROCEDURE ResetGrid*;
  839. BEGIN
  840. nofRows := 1;
  841. grid.model.Acquire;
  842. grid.model.SetNofRows(nofRows);
  843. grid.SetTopPosition(0, 0, TRUE);
  844. grid.SetSelection(0, 0, 0, 0);
  845. grid.model.Release
  846. END ResetGrid;
  847. PROCEDURE DisplayGrid*(CONST data : ARRAY OF DirEntry; noEl : LONGINT);
  848. VAR i, gridindex : LONGINT;
  849. d : DirEntry;
  850. t : ARRAY FileNameLength (* was 128*) OF CHAR;
  851. BEGIN
  852. grid.model.Acquire;
  853. grid.model.SetNofRows(nofRows + noEl);
  854. FOR i := 0 TO noEl -1 DO
  855. d := data[i];
  856. gridindex := nofRows + i;
  857. grid.model.SetCellText(0, gridindex , d.name);
  858. grid.model.SetCellData(0, gridindex, d);
  859. IF fullView THEN
  860. Strings.IntToStr(d.size, t);
  861. grid.model.SetCellText(1, gridindex, Strings.NewString(t));
  862. Strings.FormatDateTime(" yyyy mmm dd hh:nn ", Dates.OberonToDateTime(d.date, d.time), t);
  863. grid.model.SetCellText(2, gridindex, Strings.NewString(t));
  864. END;
  865. IF Files.Directory IN d.flags THEN
  866. grid.model.SetCellImage(0, gridindex, WMGraphics.LoadImage("icons.tar://Folder.png", TRUE))
  867. ELSE
  868. grid.model.SetCellImage(0, gridindex, NIL)
  869. END
  870. END;
  871. grid.model.Release;
  872. nofRows := nofRows + noEl;
  873. END DisplayGrid;
  874. PROCEDURE ToggleProps*;
  875. BEGIN
  876. grid.model.Acquire;
  877. IF fullView THEN
  878. fullView := FALSE;
  879. grid.model.SetNofCols(1);
  880. colWidths[0] := bounds.GetWidth();
  881. ELSE
  882. fullView := TRUE;
  883. grid.model.SetNofCols(3);
  884. colWidths[0] := (bounds.GetWidth() DIV 3)*2 - 20;
  885. colWidths[1] := bounds.GetWidth() DIV 6;
  886. colWidths[2] := bounds.GetWidth() DIV 6;
  887. grid.model.SetCellText(1, 0, Strings.NewString("Size"));
  888. grid.model.SetCellText(2, 0, Strings.NewString("Modified"));
  889. END;
  890. grid.SetColSpacings(colWidths);
  891. grid.model.Release;
  892. Refresh(NIL, NIL);
  893. END ToggleProps;
  894. PROCEDURE FillGridRow(rowNo : LONGINT; dir : DirEntry);
  895. VAR t : ARRAY FileNameLength (* was 128*) OF CHAR;
  896. BEGIN
  897. grid.model.SetCellText(0, rowNo, dir.name);
  898. grid.model.SetCellData(0, rowNo, dir);
  899. IF fullView THEN
  900. Strings.IntToStr(dir.size, t);
  901. grid.model.SetCellText(1, rowNo, Strings.NewString(t));
  902. Strings.FormatDateTime(" yyyy mmm dd hh:nn ", Dates.OberonToDateTime(dir.date, dir.time), t);
  903. grid.model.SetCellText(2, rowNo, Strings.NewString(t));
  904. END;
  905. IF Files.Directory IN dir.flags THEN
  906. grid.model.SetCellImage(0, rowNo, WMGraphics.LoadImage("icons.tar://Folder.png", TRUE))
  907. ELSE
  908. grid.model.SetCellImage(0, rowNo, NIL)
  909. END;
  910. END FillGridRow;
  911. PROCEDURE PrepareList;
  912. VAR i, vis : LONGINT; mask : ARRAY FileNameLength (* was 128*) OF CHAR; s : Strings.String;
  913. BEGIN
  914. IF dir = NIL THEN RETURN END;
  915. s := SELF.filter;
  916. mask := "";
  917. IF s # NIL THEN COPY(s^, mask) END;
  918. IF mask = "" THEN
  919. FOR i := 0 TO LEN(dir) - 1 DO dir[i].visible := TRUE END;
  920. vis := LEN(dir)
  921. ELSE
  922. IF prefixSearch.Get() & ( mask[Strings.Length(mask)] # "*") THEN Strings.Append(mask, "*") END;
  923. vis := 0;
  924. FOR i := 0 TO LEN(dir) - 1 DO
  925. IF Strings.Match(mask, dir[i].name^) THEN
  926. dir[i].visible := TRUE;
  927. INC(vis)
  928. ELSE dir[i].visible := FALSE
  929. END
  930. END;
  931. END;
  932. grid.model.Acquire;
  933. grid.model.SetNofRows(vis + 1);
  934. vis := 0;
  935. FOR i := 0 TO LEN(dir) - 1 DO
  936. IF dir[i].visible THEN
  937. FillGridRow(vis + 1, dir[i]);
  938. INC(vis)
  939. END
  940. END;
  941. grid.SetTopPosition(0, 0, TRUE);
  942. grid.model.Release;
  943. END PrepareList;
  944. PROCEDURE ScanPath;
  945. VAR s, pathS : Strings.String;
  946. i, l : LONGINT;
  947. name, path, filename, mask : Files.FileName; flags : SET; time, date, size : LONGINT;
  948. sorted : BOOLEAN;
  949. BEGIN
  950. s := SELF.path;
  951. IF s = NIL THEN RETURN END;
  952. COPY(s^, mask);
  953. IF Strings.Length(mask) > 1 THEN
  954. IF mask[Strings.Length(mask) - 1] = ':' THEN Strings.Append(mask, '*')
  955. ELSE Strings.Append(mask, '/*')
  956. END
  957. ELSE mask := '*'
  958. END;
  959. IF fullView THEN enumerator.Open(mask, {Files.EnumSize, Files.EnumTime}); ELSE enumerator.Open(mask, {}); END;
  960. nfiles := enumerator.size;
  961. i := 0;
  962. sorted := TRUE;
  963. NEW(dir, enumerator.size);
  964. WHILE enumerator.HasMoreEntries() DO
  965. IF enumerator.GetEntry(name, flags, time, date, size) THEN
  966. Files.SplitPath(name, path, filename);
  967. l := Strings.Length(path);
  968. path[l] := Files.PathDelimiter; path[l + 1] := 0X;
  969. IF (pathS = NIL) OR (pathS^ # path) THEN pathS := Strings.NewString(path) END;
  970. NEW(dir[i], Strings.NewString(filename), pathS, time, date, size, flags);
  971. END;
  972. INC(i)
  973. END;
  974. enumerator.Close;
  975. IF fullView THEN SortDirDate ELSE SortDir END;
  976. END ScanPath;
  977. PROCEDURE StartNewPath*(path : Strings.String);
  978. BEGIN
  979. SELF.path := path;
  980. ScanPath;
  981. PrepareList
  982. END StartNewPath;
  983. PROCEDURE StartNewFilter*(filter : Strings.String);
  984. BEGIN
  985. SELF.filter := filter;
  986. PrepareList
  987. END StartNewFilter;
  988. PROCEDURE GetNofFiles*() : LONGINT;
  989. BEGIN
  990. RETURN nfiles
  991. END GetNofFiles;
  992. (* binary insertion algorithm from "Algorithms and Data Structures" by N. Wirth *)
  993. PROCEDURE SortDir;
  994. VAR
  995. i, j, m, L, R : LONGINT;
  996. x : DirEntry;
  997. dirName, xName: Strings.String;
  998. dirFlag, xFlag: SHORTINT;
  999. BEGIN
  1000. FOR i := 1 TO LEN(dir) - 1 DO
  1001. x := dir[i]; L := 0; R := i; xName := Strings.NewString(x.name^); Strings.UpperCase(xName^);
  1002. IF Files.Directory IN x.flags THEN xFlag := 0 ELSE xFlag := 1 END;
  1003. WHILE L < R DO
  1004. m := (L + R) DIV 2; dirName := Strings.NewString(dir[m].name^); Strings.UpperCase(dirName^);
  1005. IF Files.Directory IN dir[m].flags THEN dirFlag := 0 ELSE dirFlag := 1 END;
  1006. IF (dirFlag < xFlag) OR ((dirFlag=xFlag) & (UTF8Strings.Compare(dirName^, xName^) = UTF8Strings.CmpGreater)) THEN
  1007. R := m
  1008. ELSE
  1009. L := m + 1
  1010. END
  1011. END;
  1012. FOR j := i TO R + 1 BY -1 DO dir[j] := dir[j - 1] END;
  1013. dir[R] := x
  1014. END
  1015. END SortDir;
  1016. (* binary insertion algorithm from "Algorithms and Data Structures" by N. Wirth *)
  1017. PROCEDURE SortDirDate;
  1018. VAR
  1019. i, j, m, L, R : LONGINT;
  1020. x : DirEntry;
  1021. dirTime,dirDate:LONGINT;
  1022. dirFlag, xFlag: SHORTINT;
  1023. BEGIN
  1024. FOR i := 1 TO LEN(dir) - 1 DO
  1025. x := dir[i]; L := 0; R := i;
  1026. IF Files.Directory IN x.flags THEN xFlag := 0 ELSE xFlag := 1 END;
  1027. WHILE L < R DO
  1028. m := (L + R) DIV 2;
  1029. dirTime := dir[m].time; dirDate:= dir[m].date;
  1030. IF Files.Directory IN dir[m].flags THEN dirFlag := 0 ELSE dirFlag := 1 END;
  1031. IF (dirFlag < xFlag) OR ((dirFlag=xFlag) & ((dirDate< x.date) OR ((dirDate=x.date)&(dirTime<x.time)))) THEN
  1032. R := m
  1033. ELSE
  1034. L := m + 1
  1035. END
  1036. END;
  1037. FOR j := i TO R + 1 BY -1 DO dir[j] := dir[j - 1] END;
  1038. dir[R] := x
  1039. END
  1040. END SortDirDate;
  1041. END FileList;
  1042. VAR
  1043. DirTreePathProt : WMProperties.StringProperty;
  1044. FileListPrefixSearchProt : WMProperties.BooleanProperty;
  1045. GSonPathChanged, GSonPathChangedInfo : Strings.String;
  1046. GSDirectoryTree, GSFileList : Strings.String;
  1047. PROCEDURE GenFileList*() : XML.Element;
  1048. VAR f : FileList;
  1049. BEGIN
  1050. NEW(f); RETURN f;
  1051. END GenFileList;
  1052. PROCEDURE GenDirectoryTree*() : XML.Element;
  1053. VAR t : DirectoryTree;
  1054. BEGIN
  1055. NEW(t); RETURN t;
  1056. END GenDirectoryTree;
  1057. PROCEDURE InitStrings;
  1058. BEGIN
  1059. GSonPathChanged := Strings.NewString("onPathChanged");
  1060. GSonPathChangedInfo := Strings.NewString("called when the path is changed");
  1061. GSDirectoryTree := Strings.NewString("DirectoryTree");
  1062. GSFileList := Strings.NewString("FileList");
  1063. END InitStrings;
  1064. PROCEDURE InitPrototypes;
  1065. BEGIN
  1066. NEW(DirTreePathProt, NIL, Strings.NewString("CurrentPath"), Strings.NewString("contains the selected path"));
  1067. NEW(FileListPrefixSearchProt, NIL, Strings.NewString("PrefixSearch"), Strings.NewString("match prefix only"));
  1068. FileListPrefixSearchProt.Set(TRUE);
  1069. END InitPrototypes;
  1070. PROCEDURE FileExists*(CONST name : ARRAY OF CHAR) : BOOLEAN;
  1071. BEGIN
  1072. RETURN Files.Old(name) # NIL
  1073. END FileExists;
  1074. PROCEDURE MakePathString*(VAR s : ARRAY OF CHAR);
  1075. VAR l : LONGINT;
  1076. BEGIN
  1077. l := Strings.Length(s);
  1078. IF (l > 1) & (s[l - 1] # ":") & (s[l - 1] # "/") THEN Strings.Append(s, "/") END;
  1079. END MakePathString;
  1080. BEGIN
  1081. InitStrings;
  1082. InitPrototypes;
  1083. END WMSystemComponents.
  1084. System.Free WMSystemComponents ~