WMArchives.Mod 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186
  1. MODULE WMArchives; (** AUTHOR "FN,PL"; PURPOSE "GUI for Archives"; *)
  2. IMPORT
  3. Commands, Streams, Modules, Files, FileHandlers, Archives, Strings, KernelLog, Texts, TextUtilities, Raster,
  4. WMDropTarget, WMComponents, WMStandardComponents, WMTrees, WMPopups,
  5. WMGraphics, WMDialogs, WMRectangles,
  6. WMEditors, WMRestorable, WMMessages, WMGrids, WMStringGrids, WMProperties, XML,
  7. WM := WMWindowManager;
  8. CONST
  9. WindowWidth = 600; WindowHeight = 400;
  10. NameSize = 128;
  11. BufSize = 16*1024;
  12. TreePreviewSize = 16;
  13. TYPE
  14. KillerMsg = OBJECT
  15. END KillerMsg;
  16. EntryInfo = Archives.EntryInfo;
  17. ArchiveDropInterface* = OBJECT(WMDropTarget.DropFiles)
  18. VAR
  19. out : Streams.Writer;
  20. at : ArchiveTree;
  21. parent : WMTrees.TreeNode;
  22. entryName, caption : Strings.String;
  23. PROCEDURE &New*(t : ArchiveTree; n : WMTrees.TreeNode);
  24. BEGIN
  25. at := t; parent := n
  26. END New;
  27. PROCEDURE OpenPut*(CONST remoteName : ARRAY OF CHAR; VAR outw : Streams.Writer; VAR res : WORD);
  28. BEGIN
  29. res := -1;
  30. caption := Strings.NewString(remoteName);
  31. entryName := at.GetPath(parent);
  32. Strings.Append(entryName^, remoteName);
  33. (* check if exists *)
  34. at.archive.Acquire;
  35. IF (at.archive.GetEntryInfo(entryName^) = NIL) OR
  36. (WMDialogs.Confirmation("Confirm overwriting", remoteName) = WMDialogs.ResYes) THEN
  37. Streams.OpenWriter(out, at.archive.OpenSender(entryName^));
  38. res := 0
  39. END;
  40. at.archive.Release;
  41. outw := out;
  42. END OpenPut;
  43. PROCEDURE ClosePut*(VAR res : WORD);
  44. VAR ei : EntryInfo;
  45. BEGIN
  46. IF out # NIL THEN out.Update END;
  47. at.archive.Acquire; ei := at.archive.GetEntryInfo(entryName^); at.archive.Release;
  48. at.AddChildNode(parent, caption, ei, TRUE);
  49. END ClosePut;
  50. END ArchiveDropInterface;
  51. ArchiveDropTarget* = OBJECT(WMDropTarget.DropTarget)
  52. VAR
  53. tree : ArchiveTree;
  54. node : WMTrees.TreeNode;
  55. PROCEDURE &New*(t : ArchiveTree; n : WMTrees.TreeNode);
  56. BEGIN
  57. tree := t; node := n
  58. END New;
  59. PROCEDURE GetInterface*(type : LONGINT) : WMDropTarget.DropInterface;
  60. VAR di : ArchiveDropInterface;
  61. BEGIN
  62. IF type = WMDropTarget.TypeFiles THEN
  63. NEW(di, tree, node);
  64. RETURN di
  65. ELSE RETURN NIL
  66. END
  67. END GetInterface;
  68. END ArchiveDropTarget;
  69. ArchiveTree* = OBJECT(WMStandardComponents.Panel)
  70. VAR
  71. tree -: WMTrees.Tree;
  72. treeView -: WMTrees.TreeView;
  73. archive : Archives.Archive;
  74. archiveName : ARRAY NameSize OF CHAR;
  75. popup : WMPopups.Popup;
  76. label : WMStandardComponents.Label;
  77. toolbar : WMStandardComponents.Panel;
  78. refreshBtn : WMStandardComponents.Button;
  79. px, py : LONGINT;
  80. draggedString : Strings.String;
  81. showFiles : WMProperties.BooleanProperty;
  82. showImagePreview : WMProperties.BooleanProperty;
  83. NodeChanged* : PROCEDURE {DELEGATE} (sender, data : ANY);
  84. PROCEDURE & Init*;
  85. BEGIN
  86. Init^;
  87. (* title *)
  88. NEW(label); label.alignment.Set(WMComponents.AlignTop);
  89. label.fillColor.Set(0CCCCCCFFH);
  90. label.SetCaption("Resource Index"); label.bounds.SetHeight(20);
  91. SELF.AddContent(label);
  92. (* toolbar *)
  93. NEW(toolbar); toolbar.alignment.Set(WMComponents.AlignTop);
  94. toolbar.bounds.SetHeight(20);
  95. SELF.AddContent(toolbar);
  96. (* refresh button *)
  97. NEW(refreshBtn); refreshBtn.alignment.Set(WMComponents.AlignLeft);
  98. refreshBtn.caption.SetAOC("Refresh");
  99. refreshBtn.onClick.Add(RefreshHandler);
  100. toolbar.AddContent(refreshBtn);
  101. (* treeView *)
  102. NEW(treeView); treeView.alignment.Set(WMComponents.AlignClient);
  103. SELF.AddContent(treeView);
  104. treeView.SetExtContextMenuHandler(ContextMenu);
  105. treeView.SetDrawNodeProc(DrawTreeNode);
  106. treeView.SetMeasureNodeProc(MeasureTreeNode);
  107. treeView.SetExtDragDroppedHandler(MyDragDropped);
  108. treeView.onStartDrag.Add(MyStartDrag);
  109. tree := treeView.GetTree();
  110. NEW(showFiles, ProtShowFiles, NIL, NIL); properties.Add(showFiles);
  111. NEW(showImagePreview, ProtShowImgPrev, NIL, NIL); properties.Add(showImagePreview);
  112. SetNameAsString(StrArchiveTree)
  113. END Init;
  114. (** set a new model. the view is re-initialized *)
  115. PROCEDURE SetArchive*(archive : Archives.Archive);
  116. VAR i : LONGINT;
  117. node : WMTrees.TreeNode;
  118. name : Strings.String;
  119. archiveEntries : Archives.Index;
  120. BEGIN
  121. ASSERT(archive # NIL);
  122. SELF.archive := archive;
  123. NEW(node);
  124. tree.Acquire;
  125. tree.SetRoot(node);
  126. tree.InclNodeState(node, WMTrees.NodeAlwaysExpanded);
  127. RemovePartitionLabel(archive.name, archiveName);
  128. tree.SetNodeCaption(node, Strings.NewString(archiveName));
  129. tree.Release;
  130. treeView.SetFirstLine(0, TRUE);
  131. archive.Acquire; archiveEntries := archive.GetIndex(); archive.Release;
  132. FOR i := 0 TO LEN(archiveEntries^)-1 DO
  133. name := archiveEntries[i].GetName();
  134. InsertTreeNode(node, name, archiveEntries[i])
  135. END;
  136. END SetArchive;
  137. (* ----- handlers ------------------------------------------------- *)
  138. (* called when a drag-operation has been started *)
  139. PROCEDURE MyStartDrag(sender, data : ANY);
  140. VAR img : WMGraphics.Image;
  141. c : WMGraphics.BufferCanvas;
  142. w : LONGINT;
  143. a : ANY;
  144. s : Strings.String;
  145. BEGIN
  146. tree.Acquire; a := tree.GetNodeData(treeView.draggedNode); tree.Release;
  147. IF a # NIL THEN
  148. (* render to bitmap *)
  149. s := a(EntryInfo).GetName();
  150. NEW(draggedString, LEN(s^)+64);
  151. AppendToArchiveName(s^, draggedString^);
  152. w := Strings.Length(draggedString^) * 7;
  153. IF w > 400 THEN w := 400 END;
  154. NEW(img); Raster.Create(img, w, 25, Raster.BGRA8888);
  155. NEW(c, img); c.SetColor(LONGINT(0FFFF00FFH));
  156. c.Fill(WMRectangles.MakeRect(0, 0, w, 25), 0FF80H, WMGraphics.ModeCopy);
  157. c.DrawString(3, 20, draggedString^);
  158. IF treeView.StartDrag(a, img, 0,0, DragArrived, NIL) THEN KernelLog.String("DraggingStarted"); KernelLog.Ln
  159. ELSE KernelLog.String("Drag could not be started"); KernelLog.Ln
  160. END
  161. END;
  162. END MyStartDrag;
  163. (* called when an object dragged from this treeView has been dropped anywhere *)
  164. PROCEDURE DragArrived(sender, data : ANY);
  165. VAR di : WM.DragInfo;
  166. dt : WMDropTarget.DropTarget;
  167. itf : WMDropTarget.DropInterface;
  168. res : WORD;
  169. text : Texts.Text;
  170. textPos : Texts.TextPosition;
  171. caption, entryName : Strings.String;
  172. a : ANY;
  173. rec : Streams.Receiver;
  174. BEGIN
  175. IF (data # NIL) & (data IS WM.DragInfo) THEN
  176. di := data(WM.DragInfo);
  177. IF (di.data # NIL) & (di.data IS WMDropTarget.DropTarget) THEN
  178. dt := di.data(WMDropTarget.DropTarget)
  179. ELSE RETURN
  180. END
  181. ELSE RETURN
  182. END;
  183. (* drop text *)
  184. itf := dt.GetInterface(WMDropTarget.TypeText);
  185. IF itf # NIL THEN
  186. text := itf(WMDropTarget.DropText).text;
  187. textPos := itf(WMDropTarget.DropText).pos;
  188. IF (text # NIL) & (textPos # NIL) THEN
  189. text.AcquireWrite;
  190. TextUtilities.StrToText(text, textPos.GetPosition(), draggedString^);
  191. text.ReleaseWrite;
  192. draggedString := NIL
  193. END;
  194. RETURN
  195. END;
  196. (* drop file *)
  197. itf := dt.GetInterface(WMDropTarget.TypeFiles);
  198. IF itf # NIL THEN
  199. tree.Acquire;
  200. caption := tree.GetNodeCaption(treeView.draggedNode);
  201. a := tree.GetNodeData(treeView.draggedNode);
  202. IF a = NIL THEN RETURN END;
  203. entryName := a(EntryInfo).GetName();
  204. tree.Release;
  205. archive.Acquire;
  206. rec := archive.OpenReceiver(entryName^);
  207. CopyFile(rec, itf(WMDropTarget.DropFiles), caption^, res);
  208. archive.Release;
  209. RETURN
  210. END;
  211. END DragArrived;
  212. (* refresh archive index *)
  213. PROCEDURE RefreshHandler(sender, data: ANY);
  214. BEGIN
  215. SetArchive(archive)
  216. END RefreshHandler;
  217. (* called when an object has been dropped on this treeView *)
  218. PROCEDURE MyDragDropped(x, y : LONGINT; dragInfo : WM.DragInfo; VAR handled : BOOLEAN);
  219. BEGIN
  220. handled := TRUE;
  221. DragDropped(x, y, dragInfo);
  222. IF NodeChanged # NIL THEN NodeChanged(SELF, dragInfo) END
  223. END MyDragDropped;
  224. (* called by MyDraggedDropped *)
  225. PROCEDURE DragDropped*(x, y : LONGINT; dragInfo : WM.DragInfo);
  226. VAR dropTarget : ArchiveDropTarget;
  227. parent : WMTrees.TreeNode;
  228. accept : BOOLEAN;
  229. data : ANY;
  230. BEGIN
  231. tree.Acquire;
  232. parent := treeView.GetNodeAtPos(x, y);
  233. data := tree.GetNodeData(parent);
  234. tree.Release;
  235. IF (parent = NIL) OR (data # NIL) THEN
  236. accept := FALSE
  237. ELSE
  238. accept := TRUE;
  239. NEW(dropTarget, SELF, parent);
  240. dragInfo.data := dropTarget;
  241. END;
  242. ConfirmDrag(accept, dragInfo)
  243. END DragDropped;
  244. (* pop up context-menu *)
  245. PROCEDURE ContextMenu(sender : ANY; x, y: LONGINT);
  246. VAR wmx, wmy : LONGINT;
  247. node : WMTrees.TreeNode;
  248. data : ANY;
  249. BEGIN
  250. node := treeView.GetNodeAtPos(x, y);
  251. IF node # NIL THEN
  252. px := x; py := y;
  253. NEW(popup);
  254. tree.Acquire; data := tree.GetNodeData(node); tree.Release;
  255. IF data = NIL THEN (* directory *)
  256. popup.AddParButton("Create Folder", CreateFolder, node);
  257. ELSE (* leaf-node *)
  258. popup.AddParButton("Delete", DeleteEntry, node);
  259. popup.AddParButton("Rename", RenameEntry, node);
  260. END;
  261. ToWMCoordinates(x, y, wmx, wmy);
  262. popup.Popup(wmx, wmy+40)
  263. END
  264. END ContextMenu;
  265. PROCEDURE CreateFolder(sender, data : ANY);
  266. VAR node : WMTrees.TreeNode;
  267. wmx, wmy : LONGINT;
  268. name : ARRAY 128 OF CHAR;
  269. input : WMDialogs.MiniStringInput;
  270. BEGIN
  271. tree.Acquire;
  272. ToWMCoordinates(px, py, wmx, wmy);
  273. NEW(input);
  274. IF input.Show(wmx, wmy, name) = WMDialogs.ResOk THEN
  275. IF name # "" THEN
  276. NEW(node);
  277. tree.InclNodeState(data(WMTrees.TreeNode), WMTrees.NodeExpanded);
  278. tree.AddChildNode(data(WMTrees.TreeNode), node);
  279. tree.SetNodeCaption(node, Strings.NewString(name));
  280. END
  281. END;
  282. tree.Release;
  283. END CreateFolder;
  284. PROCEDURE DeleteEntry(sender, data : ANY);
  285. VAR node : WMTrees.TreeNode;
  286. nodeData : ANY;
  287. name : Strings.String;
  288. BEGIN
  289. tree.Acquire;
  290. node := data(WMTrees.TreeNode);
  291. nodeData := tree.GetNodeData(data(WMTrees.TreeNode));
  292. name := nodeData(EntryInfo).GetName();
  293. KernelLog.String("Delete entry "); KernelLog.String(name^); KernelLog.Ln;
  294. archive.Acquire; archive.RemoveEntry(name^); archive.Release;
  295. tree.RemoveNode(node);
  296. tree.Release;
  297. END DeleteEntry;
  298. PROCEDURE RenameEntry(sender, data : ANY);
  299. VAR rename : WMDialogs.MiniStringInput;
  300. wmx, wmy : LONGINT;
  301. name, caption : ARRAY 128 OF CHAR;
  302. entryInfo : ANY;
  303. s : Strings.String;
  304. BEGIN
  305. IF popup # NIL THEN popup.Close; popup := NIL END;
  306. NEW(rename);
  307. tree.Acquire;
  308. entryInfo := tree.GetNodeData(data(WMTrees.TreeNode));
  309. s := entryInfo(EntryInfo).GetName();
  310. COPY(s^, name);
  311. ToWMCoordinates(px, py, wmx, wmy);
  312. IF rename.Show(wmx, wmy+40, name) = WMDialogs.ResOk THEN
  313. IF s^ # name THEN
  314. archive.Acquire; entryInfo := archive.RenameEntry(s^, name); archive.Release;
  315. IF entryInfo # NIL THEN
  316. tree.SetNodeData(data(WMTrees.TreeNode), entryInfo);
  317. RemovePath(name, caption);
  318. tree.SetNodeCaption(data(WMTrees.TreeNode), Strings.NewString(caption))
  319. END
  320. END
  321. END;
  322. tree.Release
  323. END RenameEntry;
  324. (* ----- internal functions ------------------------------------------*)
  325. (* concatenate the captions of all nodes from NODE to the tree's root separated by '/' *)
  326. PROCEDURE GetPath(node : WMTrees.TreeNode) : Strings.String;
  327. VAR result : Strings.String;
  328. (* recursive method *)
  329. PROCEDURE GetPathRecursive(node : WMTrees.TreeNode) : Strings.String;
  330. VAR parent : WMTrees.TreeNode;
  331. name, path : Strings.String;
  332. BEGIN
  333. IF node = tree.GetRoot() THEN NEW(path, 128); path[0] := 0X; RETURN path END;
  334. parent := tree.GetParent(node);
  335. path := GetPath(parent);
  336. name := tree.GetNodeCaption(node);
  337. Strings.Append(path^, name^);
  338. Strings.Append(path^, "/");
  339. RETURN path
  340. END GetPathRecursive;
  341. BEGIN
  342. tree.Acquire; result := GetPathRecursive(node); tree.Release;
  343. RETURN result
  344. END GetPath;
  345. (* return parent's child with name. return NIL if there is no such child *)
  346. PROCEDURE FindChildNode(parent : WMTrees.TreeNode; name : Strings.String) : WMTrees.TreeNode;
  347. VAR child : WMTrees.TreeNode;
  348. temp : Strings.String;
  349. BEGIN
  350. tree.Acquire;
  351. child := tree.GetChildren(parent);
  352. WHILE child # NIL DO
  353. temp := tree.GetNodeCaption(child);
  354. IF temp^ = name^ THEN
  355. tree.Release;
  356. RETURN child
  357. END;
  358. child := tree.GetNextSibling(child);
  359. END;
  360. tree.Release;
  361. RETURN NIL
  362. END FindChildNode;
  363. (* add a child with caption and data to parent. if REPLACE is TRUE, existing nodes with the same name will be replaced *)
  364. PROCEDURE AddChildNode(parent : WMTrees.TreeNode; caption : Strings.String; data : EntryInfo; replace : BOOLEAN);
  365. VAR child : WMTrees.TreeNode;
  366. imgName : Strings.String;
  367. imgPath : ARRAY 512 OF CHAR;
  368. img : WMGraphics.Image;
  369. state : SET;
  370. BEGIN
  371. IF (caption^ # "") THEN
  372. IF replace THEN child := FindChildNode(parent, caption) END;
  373. tree.Acquire;
  374. IF child = NIL THEN
  375. NEW(child);
  376. tree.AddChildNode(parent, child);
  377. tree.SetNodeCaption(child, caption);
  378. IF ~showFiles.Get() THEN
  379. state := tree.GetNodeState(child); INCL(state, WMTrees.NodeHidden);
  380. tree.SetNodeState(child, state)
  381. END
  382. END;
  383. tree.SetNodeData(child, data);
  384. IF showImagePreview.Get() THEN
  385. COPY(archive.name, imgPath);
  386. Strings.Append(imgPath, "://");
  387. imgName := data.GetName();
  388. Strings.Append(imgPath, imgName^); Strings.Append(imgPath, "");
  389. img := WMGraphics.LoadImage(imgPath, FALSE);
  390. tree.SetNodeImage(child, img);
  391. END;
  392. tree.Release;
  393. END
  394. END AddChildNode;
  395. (* recursive method insert a new node at the right place *)
  396. PROCEDURE InsertTreeNode(parent : WMTrees.TreeNode; name : Strings.String; data : EntryInfo);
  397. VAR posOfSlash : SIZE;
  398. subnode : WMTrees.TreeNode;
  399. dirName, tail : Strings.String;
  400. BEGIN
  401. posOfSlash := Strings.Pos("/", name^);
  402. IF posOfSlash > -1 THEN (* go deeper in tree *)
  403. SplitString(name, dirName, tail, posOfSlash);
  404. subnode := FindChildNode(parent, dirName);
  405. IF subnode = NIL THEN (* add new directory *)
  406. NEW(subnode);
  407. tree.Acquire;
  408. tree.AddChildNode(parent, subnode);
  409. tree.SetNodeCaption(subnode, dirName);
  410. tree.Release
  411. END;
  412. InsertTreeNode(subnode, tail, data)
  413. ELSE (* add a leaf *)
  414. AddChildNode(parent, name, data, FALSE)
  415. END
  416. END InsertTreeNode;
  417. (* plug-in method for treeView *)
  418. PROCEDURE DrawTreeNode(canvas : WMGraphics.Canvas; w, h : LONGINT; node : WMTrees.TreeNode; state : SET);
  419. VAR dx, tdx, tdy, width, height : LONGINT; f : WMGraphics.Font;
  420. img : WMGraphics.Image;
  421. caption : Strings.String;
  422. BEGIN
  423. tree.Acquire;
  424. img := tree.GetNodeImage(node);
  425. caption := tree.GetNodeCaption(node);
  426. tree.Release;
  427. dx := 0;
  428. f := GetFont();
  429. IF img # NIL THEN
  430. IF img.width > 16 THEN width := 16 ELSE width := img.width END;
  431. IF img.height > 16 THEN height := 16 ELSE height := img.height END;
  432. canvas.ScaleImage(img, WMRectangles.MakeRect(0, 0, img.width, img.height), WMRectangles.MakeRect(0, 0, width, height), WMGraphics.ModeSrcOverDst, WMGraphics.ScaleBox);
  433. dx := 21;
  434. END;
  435. canvas.SetFont(f);
  436. IF WMTrees.StateSelected IN state THEN canvas.SetColor(treeView.clTextSelected.Get())
  437. ELSIF WMTrees.StateHover IN state THEN canvas.SetColor(treeView.clTextHover.Get())
  438. ELSE canvas.SetColor(treeView.clTextDefault.Get())
  439. END;
  440. f.GetStringSize(caption^, tdx, tdy);
  441. IF WMTrees.StateSelected IN state THEN canvas.Fill(WMRectangles.MakeRect(0, 0, dx + tdx, h), treeView.clSelected.Get(), WMGraphics.ModeSrcOverDst)
  442. ELSIF WMTrees.StateHover IN state THEN canvas.Fill(WMRectangles.MakeRect(0, 0, dx + tdx, h), treeView.clHover.Get(), WMGraphics.ModeSrcOverDst)
  443. END;
  444. IF caption # NIL THEN canvas.DrawString(dx, h - f.descent -1, caption^) END;
  445. END DrawTreeNode;
  446. (* plug-in method for treeView *)
  447. PROCEDURE MeasureTreeNode(node : WMTrees.TreeNode; VAR w, h : LONGINT);
  448. BEGIN
  449. h := TreePreviewSize; w := 400
  450. END MeasureTreeNode;
  451. (* ----- helper -------------------------------------------------- *)
  452. (* dest := archive.name || :// || src *)
  453. PROCEDURE AppendToArchiveName(CONST src: ARRAY OF CHAR; VAR dest : ARRAY OF CHAR);
  454. VAR i, j : LONGINT;
  455. BEGIN
  456. i := 0;
  457. WHILE archiveName[i] # 0X DO dest[i] := archiveName[i]; INC(i) END;
  458. dest[i] := ':'; INC(i);
  459. dest[i] := '/'; INC(i);
  460. dest[i] := '/'; INC(i);
  461. j := 0;
  462. WHILE src[j] # 0X DO dest[i+j] := src[j]; INC(j) END
  463. END AppendToArchiveName;
  464. END ArchiveTree;
  465. NodeEntry = OBJECT
  466. VAR
  467. name, full, size : Strings.String;
  468. node : WMTrees.TreeNode;
  469. END NodeEntry;
  470. NodeList = POINTER TO ARRAY OF NodeEntry;
  471. SelectionWrapper = POINTER TO RECORD
  472. sel : NodeList;
  473. END;
  474. (* GUI Window to perform basic operations on Archives *)
  475. Window* = OBJECT (WMComponents.FormWindow)
  476. VAR
  477. topToolbar, statusbar, sidePanel : WMStandardComponents.Panel;
  478. load : WMStandardComponents.Button;
  479. statusLabel : WMStandardComponents.Label;
  480. filenameEdit : WMEditors.Editor;
  481. archiveTree : ArchiveTree;
  482. list : WMStringGrids.StringGrid;
  483. nodeContent, selection : NodeList;
  484. curArc : Archives.Archive;
  485. popup : WMPopups.Popup;
  486. px, py: LONGINT;
  487. node : WMTrees.TreeNode;
  488. curFiles, curFolders, curBytes : LONGINT;
  489. PROCEDURE &New*(c : WMRestorable.Context);
  490. VAR vc : WMComponents.VisualComponent; xml : XML.Element; s : Strings.String;
  491. BEGIN
  492. IncCount;
  493. vc := CreateForm();
  494. Init(WindowWidth, WindowHeight, FALSE);
  495. SetContent(vc);
  496. SetTitle(Strings.NewString("WMArchives"));
  497. SetIcon(WMGraphics.LoadImage("WMIcons.tar://WMArchives.png", TRUE));
  498. IF c # NIL THEN
  499. (* restore the desktop *)
  500. WMRestorable.AddByContext(SELF, c);
  501. IF c.appData # NIL THEN
  502. xml := c.appData(XML.Element);
  503. s := xml.GetAttributeValue("file");
  504. IF s # NIL THEN Load(s^) END;
  505. Resized(GetWidth(), GetHeight())
  506. END
  507. ELSE
  508. WM.DefaultAddWindow(SELF)
  509. END;
  510. CSChanged;
  511. END New;
  512. PROCEDURE CreateForm() : WMComponents.VisualComponent;
  513. VAR panel : WMStandardComponents.Panel; resizerH : WMStandardComponents.Resizer;
  514. BEGIN
  515. NEW(panel); panel.alignment.Set(WMComponents.AlignClient); panel.fillColor.Set(0FFFFFFFFH);
  516. (* -- topToolbar -- *)
  517. NEW(topToolbar); topToolbar.bounds.SetHeight(20); topToolbar.alignment.Set(WMComponents.AlignTop);
  518. panel.AddContent(topToolbar);
  519. NEW(filenameEdit); filenameEdit.alignment.Set(WMComponents.AlignLeft); filenameEdit.multiLine.Set(FALSE);
  520. filenameEdit.bounds.SetWidth(200); filenameEdit.fillColor.Set(0FFFFFFFFH); filenameEdit.tv.showBorder.Set(TRUE);
  521. filenameEdit.tv.borders.Set(WMRectangles.MakeRect(3,3,1,1)); filenameEdit.onEnter.Add(LoadHandler);
  522. filenameEdit.tv.textAlignV.Set(WMGraphics.AlignCenter);
  523. topToolbar.AddContent(filenameEdit);
  524. NEW(load); load.caption.SetAOC("Load"); load.alignment.Set(WMComponents.AlignLeft); load.onClick.Add(LoadHandler);
  525. topToolbar.AddContent(load);
  526. (* -- statusbar -- *)
  527. NEW(statusbar); statusbar.bounds.SetHeight(20); statusbar.alignment.Set(WMComponents.AlignBottom);
  528. panel.AddContent(statusbar); statusbar.fillColor.Set(0CCCCCCFFH);
  529. NEW(statusLabel); statusLabel.bounds.SetWidth(WindowWidth); statusLabel.textColor.Set(0000000FFH); statusLabel.alignment.Set(WMComponents.AlignLeft);
  530. statusLabel.caption.SetAOC(" Total -- Folder(s) and -- Byte(s) in -- File(s)");
  531. statusbar.AddContent(statusLabel);
  532. (* -- main Archive Panel -- *)
  533. NEW(sidePanel); sidePanel.bounds.SetWidth(200); sidePanel.alignment.Set(WMComponents.AlignLeft);
  534. panel.AddContent(sidePanel);
  535. NEW(resizerH); resizerH.alignment.Set(WMComponents.AlignRight); sidePanel.AddContent(resizerH);
  536. NEW(archiveTree); archiveTree.alignment.Set(WMComponents.AlignClient);
  537. archiveTree.treeView.onClickNode.Add(NodeClicked); archiveTree.showFiles.Set(FALSE); archiveTree.showImagePreview.Set(FALSE);
  538. sidePanel.AddContent(archiveTree);
  539. archiveTree.NodeChanged := RefreshList;
  540. (* File-List *)
  541. NEW(list); list.alignment.Set(WMComponents.AlignClient);
  542. list.bounds.SetWidth(WindowWidth - 200);
  543. list.SetExtContextMenuHandler(ContextMenu);
  544. list.SetExtDragDroppedHandler(MyDragDropped);
  545. list.onClickSelected.Add(OpenFile);
  546. list.onStartDrag.Add(MyStartDrag);
  547. panel.AddContent(list);
  548. InitList;
  549. RETURN panel
  550. END CreateForm;
  551. PROCEDURE InitList;
  552. BEGIN
  553. list.model.Acquire;
  554. list.model.SetNofCols(2);
  555. list.model.SetNofRows(1);
  556. list.fixedRows.Set(1);
  557. list.adjustFocusPosition.Set(FALSE);
  558. list.model.SetCellText(0, 0, Strings.NewString("Filename"));
  559. list.model.SetCellText(1, 0, Strings.NewString("Size"));
  560. list.SetSelectionMode(WMGrids.GridSelectRows);
  561. list.SetSelection(-1, -1, -1, -1);
  562. AdjustTabSize;
  563. list.model.Release
  564. END InitList;
  565. PROCEDURE Resized*(width, height : LONGINT);
  566. BEGIN
  567. Resized^(width, height);
  568. AdjustTabSize;
  569. END Resized;
  570. (* --- helpers --------------------------------------------------- *)
  571. (* adjusts the Tab sizes to the current windwo width *)
  572. PROCEDURE AdjustTabSize;
  573. VAR colWidths : WMGrids.Spacings; col0Width : LONGINT;
  574. BEGIN
  575. NEW(colWidths, 2);
  576. col0Width := (list.bounds.GetWidth() DIV 6)*5;
  577. colWidths[0] := col0Width;
  578. colWidths[1] := list.bounds.GetWidth() - col0Width;
  579. list.SetColSpacings(colWidths);
  580. END AdjustTabSize;
  581. (* removes the multiline input *)
  582. PROCEDURE FixFilename(VAR filename : ARRAY OF CHAR);
  583. VAR i : LONGINT; found : BOOLEAN;
  584. BEGIN
  585. i := 0;
  586. WHILE (i < LEN(filename)) & ~found DO
  587. IF ORD(filename[i]) = 10 THEN filename[i] := 0X; found := TRUE;
  588. ELSIF filename[i] = 0X THEN found := TRUE END;
  589. INC(i);
  590. END;
  591. END FixFilename;
  592. PROCEDURE GetFormatFromFilename(CONST filename : ARRAY OF CHAR; VAR format : ARRAY OF CHAR);
  593. VAR file : ARRAY 128 OF CHAR;
  594. BEGIN
  595. IF filename = "" THEN COPY("tar", format);
  596. ELSE
  597. Strings.GetExtension(filename, file, format);
  598. Strings.LowerCase(format);
  599. END
  600. END GetFormatFromFilename;
  601. (* --- handlers --------------------------------------------------- *)
  602. PROCEDURE NodeClicked(sender, data : ANY);
  603. VAR curNode : WMTrees.TreeNode;
  604. tree : WMTrees.Tree; entry : NodeEntry;
  605. any : ANY;
  606. string : Strings.String; temp : ARRAY 128 OF CHAR;
  607. counter, tempInt : LONGINT;
  608. img : WMGraphics.Image;
  609. BEGIN
  610. IF (sender IS WMTrees.TreeView) & (data IS WMTrees.TreeNode) THEN
  611. node := data(WMTrees.TreeNode);
  612. tree := sender(WMTrees.TreeView).GetTree();
  613. tree.Acquire;
  614. (* count elements in node *)
  615. curNode := tree.GetChildren(node);
  616. counter := 0;
  617. WHILE curNode # NIL DO
  618. IF tree.GetNodeData(curNode) # NIL THEN INC(counter) END;
  619. curNode := tree.GetNextSibling(curNode);
  620. END;
  621. (* build array with elements *)
  622. NEW(nodeContent, counter);
  623. curNode := tree.GetChildren(node); counter := 0; curFiles := 0; curFolders := 0; curBytes := 0;
  624. WHILE curNode # NIL DO
  625. NEW(entry);
  626. entry.node := curNode;
  627. any := tree.GetNodeData(curNode);
  628. IF any # NIL THEN
  629. string := any(Archives.EntryInfo).GetName();
  630. entry.full := Strings.NewString(string^);
  631. tempInt := any(Archives.EntryInfo).GetSize();
  632. Strings.IntToStr(tempInt, string^);
  633. entry.size := string;
  634. entry.name := tree.GetNodeCaption(curNode);
  635. nodeContent[counter] := entry;
  636. INC(counter); INC(curFiles); INC(curBytes, tempInt)
  637. ELSE
  638. INC(curFolders)
  639. END;
  640. curNode := tree.GetNextSibling(curNode)
  641. END;
  642. tree.Release;
  643. COPY("icons.tar://", temp);
  644. Strings.Append(temp, "File.png");
  645. img := WMGraphics.LoadImage(temp, TRUE);
  646. (* fill list with array *)
  647. list.model.Acquire;
  648. list.model.SetNofRows(counter+1);
  649. WHILE counter > 0 DO
  650. list.model.SetCellText(0, counter, nodeContent[counter-1].name);
  651. list.model.SetCellText(1, counter, nodeContent[counter-1].size);
  652. list.model.SetCellData(0, counter, nodeContent[counter-1]);
  653. list.model.SetCellImage(0, counter, img);
  654. DEC(counter);
  655. END;
  656. list.model.Release;
  657. UpdateStatusbar;
  658. END
  659. END NodeClicked;
  660. PROCEDURE LoadHandler(sender, data : ANY);
  661. VAR filename : ARRAY 256 OF CHAR;
  662. BEGIN
  663. filenameEdit.GetAsString(filename);
  664. FixFilename(filename);
  665. filenameEdit.SetAsString(filename);
  666. Load(filename)
  667. END LoadHandler;
  668. PROCEDURE Load(CONST filename : ARRAY OF CHAR);
  669. VAR format : ARRAY 16 OF CHAR;
  670. BEGIN
  671. GetFormatFromFilename(filename, format);
  672. curArc := Archives.Old(filename, format);
  673. IF curArc = NIL THEN
  674. curArc := Archives.New(filename, format)
  675. END;
  676. IF curArc # NIL THEN filenameEdit.SetAsString(curArc.name); archiveTree.SetArchive(curArc) END
  677. END Load;
  678. PROCEDURE Handle*(VAR x: WMMessages.Message);
  679. VAR data : XML.Element; a : XML.Attribute; n : ARRAY 16 OF CHAR;
  680. filename : ARRAY 256 OF CHAR;
  681. BEGIN
  682. IF (x.msgType = WMMessages.MsgExt) & (x.ext # NIL) THEN
  683. IF (x.ext IS KillerMsg) THEN Close
  684. ELSIF (x.ext IS WMRestorable.Storage) THEN
  685. NEW(data); n := "WMArchivesData"; data.SetName(n);
  686. filenameEdit.GetAsString(filename);
  687. NEW(a); n := "file"; a.SetName(n); a.SetValue(filename); data.AddAttribute(a);
  688. x.ext(WMRestorable.Storage).Add("WMArchives", "WMArchives.Restore", SELF, data)
  689. ELSE Handle^(x)
  690. END
  691. ELSE Handle^(x)
  692. END
  693. END Handle;
  694. PROCEDURE ContextMenu(sender : ANY; x, y: LONGINT);
  695. VAR curSel : NodeList;
  696. w : SelectionWrapper;
  697. BEGIN
  698. px := x; py := y;
  699. NEW(popup);
  700. curSel := GetSelection();
  701. NEW(w); w.sel := curSel;
  702. IF LEN(curSel) = 0 THEN RETURN END;
  703. popup.AddParButton("Open", Open, w);
  704. popup.AddParButton("Delete", DeleteEntries, w);
  705. IF LEN(curSel) = 1 THEN
  706. popup.AddParButton("Rename", RenameEntry, w)
  707. END;
  708. list.ToWMCoordinates(x, y, px, py);
  709. popup.Popup(px, py)
  710. END ContextMenu;
  711. PROCEDURE GetSelection() : NodeList;
  712. VAR selection : NodeList;
  713. l, t, r, b, i, j : LONGINT;
  714. p : ANY;
  715. BEGIN
  716. list.model.Acquire;
  717. list.GetSelection(l, t, r, b);
  718. NEW(selection, b- t + 1);
  719. j := 0;
  720. FOR i := t TO b DO
  721. p := list.model.GetCellData(0, i);
  722. IF (p # NIL) & (p IS NodeEntry) THEN
  723. selection[j] := p(NodeEntry);
  724. INC(j)
  725. END
  726. END;
  727. list.model.Release;
  728. RETURN selection
  729. END GetSelection;
  730. PROCEDURE Open(sender, data : ANY);
  731. VAR d: NodeList; i : LONGINT;
  732. BEGIN
  733. IF (popup # NIL) THEN popup.Close; popup := NIL END;
  734. IF (data # NIL) & (data IS SelectionWrapper) THEN
  735. d := data(SelectionWrapper).sel;
  736. IF (d # NIL) THEN
  737. FOR i := 0 TO LEN(d)-1 DO
  738. OpenFile(SELF, d[i]);
  739. END;
  740. END;
  741. END;
  742. END Open;
  743. PROCEDURE OpenFile(sender, data : ANY);
  744. VAR filename : Files.FileName;
  745. BEGIN
  746. IF (data # NIL) & (data IS NodeEntry) THEN
  747. COPY(curArc.name, filename);
  748. Strings.Append(filename, "://");
  749. Strings.Append(filename, data(NodeEntry).full^);
  750. FileHandlers.OpenFile(filename, NIL, SELF);
  751. END;
  752. END OpenFile;
  753. PROCEDURE RenameEntry(sender, data : ANY);
  754. VAR rename : WMDialogs.MiniStringInput;
  755. name, caption : ARRAY 128 OF CHAR;
  756. entryInfo : ANY; entry : NodeEntry;
  757. s : Strings.String;
  758. BEGIN
  759. IF (data # NIL) & (data IS SelectionWrapper) THEN
  760. entry := data(SelectionWrapper).sel[0];
  761. IF entry # NIL THEN
  762. NEW(rename);
  763. archiveTree.tree.Acquire;
  764. entryInfo := archiveTree.tree.GetNodeData(entry.node);
  765. s := entryInfo(EntryInfo).GetName();
  766. COPY(s^, name);
  767. IF rename.Show(px, py, name) = WMDialogs.ResOk THEN
  768. IF s^ # name THEN
  769. archiveTree.archive.Acquire; entryInfo := archiveTree.archive.RenameEntry(s^, name); archiveTree.archive.Release;
  770. IF entryInfo # NIL THEN
  771. archiveTree.tree.SetNodeData(entry.node, entryInfo);
  772. RemovePath(name, caption);
  773. archiveTree.tree.SetNodeCaption(entry.node, Strings.NewString(caption));
  774. NodeClicked(archiveTree.treeView, archiveTree.tree.GetParent(entry.node))
  775. END
  776. END
  777. END;
  778. archiveTree.tree.Release;
  779. END
  780. END
  781. END RenameEntry;
  782. PROCEDURE DeleteEntries(sender, data : ANY);
  783. VAR parent : WMTrees.TreeNode;
  784. entry : NodeEntry; entryInfo : ANY; s : Strings.String;
  785. dr, i : LONGINT; name : ARRAY 128 OF CHAR;
  786. delete, always, never : BOOLEAN;
  787. BEGIN
  788. IF (data # NIL) & (data IS SelectionWrapper) THEN
  789. always := FALSE; never := FALSE;
  790. archiveTree.tree.Acquire;
  791. FOR i := 0 TO LEN(data(SelectionWrapper).sel) - 1 DO
  792. entry := data(SelectionWrapper).sel[i];
  793. delete := FALSE;
  794. IF entry # NIL THEN
  795. entryInfo := archiveTree.tree.GetNodeData(entry.node);
  796. parent := archiveTree.tree.GetParent(entry.node);
  797. s := entryInfo(EntryInfo).GetName();
  798. COPY(s^, name);
  799. IF ~always & ~never THEN
  800. dr := WMDialogs.Message(WMDialogs.TConfirmation, "Confirm deleting file", name,
  801. {WMDialogs.ResNo, WMDialogs.ResAbort, WMDialogs.ResYes, WMDialogs.ResAll});
  802. IF dr IN {WMDialogs.ResYes, WMDialogs.ResAll} THEN delete := TRUE END;
  803. IF dr = WMDialogs.ResAll THEN always := TRUE END;
  804. IF dr = WMDialogs.ResAbort THEN never := TRUE END;
  805. END;
  806. IF ~never & (delete OR always) THEN
  807. archiveTree.archive.Acquire; archiveTree.archive.RemoveEntry(name); archiveTree.archive.Release;
  808. archiveTree.tree.RemoveNode(entry.node);
  809. NodeClicked(archiveTree.treeView, parent)
  810. END
  811. END
  812. END;
  813. archiveTree.tree.Release;
  814. END
  815. END DeleteEntries;
  816. PROCEDURE RefreshList(sender, data : ANY);
  817. VAR selected : WMTrees.TreeNode;
  818. BEGIN
  819. IF node # NIL THEN selected := node;
  820. ELSE selected := archiveTree.tree.GetRoot() END;
  821. NodeClicked(archiveTree.treeView, selected)
  822. END RefreshList;
  823. PROCEDURE UpdateStatusbar;
  824. VAR statusStr, tempStr : ARRAY 256 OF CHAR;
  825. BEGIN
  826. COPY(" Total ", statusStr);
  827. Strings.IntToStr(curFolders, tempStr); Strings.Append(statusStr, tempStr);
  828. Strings.Append(statusStr, " Folder(s) and ");
  829. Strings.IntToStr(curBytes, tempStr); Strings.Append(statusStr, tempStr);
  830. Strings.Append(statusStr, " Byte(s) in ");
  831. Strings.IntToStr(curFiles, tempStr); Strings.Append(statusStr, tempStr);
  832. Strings.Append(statusStr, " File(s)");
  833. statusLabel.caption.SetAOC(statusStr);
  834. END UpdateStatusbar;
  835. (* ----- drag operations ----------------------------------------- *)
  836. (* called when an object has been dropped on the file-list *)
  837. PROCEDURE MyDragDropped(x, y : LONGINT; dragInfo : WM.DragInfo; VAR handled : BOOLEAN);
  838. BEGIN
  839. handled := TRUE;
  840. ListDragDropped(x, y, dragInfo);
  841. RefreshList(SELF, node)
  842. END MyDragDropped;
  843. (* called by MyDraggedDropped *)
  844. PROCEDURE ListDragDropped(x, y : LONGINT; dragInfo : WM.DragInfo);
  845. VAR dropTarget : ArchiveDropTarget;
  846. parent : WMTrees.TreeNode;
  847. accept : BOOLEAN;
  848. data : ANY;
  849. BEGIN
  850. archiveTree.tree.Acquire;
  851. IF node # NIL THEN parent := node
  852. ELSE parent := archiveTree.tree.GetRoot() END;
  853. data := archiveTree.tree.GetNodeData(parent);
  854. archiveTree.tree.Release;
  855. IF (parent = NIL) OR (data # NIL) THEN
  856. accept := FALSE
  857. ELSE
  858. accept := TRUE;
  859. NEW(dropTarget, archiveTree, parent);
  860. dragInfo.data := dropTarget;
  861. END;
  862. ConfirmDrag(accept, dragInfo)
  863. END ListDragDropped;
  864. (* called when a drag-operation has been started *)
  865. PROCEDURE MyStartDrag(sender, data : ANY);
  866. VAR img : WMGraphics.Image;
  867. c : WMGraphics.BufferCanvas;
  868. top, i : LONGINT;
  869. BEGIN
  870. selection := GetSelection();
  871. (* render to bitmap *)
  872. NEW(img); Raster.Create(img, 100, 200, Raster.BGRA8888);
  873. NEW(c, img);
  874. c.SetColor(LONGINT(0FFFF00FFH));
  875. top := 0;
  876. FOR i := 0 TO LEN(selection) - 1 DO
  877. IF selection[i] # NIL THEN
  878. c.Fill(WMRectangles.MakeRect(0, top, 100, top + 25), 0FF80H, WMGraphics.ModeCopy);
  879. c.DrawString(3, top + 20, selection[i].name^);
  880. INC(top, 25)
  881. END
  882. END;
  883. IF list.StartDrag(NIL, img, 0,0,ListDragArrived, NIL) THEN KernelLog.String("Dragging started")
  884. ELSE KernelLog.String("Drag could not be started")
  885. END;
  886. END MyStartDrag;
  887. (* called when an object dragged from the list has been dropped anywhere *)
  888. PROCEDURE ListDragArrived(sender, data : ANY);
  889. VAR di : WM.DragInfo;
  890. dt : WMDropTarget.DropTarget;
  891. itf : WMDropTarget.DropInterface;
  892. i : LONGINT; res : WORD;
  893. sel : NodeList;
  894. url, caption : ARRAY 1024 OF CHAR;
  895. text : Texts.Text;
  896. textPos : Texts.TextPosition;
  897. rec : Streams.Receiver;
  898. nl: ARRAY 2 OF CHAR;
  899. BEGIN
  900. sel := selection;
  901. IF sel = NIL THEN RETURN END;
  902. IF (data # NIL) & (data IS WM.DragInfo) THEN
  903. di := data(WM.DragInfo);
  904. IF (di.data # NIL) & (di.data IS WMDropTarget.DropTarget) THEN
  905. dt := di.data(WMDropTarget.DropTarget)
  906. ELSE RETURN
  907. END
  908. ELSE RETURN
  909. END;
  910. (* File *)
  911. itf := dt.GetInterface(WMDropTarget.TypeFiles);
  912. IF itf # NIL THEN
  913. FOR i := 0 TO LEN(selection) - 1 DO
  914. IF selection[i] # NIL THEN
  915. COPY(selection[i].full^, url);
  916. COPY(selection[i].name^, caption);
  917. archiveTree.archive.Acquire;
  918. rec := archiveTree.archive.OpenReceiver(url);
  919. CopyFile(rec, itf(WMDropTarget.DropFiles), caption, res);
  920. archiveTree.archive.Release;
  921. END
  922. END;
  923. RETURN
  924. END;
  925. (* Text *)
  926. itf := dt.GetInterface(WMDropTarget.TypeText);
  927. IF itf # NIL THEN
  928. text := itf(WMDropTarget.DropText).text;
  929. textPos := itf(WMDropTarget.DropText).pos;
  930. IF (text # NIL) & (textPos # NIL) THEN
  931. text.AcquireWrite;
  932. FOR i := 0 TO LEN(selection) - 1 DO
  933. IF selection[i] # NIL THEN
  934. COPY(selection[i].name^, url);
  935. nl[0] := CHR(Texts.NewLineChar);
  936. nl[1] := 0X;
  937. Strings.Append(url, nl);
  938. TextUtilities.StrToText(text, textPos.GetPosition(), url)
  939. END
  940. END;
  941. text.ReleaseWrite
  942. END;
  943. RETURN
  944. END;
  945. END ListDragArrived;
  946. PROCEDURE Close*;
  947. BEGIN
  948. Close^;
  949. DecCount;
  950. END Close;
  951. END Window;
  952. VAR
  953. nofWindows : LONGINT;
  954. ProtShowFiles, ProtShowImgPrev : WMProperties.BooleanProperty;
  955. StrArchiveTree : Strings.String;
  956. (* ----- helpers ------------------------------------------------------- *)
  957. (* copy the head of string to head and the tail of string to tail *)
  958. PROCEDURE SplitString(string : Strings.String; VAR head, tail : Strings.String; index : SIZE);
  959. VAR i : LONGINT;
  960. BEGIN
  961. NEW(head, index+1);
  962. NEW(tail, LEN(string^)-index);
  963. (* head *)
  964. i := 0;
  965. WHILE i < index DO
  966. head[i] := string[i];
  967. INC(i)
  968. END;
  969. head[i] := 0X;
  970. (* tail *)
  971. i := 0;
  972. WHILE string[index+1+i] # 0X DO
  973. tail[i] := string[index+1+i];
  974. INC(i)
  975. END;
  976. tail[i] := 0X
  977. END SplitString;
  978. (* "path1/path2/.../name" => "name" *)
  979. PROCEDURE RemovePath(CONST src : ARRAY OF CHAR; VAR dest : ARRAY OF CHAR);
  980. VAR i, j : LONGINT;
  981. BEGIN
  982. i := LEN(src) - 1;
  983. WHILE (i > 0) & (src[i] # '/') DO DEC(i) END;
  984. IF i > 0 THEN INC(i) END;
  985. FOR j := 0 TO LEN(src) - 1 - i DO
  986. dest[j] := src[i];
  987. INC(i)
  988. END
  989. END RemovePath;
  990. (* "PART:file.ext" => "file.ext" *)
  991. PROCEDURE RemovePartitionLabel(CONST src : ARRAY OF CHAR; VAR dest : ARRAY OF CHAR);
  992. VAR i, j : LONGINT;
  993. BEGIN
  994. i := 0;
  995. WHILE (i < LEN(src)) & (src[i] # ':') DO INC(i) END;
  996. IF i = LEN(src) THEN
  997. COPY(src, dest)
  998. ELSE
  999. j := 0;
  1000. WHILE j + i + 1 < LEN(src) DO
  1001. dest[j] := src[i+j+1];
  1002. INC(j)
  1003. END
  1004. END
  1005. END RemovePartitionLabel;
  1006. (* transfer data from rec to target *)
  1007. PROCEDURE CopyFile(rec : Streams.Receiver; target : WMDropTarget.DropFiles; CONST remote : ARRAY OF CHAR; VAR res : WORD);
  1008. VAR w : Streams.Writer; r : Streams.Reader; buf: ARRAY BufSize OF CHAR; len: LONGINT;
  1009. BEGIN
  1010. res := -1;
  1011. Streams.OpenReader(r, rec);
  1012. target.OpenPut(remote, w, res);
  1013. IF res = 0 THEN
  1014. REPEAT
  1015. r.Bytes(buf, 0, BufSize, len); w.Bytes(buf, 0, len);
  1016. UNTIL r.res # 0;
  1017. target.ClosePut(res)
  1018. END
  1019. END CopyFile;
  1020. (* ---- window stuff -------------------------------------------------------------------- *)
  1021. PROCEDURE InitPrototypes;
  1022. VAR plArchiveTree : WMProperties.PropertyList;
  1023. BEGIN
  1024. (* archive tree *)
  1025. NEW(plArchiveTree); WMComponents.propertyListList.Add("Archive Tree", plArchiveTree);
  1026. NEW(ProtShowFiles, NIL, Strings.NewString("Show Files"), Strings.NewString("Enables Tree to show the Files")); plArchiveTree.Add(ProtShowFiles);
  1027. ProtShowFiles.Set(TRUE);
  1028. NEW(ProtShowImgPrev, NIL, Strings.NewString("Show Image Preview"), Strings.NewString("Enables Tree to show Image Previews")); plArchiveTree.Add(ProtShowImgPrev);
  1029. ProtShowImgPrev.Set(TRUE);
  1030. StrArchiveTree := Strings.NewString("Archive Tree")
  1031. END InitPrototypes;
  1032. PROCEDURE Open*(context : Commands.Context);
  1033. VAR window : Window; filename : Files.FileName;
  1034. BEGIN
  1035. NEW(window, NIL);
  1036. IF context.arg.GetString(filename) THEN
  1037. window.Load(filename);
  1038. END;
  1039. END Open;
  1040. PROCEDURE Restore*(context : WMRestorable.Context);
  1041. VAR win : Window;
  1042. BEGIN
  1043. ASSERT(context # NIL);
  1044. NEW(win, context)
  1045. END Restore;
  1046. PROCEDURE IncCount;
  1047. BEGIN {EXCLUSIVE}
  1048. INC(nofWindows);
  1049. END IncCount;
  1050. PROCEDURE DecCount;
  1051. BEGIN {EXCLUSIVE}
  1052. DEC(nofWindows);
  1053. END DecCount;
  1054. PROCEDURE Cleanup;
  1055. VAR die : KillerMsg;
  1056. msg : WMMessages.Message;
  1057. m : WM.WindowManager;
  1058. BEGIN {EXCLUSIVE}
  1059. NEW(die);
  1060. msg.ext := die;
  1061. msg.msgType := WMMessages.MsgExt;
  1062. m := WM.GetDefaultManager();
  1063. m.Broadcast(msg);
  1064. AWAIT(nofWindows = 0);
  1065. END Cleanup;
  1066. BEGIN
  1067. InitPrototypes;
  1068. Modules.InstallTermHandler(Cleanup);
  1069. END WMArchives.
  1070. WMArchives.Open ~
  1071. WMArchives.Open traditional.skin ~
  1072. System.Free WMArchives ~