36e6b7b696414422b8942ebdc2c739bcd5bc2e7d
[ede] / libede / src / FileSystemBox.ec
1 public import "ecere"
2 import "FileSystemCache"
3
4 #ifdef __WIN32__
5 static char * rootName = "Entire Computer";
6 static char * msNetwork = "Microsoft Windows Network";
7 #else
8 static char * rootName = "File System";
9 #endif
10
11 private:
12 define guiApp = (GuiApplication)((__thisModule).application);
13 define selectionColor = guiApp.currentSkin.selectionColor; //Color { 10, 36, 106 };
14
15 void MessageBoxTodo(char * message)
16 {
17    PrintLn("MessageBoxTodo(char * message) -- ", message);
18    MessageBox { type = ok, text = "MessageBoxTodo(char * message)", contents = message }.Modal();
19 }
20
21 static char * fileIconNames[] =
22 {
23    "<:ecere>mimeTypes/file.png",         /* none */
24
25    "<:ecere>mimeTypes/file.png",         /* normalFile */
26    "<:ecere>mimeTypes/textEcereWorkspace.png",          /* ewsFile */
27    "<:ecere>mimeTypes/textEcereProject.png",      /* epjFile */
28    "<:ecere>mimeTypes/textEcereSource.png",         /* ecFile */
29    "<:ecere>mimeTypes/textEcereHeader.png",         /* ehFile */
30    "<:ecere>mimeTypes/textCSource.png",          /* cFile */
31    "<:ecere>mimeTypes/textCHeader.png",          /* hFile */
32    "<:ecere>mimeTypes/textC++Source.png",        /* cppFile */
33    "<:ecere>mimeTypes/textC++Header.png",        /* hppFile */
34    "<:ecere>mimeTypes/text.png",         /* textFile */
35    "<:ecere>mimeTypes/textHyperTextMarkup.png",              /* webFile */
36    "<:ecere>mimeTypes/image.png",        /* pictureFile */
37    "<:ecere>status/audioVolumeHigh.png",         /* soundFile */
38    "<:ecere>mimeTypes/package.png",      /* archiveFile */
39    "<:ecere>mimeTypes/packageSoftware.png",     /* packageFile */
40    "<:ecere>mimeTypes/packageOpticalDisc.png", /* opticalMediaImageFile */
41
42    "<:ecere>places/folder.png",                    /* folder */
43    "<:ecere>status/folderOpen.png",               /* folderOpen */
44    "<:ecere>devices/computer.png",                 /* computer */
45    "<:ecere>devices/driveHardDisk.png",           /* drive */
46    "<:ecere>places/driveRemote.png",              /* netDrive */
47    "<:ecere>devices/mediaOptical.png",            /* cdrom */
48    "<:ecere>devices/driveRemovableMedia.png",    /* removable */
49    "<:ecere>devices/mediaFloppy.png",             /* floppy */
50    "<:ecere>places/networkWorkgroup.png",         /* network */
51    "<:ecere>places/networkServer.png",            /* server */
52    "<:ecere>places/folderRemote.png",             /* share */
53
54    "<:ecere>mimeTypes/package.png",      /* treeLoader */
55    "<:ecere>places/startHere.png",                /* lineNumbers */
56    
57    ""
58 };
59
60 define countOfCompIconNames = 6;
61 static char * compIconNames[] =
62 {
63 /*
64    "<:ede>a.png",
65    "<:ede>b.png",
66    "<:ede>c.png",
67    "<:ede>d.png",
68    "<:ede>not.png",
69 */
70    "<:ede>devices/media-optical.png",
71    "<:ede>devices/media-flash.png",
72    "<:ede>places/network-server.png",
73    "<:ede>places/folder-saved-search.png",
74    "<:ede>places/user-home.png",
75    "<:ede>emblem-not.png",
76    ""
77 };
78
79 public enum _FileType
80 {
81    none,
82    
83    normalFile, ewsFile, epjFile, ecFile, ehFile, cFile, hFile, cppFile, hppFile,
84    textFile, webFile, pictureFile, soundFile,
85    archiveFile, packageFile, opticalMediaImageFile, /* these (all previous) are sort equal */
86    
87    folder, folderOpen, computer,
88    drive, netDrive, cdrom, removable, floppy, network, server, share, // these are sort equal
89    
90    // utilities
91    treeLoader,
92    lineNumbers;
93
94    /*property char * 
95    {
96       set
97       {
98          this = SelectByExtension(value);
99       }
100    }*/
101
102    public property bool isFolder
103    {
104       get { return this >= folder && this <= share; }
105    }
106
107    public property bool isFile
108    {
109       get { return this >= normalFile && this <= opticalMediaImageFile; }
110    }
111
112    _FileType ::SelectByExtension(char * extension)
113    {
114       if(!strcmpi(extension, "ews"))
115          return ewsFile;
116       else if(!strcmpi(extension, "epj"))
117          return epjFile;
118       else if(!strcmpi(extension, "ec"))
119          return ecFile;
120       else if(!strcmpi(extension, "eh"))
121          return ehFile;
122       else if(!strcmpi(extension, "cpp") ||
123             !strcmpi(extension, "cc") || !strcmpi(extension, "cxx"))
124          return cppFile;
125       else if(!strcmpi(extension, "hpp") ||
126             !strcmpi(extension, "hh") || !strcmpi(extension, "hxx"))
127          return hppFile;
128       else if(!strcmpi(extension, "c"))
129          return cFile;
130       else if(!strcmpi(extension, "h"))
131          return hFile;
132       else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
133             !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
134          return textFile;
135       else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
136             !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
137             !strcmpi(extension, "js"))
138          return webFile;
139       else if(!strcmpi(extension, "bmp") || !strcmpi(extension, "pcx") ||
140             !strcmpi(extension, "jpg") || !strcmpi(extension, "jpeg") ||
141             !strcmpi(extension, "gif") || !strcmpi(extension, "png") ||
142             !strcmpi(extension, "ico"))
143          return pictureFile;
144       else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
145             !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
146          return soundFile;
147       else if(!strcmpi(extension, "ear") || !strcmpi(extension, "7z") ||
148             !strcmpi(extension, "rar") || !strcmpi(extension, "zip") ||
149             !strcmpi(extension, "gz") || !strcmpi(extension, "bz2") ||
150             !strcmpi(extension, "tar") || !strcmpi(extension, "arj") ||
151             !strcmpi(extension, "lza") || !strcmpi(extension, "lzh") ||
152             !strcmpi(extension, "cpio") || !strcmpi(extension, "z"))
153          return archiveFile;
154       else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
155             !strcmpi(extension, "rpm"))
156          return packageFile;
157       else if(!strcmpi(extension, "iso") || !strcmpi(extension, "mds") ||
158             !strcmpi(extension, "cue") || !strcmpi(extension, "bin") ||
159             !strcmpi(extension, "ccd") || !strcmpi(extension, "bwt") ||
160             !strcmpi(extension, "cdi") || !strcmpi(extension, "nrg"))
161          return opticalMediaImageFile;
162       return normalFile;
163    }
164 };
165
166 public enum FileSystemBoxMode { directory, list };
167
168 class FileSystemBoxBits
169 {
170    bool foldersOnly:1, filesOnly:1, details:1, pathColumn:1, treeBranches:1, previewPictures:1, navigateFolders:1, autoLoad:1;
171    bool preview:1;
172    bool columnsCompareStyle:1;
173    //bool header:1, freeSelect:1, fullRowSelect:1, multiSelect:1, autoScroll:1, alwaysHL : 1, moveRows:1, resizable:1;
174    //bool moveFields:1, clearHeader:1, alwaysEdit:1, collapse:1, treeBranch:1, rootCollapse:1, heightSet:1;
175    //bool sortable:1, noDragging:1, fillLastField:1, expandOnAdd:1;
176    bool textFileLinesStyle:1;
177
178    FileSystemBoxMode mode:2;
179 }
180
181 public class FileSystemBox : Window // should we not derive from ListBox instead?
182                                     // I say we should, but we can't right now...
183                                     // because ListBox (inside ecere library) is
184                                     // not exposing enough internal machinery...
185                                     // could we not have a different private and
186                                     // public mechanism when deriving a class than
187                                     // we do when simply instanciating a class?
188 /*
189    this stuff from the listbox would be nicely exposed...
190       fullRowSelect = false;
191       treeBranches = true;
192       collapseControl = true;
193       rootCollapseButton = true;
194       sortable = true;
195 */
196 {
197    borderStyle = deep;
198    hasHorzScroll = false;
199    hasVertScroll = false;
200
201    menu = Menu { };
202
203 public:
204    FileSystemNode root;
205    FileSystemBoxSelection selection { };
206
207    subclass(InterfaceFileSystemIterator) iteratorClass;
208    FileSystemCache cache;
209
210    virtual bool Window::NotifyNodeSelect(FileSystemBox box, FileSystemBoxSelection selection);
211    //virtual bool Window::NotifyNodeNavigate(FileSystemBox box, FileSystemNode node);
212    virtual bool Window::NotifyNodeOpen(FileSystemBox box, FileSystemBoxSelection selection);
213    virtual bool Window::NotifyNodeMenu(FileSystemBox box, Menu menu, FileSystemBoxSelection selection);
214    virtual bool Window::NotifyIteratorInit(FileSystemBox box, FileSystemIterator fileSystemIterator);
215    
216    property char * path
217    {
218       set
219       {
220          delete path;
221          if(value && value[0])
222             path = CopyString(value);
223          if(locationBox)
224             locationBox.path = value;
225          if(created)
226             Load();
227       }
228       get { return path; }
229       //isset { return path && path[0]; }
230    }
231
232    property Array<String> comparedPaths
233    {
234       set
235       {
236          delete comparedPaths;
237          if(value && value.count)
238             comparedPaths = value;
239          if(locationBox)
240             locationBox.path = value[0];
241          if(created)
242             Load();
243       }
244       get { return comparedPaths; }
245       //isset { return comparedPaths && comparedPaths.count; }
246    }
247
248    property FileSystemBoxMode mode { set { bits.mode = value; } get { return bits.mode; } };
249    property bool foldersOnly { set { bits.foldersOnly = value; bits.filesOnly = !value; } get { return bits.foldersOnly; } };
250    property bool filesOnly { set { bits.filesOnly = value; bits.foldersOnly = !value; } get { return bits.filesOnly; } };
251    property bool previewPictures { set { bits.previewPictures = value; } get { return bits.previewPictures; } };
252    property char * extensions { set { delete extensions; if(value && value[0]) extensions = CopyString(value); } get { return extensions; } }
253    property bool details { set { bits.details = value; ChangeViewType(); } get { return bits.details; } };
254    property bool pathColumn { set { bits.pathColumn = value; ChangeViewType(); } get { return bits.pathColumn; } };
255    property bool treeBranches
256    {
257       set
258       {
259          bits.treeBranches = value;
260          list.treeBranches = value;
261          list.collapseControl = value;
262          list.rootCollapseButton = value;
263       }
264       get { return bits.treeBranches; }
265    };
266    property Color selectionColor { set { list.selectionColor = value; } get { return list.selectionColor; }/* isset { return selectionColor ? true : false; }*/ };
267    property Color selectionText  { set { list.selectionText = value; } get { return list.selectionText; }/* isset { return selectionText ? true : false; }*/ };
268    property bool navigateFolders { set { bits.navigateFolders = value; bits.filesOnly = !value; } get { return bits.navigateFolders; } };
269    property bool multiSelect { set { list.multiSelect = value; } get { return list.multiSelect; } };
270    property bool autoLoad { set { bits.autoLoad = value; } get { return bits.autoLoad; } };
271    property bool hasHeader { set { list.hasHeader = value; } get { return list.hasHeader; } };
272    property bool preview
273    {
274       set
275       {
276          bits.preview = value;
277          split.leftPane = value ? list : null;
278          split.visible = value;
279          show.visible = value;
280       }
281       get { return bits.preview; }
282    };
283    property bool columnsCompareStyle { set { bits.columnsCompareStyle = value; } get { return bits.columnsCompareStyle; } };
284    property bool textFileLinesStyle { set { bits.textFileLinesStyle = value; } get { return bits.textFileLinesStyle; } };
285    
286    property FileSystemNode node
287    {
288       get
289       {
290          if(!list)
291             return null;
292          if(!list.currentRow)
293             return null;
294          if(!list.currentRow.tag)
295             return null;
296          return (FileSystemNode)list.currentRow.tag;
297       }
298    }
299
300    PathBox locationBox;
301
302    void Select(FileSystemNode node)
303    {
304       if(node.row)
305       {
306          node.EnsureVisible(false);
307          list.SelectRow(node.row);
308       }
309    }
310
311    void SelectMultipleByPath(Array<String> paths)
312    {
313       DataRow row;
314       bool firstRow = false;
315       Map<String, bool> map { };
316       for(path : paths)
317          map[path] = true;
318       for(row = list.firstRow; row; row = row.next)
319       {
320          FileSystemNode node = (FileSystemNode)row.tag;
321          if(map[node.path])
322          {
323             if(!firstRow)
324             {
325                list.SelectRow(row);
326                firstRow = true;
327             }
328             else
329                row.selected = true;
330          }
331          else
332             row.selected = false;
333       }
334       delete map;
335    }
336
337    FileSystemNode SelectLocation(char * location)
338    {
339       int c;
340       char * temp;
341       char step[MAX_LOCATION];
342
343       //StringArray steps { growingFactor = 4 };
344       Array<String> steps { };
345       FileSystemNode result = null;
346       FileSystemNode node = null;
347
348       temp = CopyString(location);
349       while(temp[0])
350       {
351          GetLastDirectory(temp, step);
352          StripLastDirectory(temp, temp);
353          steps.Add(CopyString(step));
354       }
355
356       for(c = steps.count - 1; c >= 0; c--)
357       {
358          char * t = steps[c];
359          node = Find(steps[c], node);
360          if(!node)
361             break;
362          //Select(node);
363       }
364       if(node)
365       {
366          result = node;
367          Select(result);
368       }
369
370       steps.Free();
371       delete temp;
372       delete steps;
373
374       return result;
375    }
376
377    FileSystemNode Find(const char * name, FileSystemNode parent)
378    {
379       FileSystemNode node = null;
380       FileSystemNode result = null;
381       if(!parent/* && !strcmp(name, "/")*/)
382       {
383          DataRow row;
384          for(row = list.firstRow; row; row = row.next)
385          {
386             node = (FileSystemNode)row.tag;
387             if(node.name && !fstrcmp(node.name, name))
388                break;
389          }
390          if(node)
391             result = node;
392          //result = root;
393       }
394       else
395       {
396          FileSystemNode start = parent ? parent : root;
397          if(!start.bits.loaded || !start.bits.childrenLoaded)
398             LoadTreeNode(start);
399          for(node = start.children.first; node; node = node.next)
400             if(node.name && !fstrcmp(node.name, name))
401                break;
402          if(node)
403             result = node;
404       }
405       return result;
406    }
407
408    void Clear()
409    {
410       list.Clear();
411    }
412
413    void Refresh()
414    {
415       Load();
416    }
417
418    bool MenuOpen(MenuItem selection, Modifiers mods)
419    {
420       OpenNode();
421    }
422
423    bool MenuReplaceListItemByContainingDir(MenuItem selection, Modifiers mods)
424    {
425       bool result = true;
426       //FileSystemBoxSelection selection = this.selection.Copy(); // TOFIX compiler bug -- FileSystemBox.c -- ../libede/src/FileSystemBox.ec:420:49: error: ‘selection’ redeclared as different kind of symbol        
427       FileSystemBoxSelection sel = this.selection.Copy();
428       FileSystemNode node = sel.node;
429       char newPath[MAX_LOCATION];
430       StripLastDirectory(node.path, newPath);
431       //node.path = newPath;
432       //node.
433       //if(node && node.type.isFolder && bits.navigateFolders)
434       //   property::path = node.path;
435       delete sel;
436       return result;
437    }
438
439    bool MenuReplaceListItemByChild(MenuItem selection, Modifiers mods)
440    {
441       bool result = true;
442       //FileSystemBoxSelection selection = this.selection.Copy(); // TOFIX compiler bug -- FileSystemBox.c -- ../libede/src/FileSystemBox.ec:420:49: error: ‘selection’ redeclared as different kind of symbol        
443       FileSystemBoxSelection sel = this.selection.Copy();
444       FileSystemNode node = sel.node;
445       char newPath[MAX_LOCATION];
446       StripLastDirectory(node.path, newPath);
447       //node.path = newPath;
448       //node.
449       //if(node && node.type.isFolder && bits.navigateFolders)
450       //   property::path = node.path;
451       delete sel;
452       return result;
453    }
454
455 private:
456    FileSystemBoxBits bits;
457
458    char * path;
459    char * extensions;
460    Array<String> comparedPaths;
461
462    BitmapResource fileIcons[_FileType];
463    BitmapResource compIcons[countOfCompIconNames]; // todo: fix this limitation
464
465    Bitmap bitmap;
466    //BitmapArray bitmaps { growingFactor = 16 };
467
468    FileSystemBox()
469    {
470       path = CopyString("");
471       InitFileIcons();
472       InitCompIcons(); // todo: these icons should not be initialize, they should be set
473                        //       or at least initalized when the comparison listing is requested
474                        //       and we know how many paths are being compared.
475       list.AddField(nameField);
476       bits.autoLoad = true;
477       //iteratorClass = class(FileSystemIterator);
478    }
479
480    ~FileSystemBox()
481    {
482       delete extensions;
483       delete path;
484    }
485
486    watch(background)
487    {
488       list.background = background;
489    };
490
491    void InitFileIcons()
492    {
493       _FileType c;
494       for(c = 0; c < _FileType::enumSize; c++)
495       {
496          fileIcons[c] = BitmapResource { fileIconNames[c], alphaBlend = true };
497          AddResource(fileIcons[c]);
498       }
499    }
500
501    void InitCompIcons()
502    {
503       _FileType c;
504       for(c = 0; c < countOfCompIconNames; c++)
505       {
506          compIcons[c] = BitmapResource { compIconNames[c], alphaBlend = true };
507          AddResource(compIcons[c]);
508       }
509    }
510
511    DataField nameField { header = "Name", dataType = "FileSystemNode", width = 240, userData = this, freeData = false/*, editable = true*/; };
512    DataField pathField { header = "Location", dataType = /*"String"*/ "char *", width = 300, freeData = true };
513    DataField typeField { header = "Type", dataType = /*"String"*/ "char *", width = 40, freeData = false };
514    DataField sizeField { header = "Size", dataType = "FileSize", width = 96, alignment = right, freeData = false };
515    DataField modifiedField { header = "Modified", dataType = "SecSince1970", width = 96, alignment = right, freeData = false };
516
517    bool OnPostCreate()
518    {
519       if(bits.autoLoad)
520       {
521          if(!path)
522          {
523             char wd[MAX_LOCATION];
524             GetWorkingDir(wd, sizeof(wd));
525             property::path = wd;
526          }
527          Load();
528       }
529       return true;
530    }
531
532    ListBox list
533    {
534       this;
535
536       borderStyle = none;
537       hasHorzScroll = true;
538       hasVertScroll = true;
539       fullRowSelect = false;
540       sortable = true;
541       alwaysHighLight = true;
542
543       anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
544
545       // WHY is this not working ?
546       /*void OnResize(int width, int height)
547       {
548          if(vertScroll.visible)
549             nameField.width = width - vertScroll.size.w;
550          else
551             nameField.width = width;
552       }*/
553
554       bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed)
555       {
556          if(row)
557          {
558             FileSystemNode node = (FileSystemNode)row.tag;
559             FileSystemNode child;
560             if(collapsed)
561             {
562                /*
563                for(child = node.children.last; child; child = node.children.last)
564                {
565                   listBox.DeleteRow(child.row);
566                   child.Free();
567                   delete child;
568                }
569                node.childrenLoaded = false;
570                */
571             }
572             else
573             {
574                if(!node.bits.loaded || !node.bits.childrenLoaded)
575                {
576                   LoadTreeNode(node);
577                   //list.Sort(nameField, 1);
578                   //node.
579                }
580                for(child = node.children.first; child && child.next; child = child.next);
581                if(child)
582                   child.EnsureVisible(false);
583             }
584          }
585          return true;
586       }
587       
588       bool NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods)
589       {
590          DataRow row = listBox.currentRow;
591          if(row)
592          {
593             FileSystemNode node = (FileSystemNode)row.tag;
594             if(node)
595             {
596                PopupMenu popup;
597                Menu menu { };
598
599                if(NotifyNodeMenu)
600                   NotifyNodeMenu(master, this, menu, selection);
601                else
602                {
603                   char * text;
604
605                   text = PrintString("Open ", node.name);
606                   MenuItem { menu, text, o, NotifySelect = MenuOpen, disabled = false }; //delete text;
607
608                   if(node.bits.isListItem/* && TODO: unless node is at root location*/)
609                   {
610                      MenuDivider { menu };
611                      MenuItem { menu, "Replace by Parent\tCtrl+R", r, NotifySelect = MenuReplaceListItemByContainingDir, disabled = false };
612                   }
613                   else if(bits.mode == list)
614                   {
615                      MenuDivider { menu };
616                      MenuItem { menu, "Replace List Item\tCtrl+R", r, NotifySelect = MenuReplaceListItemByChild, disabled = false };
617                   }
618                   MenuDivider { menu };
619                   MenuItem { menu, "Cut\tCtrl+X", t, NotifySelect = null, disabled = false };
620                   MenuItem { menu, "Copy\tCtrl+C", c, NotifySelect = null, disabled = false };
621                   MenuItem { menu, "Paste\tCtrl+V", p, NotifySelect = null, disabled = false /*!clipboard*/ };
622                   MenuItem { menu, "Delete\tDel", d, NotifySelect = null, disabled = false };
623                   //MenuDivider { menu };
624                }
625
626                popup = PopupMenu
627                   {
628                      master = this, menu = menu,
629                      position = { 
630                         x + clientStart.x + absPosition.x - guiApp.desktop.position.x, 
631                         y + clientStart.y + absPosition.y - guiApp.desktop.position.y }
632                   };
633                popup.Create();
634             }
635          }
636          return true;
637       }
638
639       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
640       {
641          OldList rows;
642          OldLink item;
643
644          selection.nodes.Free();
645          list.GetMultiSelection(rows);
646          for(item = rows.first; item; item = item.next)
647          {
648             DataRow row = item.data;
649             FileSystemNode node = (FileSystemNode)row.tag;
650             selection.nodes.Add(node);
651             incref node;
652          }
653          rows.Free(null);
654          if(row)
655             selection.node = (FileSystemNode)row.tag;
656          else
657             selection.node = null;
658
659          if(selection.node && bits.preview)
660          {
661             //int pos;
662             FileSystemNode node = selection.node;
663             /*if(bitmap)
664                bitmap.Free();*/
665             delete bitmap;
666             if(node && node.type == pictureFile)
667             {
668                bitmap = Bitmap { };
669                bitmap.Load(node.path, null, displaySystem);
670             }
671
672             /*bitmaps.Clear();
673             bitmaps = BitmapArray { };
674             for(pos = 0; pos < selectedItems.count; pos++)
675             {
676                Bitmap bitmap { };
677                selItem = (ExplorerFileItem)selectedItems._[pos];
678                bitmap.Load(selItem.path, null, displaySystem);
679                //bitmaps.Add(bitmap);
680             }
681             if(node && node.type == pictureFile)
682             {
683                bitmap = Bitmap { };
684                bitmap.Load(node.path, null, displaySystem);
685             }*/
686
687             show.Update(null);
688             //NotifyItemSelect(master, view, item, selectedItems);
689          }
690
691          NotifyNodeSelect(listBox.parent.master, this, selection);
692          return true;
693       }
694
695       bool NotifyEditing(ListBox listBox, DataRow row)
696       {
697          if(row)
698          {
699             FileSystemNode node = (FileSystemNode)row.tag;
700          }
701          return true;
702       }
703
704       bool NotifyEdited(ListBox listBox, DataRow row)
705       {
706          if(row)
707          {
708             FileSystemNode node = (FileSystemNode)row.tag;
709          }
710          return true;
711       }
712
713       bool NotifyEditDone(ListBox listBox, DataRow row)
714       {
715          if(row)
716          {
717             FileSystemNode node = (FileSystemNode)row.tag;
718          }
719          return true;
720       }
721
722       bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
723       {
724          bool result = !(selection.node && selection.node.type.isFolder && bits.navigateFolders);
725          OpenNode();
726          return result;
727       }
728
729       bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
730       {
731          bool result;
732          if((SmartKey)key == enter)
733             result = OpenNode();
734          #if 0
735          else if((SmartKey)key == f2)
736             result = RenameNode();
737          #endif
738          else if((SmartKey)key == f2)
739          {
740             FileSystemNode node = selection.node;
741             node.row.Edit(nameField);
742          }
743          else
744             result = true;
745          return true;
746       }
747    };
748
749    PaneSplitter split
750    {
751       this;
752       //leftPane = list;
753       rightPane = show;
754       //split = 200;
755       scaleSplit = 0.5f;
756       tabCycle = true;
757       visible = false;
758    };
759
760    Window show
761    {
762       this;
763       visible = false;
764       borderStyle = none;
765       anchor = Anchor { top = 0, right = 0, bottom = 0 };
766
767       void OnRedraw(Surface surface)
768       {
769          FileSystemBox fsb = (FileSystemBox)parent;
770          if(fsb.bitmap)
771          {
772             int wBmp = fsb.bitmap.width;
773             int hBmp = fsb.bitmap.height;
774             int wWnd = fsb.show.clientSize.w;
775             int hWnd = fsb.show.clientSize.h;
776
777             int wList = 0;//fsb.list.size.w + fsb.split.size.w;
778
779             float scale = Min((float)(wWnd - 10) / wBmp, (float)(hWnd - 10) / hBmp);
780
781             int wDraw = (int)(wBmp * scale);
782             int hDraw = (int)(hBmp * scale);
783
784       #ifndef __linux__
785             surface.Filter(fsb.bitmap, (wWnd - wDraw) / 2, (hWnd - hDraw) / 2, 0, 0, wDraw, hDraw, wBmp, hBmp);
786       #else
787             // Until Filter / Stretch works with X
788             surface.Blit(fsb.bitmap, (wWnd - wBmp) / 2, (hWnd - hBmp) / 2, 0, 0, wBmp, hBmp);
789       #endif
790          }
791          else
792          {
793             surface.SetForeground(white);
794             surface.Area(0, 0, fsb.clientSize.w - 1, fsb.clientSize.h - 1);
795          }
796       }
797    }
798
799    bool OpenNode()
800    {
801       bool result = false;
802       FileSystemBoxSelection sel = this.selection.Copy();
803       //FileSystemNode node = selection.node;
804       for(node : sel.nodes)
805       {
806          sel.node = node;
807          if(node && node.type.isFolder && bits.navigateFolders)
808             property::path = node.path;
809          if(NotifyNodeOpen(this.master, this, sel) && !result)
810             result = true;
811       }
812       delete sel;
813       return result;
814    }
815
816    #if 0
817    bool RenameNode()
818    {
819       bool result;
820       //FileSystemBoxSelection selection = this.selection.Copy();
821       FileSystemNode node = selection.node;
822       //if(node && node.type.isFolder && bits.navigateFolders)
823       //   property::path = node.path;
824       // ------------------------------------------- working here ---------------------------
825       //node.row.Edit();
826       /*result = NotifyNodeRename(this.master, this, node);
827       if(result)
828       {
829          if(RenameFile(oldn, newn))
830          {
831             node.name = newn;
832          }
833       }*/
834       return result;
835    }
836    #endif
837
838    // Edit Menu
839    Menu editMenu { menu, "Edit", e };
840    MenuItem itemEditCut
841    {
842       editMenu, "Cut\tCtrl+X", t, disabled = true;
843
844       bool NotifySelect(MenuItem selection, Modifiers mods)
845       {
846          //EditCut();
847          return true;
848       }
849    };
850    MenuItem itemEditCopy
851    {
852       editMenu, "Copy\tCtrl+C", c, disabled = true;
853
854       bool NotifySelect(MenuItem selection, Modifiers mods)
855       {
856          //EditCopy();
857          return true;
858       }
859    };
860    MenuItem itemEditPaste
861    {
862       editMenu, "Paste\tCtrl+V", p;
863    
864       bool NotifySelect(MenuItem selection, Modifiers mods)
865       {
866          //EditPaste();
867          return true;
868       }
869    };
870    MenuItem itemEditDelete
871    {
872       editMenu, "Delete\tDel", d, disabled = true;
873
874       bool NotifySelect(MenuItem selection, Modifiers mods)
875       {
876          //EditDelete();
877          return true;
878       }
879    };
880
881    // WHY is this crashing ? 
882    /*void OnResize(int width, int height)
883    {
884       if(this && nameField)
885          nameField.width = width - 80;
886    }*/
887
888    void ChangeViewType()
889    {
890       list.Clear();
891       list.ClearFields();
892       list.resizable = bits.details || bits.pathColumn;
893       list.moveFields = bits.details || bits.pathColumn;
894       list.hasHeader = bits.details || bits.pathColumn;
895       list.AddField(nameField);
896       if(bits.pathColumn)
897          list.AddField(pathField);
898       if(bits.details)
899       {
900          list.AddField(typeField);
901          list.AddField(sizeField);
902          list.AddField(modifiedField);
903       }
904    }
905
906    void Load()
907    {
908       // TODO: fix this!
909       // this is crashing in for designer when details = true // can't save the file, always yields a crash
910       /*if(list && created)
911       {
912          list.ClearFields();
913          list.AddField(nameField);
914          if(bits.details)
915          {
916             list.AddField(typeField);
917             list.AddField(sizeField);
918          }
919       }*/
920       list.Clear();
921       if(comparedPaths && !bits.treeBranches)
922          LoadComparedList();
923       else
924       {
925          FileAttribs pathAttribs = FileExists(path);
926          if(pathAttribs)
927          {
928             if(pathAttribs.isDirectory)
929             {
930                if(bits.treeBranches)
931                   LoadTreeDirectory();
932                else
933                {
934                   if(iteratorClass)
935                      LoadListIterator();
936                   else
937                      LoadListDirectory();
938                }
939             }
940             else if(pathAttribs.isFile) // we assume this is a file list
941             {
942                File f = FileOpen(path, read);
943                if(f)
944                {
945                   if(bits.treeBranches)
946                      LoadTreeFileList(f);
947                   else
948                      LoadListFileList(f);
949                   delete f;
950                }
951                else
952                   MessageBoxTodo($"unable to open file list");
953             }
954             else
955                MessageBoxTodo($"path is not a directory nor is it a file");
956          }
957          else
958             MessageBoxTodo($"path does not exist");
959       }
960       list.Sort(nameField, 1);
961    }
962
963    void LoadTreeDirectory()
964    {
965       bool isRoot = !strcmp(path, "/");
966       char name[MAX_LOCATION];
967       FileSystemNode parent;
968       FileSystemNode node;
969       FileListing listing { path, extensions = extensions };
970
971       if(!isRoot)
972          GetLastDirectory(path, name);
973       else
974          name[0] = '\0';
975       
976       /*if(!path)
977          GetWorkingDir(startPath, sizeof(startPath));
978       else
979          strcpy(path, startPath);*/
980       
981       bits.mode = directory;
982
983       delete root;
984 #ifdef __WIN32__
985       if(isRoot)
986       {
987          root = FileSystemNode { bits.loaded = true, bits.childrenLoaded = true };
988          AddTreeNode(root, true, false, false, null);
989          while(listing.Find())
990          {
991             int len = strlen(listing.name);
992             char info[MAX_LOCATION];
993             char name[MAX_LOCATION];
994             if(listing.stats.attribs.isDrive &&
995                   len > 3 && !strncmp(&listing.name[1], ": [", 3))
996             {
997                strncpy(name, listing.name, 2);
998                name[2] = 0;
999                strncpy(info, &listing.name[4], len - 5);
1000                info[len - 5] = 0;
1001             }
1002             else
1003             {
1004                strcpy(name, listing.name);
1005                info[0] = 0;
1006             }
1007
1008             parent =
1009                   MakeFileSystemNode(
1010                         listing.stats,
1011                         name,
1012                         listing.path,
1013                         false, bits.previewPictures, false,
1014                         displaySystem);
1015             if(info[0])
1016                parent.info = info; //CopyString(info);
1017             parent.bits.loaded = true;
1018             AddTreeNode(
1019                   parent,
1020                   !listing.stats.attribs.isDirectory,
1021                   false,
1022                   listing.stats.attribs.isDirectory,
1023                   root);
1024             if(!listing.stats.attribs.isDirectory)
1025                parent.bits.childrenLoaded = true;
1026          }
1027
1028          node = FileSystemNode { name = msNetwork, type = network };
1029          AddTreeNode(node, false, false, true, null);
1030          node.row.collapsed = true;
1031       }
1032       else
1033 #endif
1034       {
1035          FileStats stats;
1036          FileGetStats(path, stats);
1037          root = MakeFileSystemNode(stats, name, path, false, bits.previewPictures, false, displaySystem);
1038          AddTreeNode(root, false, false, true, null);
1039          LoadTreeNode(root);
1040       }
1041
1042       if(isRoot)
1043       {
1044          root.type = computer;
1045          root.label = rootName;
1046       }
1047
1048       list.Sort(nameField, 1);
1049       list.SelectRow(root.row);
1050    }
1051
1052    void LoadListDirectory()
1053    {
1054       FileListing listing { path, extensions = extensions };
1055
1056       bits.mode = directory;
1057       while(listing.Find())
1058          ProcessListItem(listing.name, listing.path, listing.stats, false);
1059    }
1060
1061    void LoadListFileList(File f)
1062    {
1063       char line[65536];
1064       bits.mode = list;
1065       while(f.GetLine(line, 65536))
1066       {
1067          FileStats stats {};
1068          char name[MAX_FILENAME];
1069          FileGetStats(line, stats);
1070          GetLastDirectory(line, name);
1071          ProcessListItem(name, line, stats, true);
1072       }
1073    }
1074
1075    void LoadTreeFileList(File f)
1076    {
1077       char line[65536];
1078       bits.mode = list;
1079       while(f.GetLine(line, 65536))
1080       {
1081          FileStats stats {};
1082          char name[MAX_FILENAME];
1083          FileSystemNode node;
1084          FileGetStats(line, stats);
1085          GetLastDirectory(line, name);
1086          node = ProcessTreeItem(name, line, stats, node);
1087       }
1088    }
1089
1090    void LoadListIterator()
1091    {
1092       FileSystemIterator iterator = eInstance_New(iteratorClass);
1093       if(iterator)
1094       {
1095          iterator.owner = this;
1096          iterator.OnObject = ListIterator_OnObject;
1097          //iterator.OnLeavingDirectory = ListIterator_OnLeavingDirectory;
1098          NotifyIteratorInit(master, this, iterator);
1099          iterator.Iterate(path, true);
1100          delete iterator;
1101       }
1102    }
1103
1104    bool ListIterator_OnObject(char * name, char * path, FileStats stats, bool isRootObject)
1105    {
1106       ProcessListItem(name, path, stats, false);
1107       return false;
1108    }
1109
1110    //void ListIterator_OnLeavingDirectory(char * path) { }
1111
1112    void ProcessListItem(char * name, char * path, FileStats stats, bool isListItem)
1113    {
1114       if((!bits.foldersOnly && !bits.filesOnly) || (bits.foldersOnly && stats.attribs.isDirectory) || (bits.filesOnly && stats.attribs.isFile))
1115       {
1116          FileSystemNode node = MakeFileSystemNode(stats, name, path, false, bits.previewPictures, isListItem, displaySystem);
1117          AddNode(node);
1118       }
1119    }
1120
1121    FileSystemNode ProcessTreeItem(char * name, char * path, FileStats stats, FileSystemNode parent)
1122    {
1123       FileSystemNode node = MakeFileSystemNode(stats, name, path, false, bits.previewPictures, true, displaySystem);
1124       AddTreeNode(parent, false, false, true, null);
1125       //LoadTreeNode(node);
1126       return node;
1127    }
1128
1129    void LoadTreeNode(FileSystemNode node)
1130    {
1131       if(!node.bits.loaded)
1132       {
1133          char path[MAX_LOCATION];
1134          node.GetPath(path);
1135          {
1136             FileListing listing { path, extensions = extensions };
1137             if(node.children.count == 1)
1138                DeleteNode(node.children.first);
1139
1140             while(listing.Find())
1141             {
1142                char * test;
1143                FileSystemNode child = null;
1144                if(!listing.stats.attribs.isRemovable && ((!bits.foldersOnly && !bits.filesOnly) ||
1145                   (bits.foldersOnly && listing.stats.attribs.isDirectory) ||
1146                   (bits.filesOnly && listing.stats.attribs.isFile)))
1147                   child = MakeAndAddToTreeFileSystemNodeFromFileListing(listing, node);
1148                if(child)
1149                   NodeChildLoad(child, node);
1150                test = child.name;
1151                if(!test)
1152                   PrintLn("error");
1153             }
1154          }
1155          node.bits.childrenLoaded = true;
1156          node.bits.loaded = true;
1157          node.row.SortSubRows(false);
1158       }
1159       else if(!node.bits.childrenLoaded)
1160       {
1161          FileSystemNode child;
1162          if(node.children.first)
1163          {
1164             for(child = node.children.first; child; child = child.next)
1165             {
1166                if(!child.bits.loaded)
1167                   LoadTreeNode(child);
1168                else if(!child.bits.childrenLoaded)
1169                   NodeChildLoad(child, node);
1170             }
1171             node.bits.childrenLoaded = true;
1172             node.row.SortSubRows(false);
1173          }
1174       }
1175    }
1176
1177    void NodeChildLoad(FileSystemNode parent, FileSystemNode node)
1178    {
1179       char path[MAX_LOCATION];
1180       parent.GetPath(path);
1181       if(bits.textFileLinesStyle && FileExists(path).isFile)
1182       {
1183          PrintLn("Test");
1184       }
1185       else
1186       {
1187          bool added = false;
1188          FileListing listing { path, extensions = extensions };
1189          while(listing.Find())
1190          {
1191             char * test;
1192             FileSystemNode child = null;
1193             if((!bits.foldersOnly && !bits.filesOnly) ||
1194                (bits.foldersOnly && listing.stats.attribs.isDirectory) ||
1195                (bits.filesOnly && listing.stats.attribs.isFile))
1196                child = MakeAndAddToTreeFileSystemNodeFromFileListing(listing, parent);
1197             if(child)
1198                added = true;
1199             test = child.name;
1200             if(!test)
1201                PrintLn("error");
1202          }
1203          if(!added)
1204             added = true;
1205       }
1206       parent.bits.childrenLoaded = true;
1207    }
1208
1209    void LoadComparedList()
1210    {
1211       int c, cmp/*, smallest*/, icon;//, equalCount;
1212       int count = comparedPaths ? comparedPaths.count : 0;
1213       //bool allDone = false;
1214       bool not;
1215       FileStats stats;
1216       char path[MAX_LOCATION];
1217       //Array<ComparisonState> states { };
1218       //Array<FileListing> listings { };
1219       //Array<int> equals { };
1220       //Array<MapNode<String, int>> mapNodes { };
1221
1222       //Array<Map<String, int>> lists { };
1223       //Map<int, bool> equals{ };
1224
1225
1226       MapNode<String, /*Map<int, */Array<int>> na;
1227       //MapNode<int, int> nb;
1228       Map<String, /*Map<int, */Array<int>> names { };
1229       //Map<String, Array<bool>> names { };
1230       //Map<String, bool[16]> names { }; // does not seem to be working
1231       //Map<String, BoolArrayInt> names { };
1232       {
1233          for(c = 0; c < comparedPaths.count; c++)
1234          {
1235             FileListing listing { comparedPaths[c], extensions = extensions };
1236             while(listing.Find())
1237             {
1238                /*Map<int, int>*/Array<int> m = names[listing.name];
1239                if(!m)
1240                   m = { };
1241                names[listing.name] = m;
1242                /*/m[c] = */m.Add(c);
1243             }
1244          }
1245          /* // compiles and should work but better solution?
1246          for(c = 0; c < comparedPaths.count; c++)
1247          {
1248             FileListing listing { comparedPaths[c], extensions = extensions };
1249             while(listing.Find())
1250             {
1251                Array<bool> a = names[listing.name];
1252                if(!a)
1253                   a = { };
1254                names[listing.name] = a;
1255                a[c] = true;
1256             }
1257          }
1258          */
1259          /* // does not seem to be working
1260          for(c = 0; c < comparedPaths.count; c++)
1261          {
1262             FileListing listing { comparedPaths[c], extensions = extensions };
1263             while(listing.Find())
1264             {
1265                names[listing.name][c] = true;
1266             }
1267          }
1268          */
1269          /*
1270          if(comparedPaths.count > 0)
1271          {
1272             FileListing listing { comparedPaths[0], extensions = extensions };
1273             while(listing.Find())
1274             {
1275                // should be able to just do names[listing.name]._0 = true;
1276                BoolArrayInt bai = names[listing.name];
1277                bai._0 = true;
1278                names[listing.name] = bai;
1279             }
1280          }
1281          if(comparedPaths.count > 1)
1282          {
1283             FileListing listing { comparedPaths[1], extensions = extensions };
1284             while(listing.Find())
1285             {
1286                // should be able to just do names[listing.name]._1 = true;
1287                BoolArrayInt bai = names[listing.name];
1288                bai._1 = true;
1289                names[listing.name] = bai;
1290             }
1291          }
1292          */
1293          // and so on....
1294       }
1295
1296       /*
1297       for(dirPath : comparedPaths)
1298       {
1299          char * p = dirPath;
1300          if(FileExists(dirPath).isDirectory)
1301          {
1302             FileListing listing { dirPath, extensions = extensions };
1303             //MapNode<String, int> mn;
1304             Map<String, int> list { };
1305             //states.Add(listing.Find() == true ? matching : endOfListing);
1306             while(listing.Find())
1307                list[listing.name] = 0;
1308             //for(mn = ; mn; mn = mn.next)
1309             //mn = list.root.minimum;
1310             mapNodes.Add(/-*mn*-/list.root.minimum);
1311             lists.Add(list);
1312             //PrintLn(dirPath, " -- .Find() -- ", states[states.count-1] == matching ? listing.name : "endOfListing*");
1313             //listings.Add(listing);
1314
1315             {
1316                MapNode<String, int> mn;
1317                PrintLn("------------- DIR LISTING FOR ", dirPath);
1318                for(mn = list.root.minimum; mn; mn = mn.next)
1319                {
1320                   PrintLn(mn.key);
1321                }
1322             }
1323          }
1324       }
1325       */
1326
1327       for(na = names.root.minimum; na; na = na.next)
1328       {
1329          /*Map<int, */Array<int> equals = na.value;
1330          //MapNode<int, int> nb;
1331       /*
1332       while(!allDone)
1333       {
1334          smallest = 0;
1335          equals.Add(0);
1336          for(c = 1; c < count; c++)
1337          {
1338             //if(states[c] == endOfListing) continue;
1339             if(!mapNodes[c]) continue;
1340             // todo: use better comparison method
1341             //       it should compare file type (dir/file) before
1342             //       comparing file name.
1343             //       should also provide alternative methods
1344             //       of comparison including ones that consider
1345             //       date changes as differences of some kind.
1346             //       pethaps a OnCompare(a, b) to allow implementation
1347             //       of custom methods of comparison.
1348             // note: this (or these) method(s) depend on files
1349             //       being listed in sorted order by FileListing.
1350             //       different comparison methods should have
1351             //       appropriatly different sorting in FileListing.
1352             //
1353             //cmp = strcmp(listings[smallest].name, listings[c].name);
1354             cmp = fstrcmp(mapNodes[smallest].key, mapNodes[c].key);
1355             PrintLn("COMPARING - ", mapNodes[smallest].key, " and ", mapNodes[c].key);
1356             if(cmp == 0)
1357                equals.Add(c);
1358                //equals[c] = true;
1359             else if(cmp > 0)
1360             {
1361                smallest = c;
1362                equals.size = 0;
1363                equals.Add(c);
1364             }
1365          }
1366
1367       */
1368          if(equals.count == count) // all are equal, no diff icon
1369          {
1370             icon = 0;
1371             not = false;
1372          }
1373          else if(equals.count == count-1) // all are equal but one, not-sign icon for singled out missing
1374          {
1375             int i;
1376             /*
1377             for(nb = equals.root.minimum, i = 0; nb; nb = nb.next, i++)
1378             {
1379                if(i != nb.key)
1380                */
1381             for(i = 0; i < equals.count; i++)
1382             {
1383                if(i != equals[i])
1384                {
1385                   icon = i+1;
1386                   break;
1387                }
1388             }
1389             //if(!nb)
1390             if(i == equals.count)
1391                icon = count;
1392             not = true;
1393          }
1394          else if(equals.count == 1) // only one is present, all others missing, present-sign for singled out present
1395          {
1396             //icon = equals.root.minimum.key+1;
1397             icon = equals[0]+1;
1398             not = false;
1399          }
1400          else // mixed
1401          {
1402             icon = 0; // todo
1403             not = true;
1404          }
1405 #if 0
1406          // or
1407          if(equals.count == count) // all are equal, no diff icon
1408             ;
1409          else if(count/2 - equals.count < 0) // more than half are equal, use not-sign icons for all missing
1410             ;
1411          else // less than half are equal, use present-sign icons for all present
1412             ;
1413 #endif
1414
1415          /*if((!bits.foldersOnly && !bits.filesOnly) ||
1416             (bits.foldersOnly && listings[smallest].stats.attribs.isDirectory) ||
1417             (bits.filesOnly && listings[smallest].stats.attribs.isFile))*/
1418          strcpy(path, comparedPaths[/*smallest*/equals[0]]);
1419          PathCat(path, /*mapNodes[smallest].key*/na.key);
1420          FileGetStats(path, stats);
1421          if((!bits.foldersOnly && !bits.filesOnly) ||
1422             (bits.foldersOnly && stats.attribs.isDirectory) ||
1423             (bits.filesOnly && stats.attribs.isFile))
1424          {
1425             FileSystemNode node =
1426                   MakeComparedFileSystemNode(
1427                         stats,
1428                         /*mapNodes[smallest].key*/na.key,
1429                         path,
1430                         false, bits.previewPictures,
1431                         icon, not, equals,
1432                         displaySystem);
1433             AddNode(node);
1434          }
1435       /*
1436          for(equal : equals)
1437          {
1438             mapNodes[equal] = mapNodes[equal].next;
1439             //states[equal] = listings[equal].Find() == true ? matching : endOfListing;
1440             //PrintLn(comparedPaths[equal], " -- .Find() -- ", states[equal] == matching ? listings[equal].name : "endOfListing*");
1441          }
1442          equals.size = 0;
1443          //for(c = 0; c < count && states[c] == endOfListing; c++);
1444          for(c = 0; c < count && !mapNodes[c]; c++);
1445          if(c == count)
1446             allDone = true;
1447       */
1448       }
1449       list.Sort(nameField, 1);
1450    }
1451
1452    void AddNode(FileSystemNode node)
1453    {
1454       DataRow row = list.AddRow();
1455       row.tag = (int)node;
1456       node.row = row;
1457       incref node;
1458       row.SetData(nameField, node);
1459       if(bits.pathColumn)
1460       {
1461          char path[MAX_LOCATION];
1462          StripLastDirectory(node.path, path);
1463          row.SetData(pathField, CopyString(path));
1464       }
1465       if(bits.details)
1466       {
1467          if(node.type.isFile)
1468          {
1469             row.SetData(typeField, node.extension);
1470             row.SetData(sizeField, /*(void *)*/node.stats.size);
1471          }
1472          row.SetData(modifiedField, node.stats.modified);
1473       }
1474    }
1475
1476    FileSystemNode MakeAndAddToTreeFileSystemNodeFromFileListing(FileListing listing, FileSystemNode parent)
1477    {
1478       FileSystemNode result = null;
1479       /*if((!bits.foldersOnly && !bits.filesOnly) ||
1480          (bits.foldersOnly && listing.stats.attribs.isDirectory) ||
1481          (bits.filesOnly && listing.stats.attribs.isFile))*/
1482       /*if(!listing.stats.attribs.isRemovable && ((!bits.foldersOnly && !bits.filesOnly) ||
1483          (bits.foldersOnly && listing.stats.attribs.isDirectory) ||
1484          (bits.filesOnly && listing.stats.attribs.isFile)))*/
1485       {
1486          bool textFileLinesStyle = false;
1487          char * test = listing.name;
1488          if(!test)
1489             PrintLn("error");
1490          result = MakeFileSystemNode(listing.stats, listing.name, listing.path, false, bits.previewPictures, false, displaySystem);
1491          test = result.name;
1492          if(!test)
1493             PrintLn("error");
1494          if(bits.textFileLinesStyle)
1495          {
1496             char ext[MAX_LOCATION];
1497             GetExtension(listing.name, ext);
1498             if(!strcmpi(ext, "txt") || !strcmpi(ext, "text"))
1499                textFileLinesStyle = true;
1500          }
1501          //AddTreeNode(result, true, false, textFileLinesStyle, parent);
1502          AddTreeNode(result, !textFileLinesStyle && listing.stats.attribs.isFile, false, !listing.stats.attribs.isFile || textFileLinesStyle, parent);
1503          test = result.name;
1504          if(!test)
1505             PrintLn("error");
1506       }
1507       return result;
1508    }
1509
1510    void AddTreeNode(
1511       FileSystemNode node,
1512       bool loaded,
1513       bool childrenLoaded,
1514       bool addLoader,
1515       FileSystemNode addTo)
1516    {
1517       DataRow row = (addTo && addTo.row) ? addTo.row.AddRow() : list.AddRow();
1518       if(addTo)
1519       {
1520          node.parent = addTo;
1521          node.indent = addTo.indent + 1;
1522          addTo.children.Add(node);
1523       }
1524       row.tag = (int)node;
1525       node.row = row;
1526       row.SetData(null, node);
1527       if(bits.pathColumn)
1528       {
1529          char path[MAX_LOCATION];
1530          StripLastDirectory(node.path, path);
1531          row.SetData(pathField, CopyString(path));
1532       }
1533       if(bits.details)
1534       {
1535          if(node.type.isFile)
1536          {
1537             row.SetData(typeField, node.extension);
1538             row.SetData(sizeField, /*(void *)*/node.stats.size);
1539          }
1540          row.SetData(modifiedField, node.stats.modified);
1541       }
1542
1543       node.bits.loaded = loaded;
1544       node.bits.childrenLoaded = childrenLoaded;
1545       if(addLoader)
1546          //AddTreeNode(FileSystemNode { }, false, false, node); // why would this create a compile error?
1547          AddTreeNode(FileSystemNode { type = none, name = "Loader" }, false, false, false, node);
1548
1549       if(node.indent > 0 || bits.mode == list)
1550          row.collapsed = true;
1551       else if(node.type == folder)
1552          node.type = folderOpen;
1553    }
1554
1555    void DeleteNode(FileSystemNode node)
1556    {
1557       FileSystemNode child;
1558       if(treeBranches)
1559       {
1560          for(; (child = node.children.first); )
1561             DeleteNode(child);
1562       }
1563       list.DeleteRow(node.row);
1564       node.Delete();
1565       //delete node;
1566       //Update(null);
1567    }
1568 }
1569
1570 enum ComparisonState { endOfListing, matching };
1571
1572 /*
1573 #if 0
1574 class ExplorerView : FileSystemBox
1575 {
1576    borderStyle = none;
1577    hasHorzScroll = false;
1578    hasVertScroll = false;
1579
1580    virtual void Load(FileSystemNode parent);
1581    virtual void Refresh();
1582
1583    virtual void LaunchNotifyItemSelect(Window master, ExplorerView view, ExplorerFileItem item, ExplorerFileItemArray selectedItems)
1584    {
1585       view.NotifyItemSelect(master, view, item, selectedItems);
1586    }
1587
1588    virtual bool Window::NotifyItemSelect(ExplorerView view, ExplorerFileItem item, ExplorerFileItemArray selectedItems);
1589    virtual bool Window::NotifyItemOpen(ExplorerView view, ExplorerFileItem item);
1590
1591    ListBox list
1592    {
1593       master = master, parent = this;
1594       //this, master;
1595       borderStyle = none;
1596       hasHorzScroll = true;
1597       hasVertScroll = true;
1598       resizable = true;
1599       sortable = true;
1600       fullRowSelect = false;
1601       multiSelect = true;
1602
1603       anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
1604
1605       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
1606       {
1607          ExplorerView view = (ExplorerView)listBox.parent;
1608          if(listBox.currentRow)
1609          {
1610             DataRow listRow;
1611             ExplorerFileItemArray selectedItems { growingFactor = 16 };
1612             for(listRow = listBox.firstRow; listRow; listRow = listRow.next)
1613                if(listRow.selected)
1614                   selectedItems.Add((ExplorerFileItem)listRow.tag);
1615             //view.NotifyItemSelect(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag);
1616             view.LaunchNotifyItemSelect(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag, selectedItems);
1617          }
1618          return true;
1619       }
1620
1621       bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
1622       {
1623          ExplorerView view = (ExplorerView)listBox.parent;
1624          view.NotifyItemOpen(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag);
1625          return false;
1626       }
1627
1628       bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
1629       {
1630          if((SmartKey)key == enter)
1631          {
1632             ExplorerView view = (ExplorerView)listBox.parent;
1633             view.NotifyItemOpen(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag);
1634          }
1635          return true;
1636       }
1637    };
1638
1639    ExplorerView()
1640    {
1641    }
1642 }
1643 #endif
1644
1645 #if 0
1646 class ExplorerViewList : ExplorerView
1647 {
1648
1649    FileSystemNode location;
1650
1651 public:
1652
1653    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
1654
1655    ExplorerViewDetails()
1656    {
1657       list.AddField(nameField);
1658    }
1659
1660    void Refresh()
1661    {
1662       Load(location);
1663    }
1664
1665    void Load(FileSystemNode location)
1666    {
1667       char path[MAX_LOCATION];
1668       this.location = location;
1669       location.GetPath(path);
1670       {
1671          FileListing listing { path };
1672          
1673          ExplorerFileItem item;
1674          DataRow row;
1675
1676          list.Clear();
1677
1678          while(listing.Find())
1679          {
1680             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
1681
1682             row = list.AddRow();
1683             row.tag = (int)item;
1684             row.SetData(nameField, item);
1685          }
1686          list.Sort(nameField, 1);
1687       }
1688    }
1689 }
1690 #endif
1691
1692 #if 0
1693 class ExplorerViewDetails : ExplorerView
1694 {
1695    list.hasHeader = true;
1696    list.moveFields = true;
1697    list.resizable = true;
1698    list.sortable = true;
1699
1700    FileSystemNode location;
1701
1702 public:
1703
1704    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
1705    DataField typeField { header = "Type", dataType = /-*"String"*-/ "char *", width = 40 };
1706    DataField sizeField { header = "Size", dataType = "FileSize", width = 96, alignment = right };
1707
1708    ExplorerViewDetails()
1709    {
1710       list.AddField(nameField);
1711       list.AddField(typeField);
1712       list.AddField(sizeField);
1713    }
1714
1715    void Refresh()
1716    {
1717       Load(location);
1718    }
1719
1720    void Load(FileSystemNode location)
1721    {
1722       char path[MAX_LOCATION];
1723       this.location = location;
1724       location.GetPath(path);
1725       {
1726          FileListing listing { path };
1727          
1728          ExplorerFileItem item;
1729          DataRow row;
1730
1731          list.Clear();
1732
1733          while(listing.Find())
1734          {
1735             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
1736
1737             row = list.AddRow();
1738             row.tag = (int)item;
1739             row.SetData(nameField, item);
1740             row.SetData(typeField, CopyString(item.extension));
1741             row.SetData(sizeField, (uint)listing.stats.size);
1742          }
1743          list.Sort(nameField, 1);
1744       }
1745    }
1746 }
1747 #endif
1748
1749 #if 0
1750 class ExplorerViewIcons : ExplorerView
1751 {
1752
1753    FileSystemNode location;
1754
1755 public:
1756
1757    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
1758
1759    ExplorerViewDetails()
1760    {
1761       list.AddField(nameField);
1762    }
1763
1764    void Refresh()
1765    {
1766       Load(location);
1767    }
1768
1769    void Load(FileSystemNode location)
1770    {
1771       char path[MAX_LOCATION];
1772       this.location = location;
1773       location.GetPath(path);
1774       {
1775          FileListing listing { path };
1776          
1777          ExplorerFileItem item;
1778          DataRow row;
1779
1780          list.Clear();
1781
1782          while(listing.Find())
1783          {
1784             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
1785
1786             row = list.AddRow();
1787             row.tag = (int)item;
1788             row.SetData(nameField, item);
1789          }
1790          list.Sort(nameField, 1);
1791       }
1792    }
1793 }
1794 #endif
1795
1796 #if 0
1797 class ExplorerViewCards : ExplorerView
1798 {
1799
1800    FileSystemNode location;
1801
1802 public:
1803
1804    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
1805
1806    ExplorerViewDetails()
1807    {
1808       list.AddField(nameField);
1809    }
1810
1811    void Refresh()
1812    {
1813       Load(location);
1814    }
1815
1816    void Load(FileSystemNode location)
1817    {
1818       char path[MAX_LOCATION];
1819       this.location = location;
1820       location.GetPath(path);
1821       {
1822          FileListing listing { path };
1823          
1824          ExplorerFileItem item;
1825          DataRow row;
1826
1827          list.Clear();
1828
1829          while(listing.Find())
1830          {
1831             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
1832
1833             row = list.AddRow();
1834             row.tag = (int)item;
1835             row.SetData(nameField, item);
1836          }
1837          list.Sort(nameField, 1);
1838       }
1839    }
1840 }
1841 #endif
1842
1843 #if 0
1844 public class BitmapArray : RedjArray
1845 {
1846    type = class(Bitmap);
1847 public:
1848    Bitmap * const _;
1849    Bitmap * Add(Bitmap bitmap)
1850    {
1851       uint pos = _count;
1852       Append(1);
1853       _[pos] = bitmap;
1854       return &_[pos];
1855    }
1856    Bitmap * AddBefore(uint position, Bitmap bitmap)
1857    {
1858       Insert(position, 1);
1859       _[position] = bitmap;
1860       return &_[position];
1861    }
1862    void Clear()
1863    {
1864       int c;
1865       for(c = 0; c < _count; c++)
1866       {
1867          _[c].Free();
1868          delete _[c];
1869       }  
1870       count = 0;
1871       size = 0;
1872    }
1873 }
1874 #endif
1875
1876 #if 0
1877 class ExplorerViewShowcase : ExplorerView
1878 {
1879    list.anchor = Anchor { left = 0, top = 0, bottom = 0 };
1880    list.size = Size { w = 200 };
1881
1882    FileSystemNode location;
1883
1884 public:
1885
1886    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 180, editable = true, userData = this };
1887
1888    Bitmap bitmap;
1889    BitmapArray bitmaps { growingFactor = 16 };
1890
1891    Window show
1892    {
1893       this;
1894       borderStyle = none;
1895       anchor = Anchor { top = 0, right = 0, bottom = 0 };
1896
1897       void OnRedraw(Surface surface)
1898       {
1899          ExplorerViewShowcase view = (ExplorerViewShowcase)parent;
1900          if(view.bitmap)
1901          {
1902             int wBmp = view.bitmap.width;
1903             int hBmp = view.bitmap.height;
1904             int wWnd = clientSize.w;
1905             int hWnd = clientSize.h;
1906
1907             int wList = view.list.size.w + view.split.size.w;
1908             
1909             float scale = Min((float)(wWnd - 10) / wBmp, (float)(hWnd - 10) / hBmp);
1910             
1911             int wDraw = (int)(wBmp * scale);
1912             int hDraw = (int)(hBmp * scale);
1913
1914       #ifndef __linux__
1915             surface.Filter(view.bitmap, (wWnd - wDraw) / 2, (hWnd - hDraw) / 2, 0, 0, wDraw, hDraw, wBmp, hBmp);
1916       #else
1917             // Until Filter / Stretch works with X
1918             surface.Blit(view.bitmap, (wWnd - wDraw) / 2, (hWnd - hDraw) / 2, 0, 0, wDraw, hDraw);
1919       #endif
1920          }
1921          else
1922          {
1923             surface.SetForeground(white);
1924             surface.Area(0, 0, view.clientSize.w - 1, view.clientSize.h - 1);
1925          }
1926       }
1927    }
1928
1929    SplitWindow split
1930    {
1931       this;
1932       leftPane = list;
1933       rightPane = show;
1934       split = 200;
1935       tabCycle = true;
1936    };
1937
1938    ExplorerViewDetails()
1939    {
1940       list.AddField(nameField);
1941    }
1942
1943    void LaunchNotifyItemSelect(Window master, ExplorerViewShowcase view, ExplorerFileItem item, ExplorerFileItemArray selectedItems)
1944    {
1945       int pos;
1946       ExplorerFileItem selItem;
1947       if(view.bitmap)
1948          view.bitmap.Free();
1949       delete view.bitmap;
1950       if(item && item.type == pictureFile)
1951       {
1952          view.bitmap = Bitmap { };
1953          view.bitmap.Load(item.path, null, displaySystem);
1954       }
1955
1956       view.bitmaps.Clear();
1957       view.bitmaps = BitmapArray { };
1958       for(pos = 0; pos < selectedItems.count; pos++)
1959       {
1960          Bitmap bitmap { };
1961          selItem = (ExplorerFileItem)selectedItems._[pos]; 
1962          bitmap.Load(selItem.path, null, displaySystem);
1963          //view.bitmaps.Add(bitmap);
1964       }  
1965       if(item && item.type == pictureFile)
1966       {
1967          view.bitmap = Bitmap { };
1968          view.bitmap.Load(item.path, null, displaySystem);
1969       }
1970
1971       view.show.Update(null);
1972       view.NotifyItemSelect(master, view, item, selectedItems);
1973    }
1974
1975    void Refresh()
1976    {
1977       Load(location);
1978    }
1979
1980    void Load(FileSystemNode location)
1981    {
1982       char path[MAX_LOCATION];
1983       this.location = location;
1984       location.GetPath(path);
1985       {
1986          FileListing listing { path };
1987          
1988          ExplorerFileItem item;
1989          DataRow row;
1990
1991          list.Clear();
1992
1993          while(listing.Find())
1994          {
1995             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
1996
1997             row = list.AddRow();
1998             row.tag = (int)item;
1999             row.SetData(nameField, item);
2000          }
2001          list.Sort(nameField, 1);
2002       }
2003    }
2004 }
2005 #endif
2006
2007 #if 0
2008 class ExplorerTree : FileSystemBox
2009 {
2010    hasHorzScroll = false;
2011    hasVertScroll = false;
2012
2013    menu = Menu { };
2014
2015 public:
2016
2017    DataField nameField { dataType = "FileSystemNode", width = 240, userData = this };
2018
2019    FileSystemNode root;
2020    FileSystemNode selection;
2021
2022    virtual bool Window::NotifyNodeSelect(ExplorerTree tree, FileSystemNode node);
2023    
2024    property FileSystemNode node
2025    {
2026       get
2027       {
2028          if(!tree)
2029             return null;
2030          if(!tree.currentRow)
2031             return null;
2032          if(!tree.currentRow.tag)
2033             return null;
2034          return (FileSystemNode)tree.currentRow.tag;
2035       }
2036    }
2037
2038    void Select(FileSystemNode node)
2039    {
2040       if(node.row)
2041       {
2042          node.EnsureVisible(false);
2043          tree.SelectRow(node.row);
2044       }
2045    }
2046
2047    FileSystemNode Find(const char * name, FileSystemNode parent)
2048    {
2049       FileSystemNode node;
2050       FileSystemNode start = parent ? parent : root;
2051       if(!start.loaded || !start.childrenLoaded)
2052          LoadTreeNode(start, tree);
2053       for(node = start.children.first; node; node = node.next)
2054          if(node.name && !strcmpi(node.name, name))
2055             return node;
2056       return null;
2057    }
2058
2059    ListBox tree
2060    {
2061       master = master, parent = this;
2062       //this, master;
2063       borderStyle = none;
2064       hasHorzScroll = true;
2065       hasVertScroll = true;
2066       fullRowSelect = false;
2067       treeNodees = true;
2068       collapseControl = true;
2069       rootCollapseButton = true;
2070
2071       anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
2072
2073       // WHY is this not working ?
2074       /-*void OnResize(int width, int height)
2075       {
2076          if(vertScroll.visible)
2077             nameField.width = width - vertScroll.size.w;
2078          else
2079             nameField.width = width;
2080       }*-/
2081
2082       bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed)
2083       {
2084          if(row)
2085          {
2086             FileSystemNode node = (FileSystemNode)row.tag;
2087             FileSystemNode child;
2088             if(collapsed)
2089             {
2090                /-*
2091                for(child = node.children.last; child; child = node.children.last)
2092                {
2093                   listBox.DeleteRow(child.row);
2094                   child.Free();
2095                   delete child;
2096                }
2097                node.childrenLoaded = false;
2098                *-/
2099             }
2100             else
2101             {
2102                if(!node.loaded || !node.childrenLoaded)
2103                   LoadTreeNode(node, tree);
2104                for(child = node.children.first; child && child.next; child = child.next);
2105                if(child)
2106                   child.EnsureVisible(false);
2107             }
2108          }
2109          return true;
2110       }
2111       
2112       bool NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods)
2113       {
2114          DataRow row = listBox.currentRow;
2115          if(row)
2116          {
2117             FileSystemNode node = (FileSystemNode)row.tag;
2118             if(node)
2119             {
2120                PopupMenu popup;
2121                Menu menu { };
2122
2123                MenuItem { menu, "Cut\tCtrl+X", t, NotifySelect = null, disabled = false };
2124                MenuItem { menu, "Copy\tCtrl+C", c, NotifySelect = null, disabled = false };
2125                MenuItem { menu, "Paste\tCtrl+V", p, NotifySelect = null, disabled = false /-*!clipboard*-/ };
2126                MenuItem { menu, "Delete\tDel", d, NotifySelect = null, disabled = false };
2127                //MenuDivider { menu };
2128
2129                popup = PopupMenu
2130                   {
2131                      master = this, menu = menu,
2132                      position = { 
2133                         x + clientStart.x + absPosition.x - guiApp.desktop.position.x, 
2134                         y + clientStart.y + absPosition.y - guiApp.desktop.position.y }
2135                   };
2136                popup.Create();
2137             }
2138          }
2139          return true;
2140       }
2141
2142       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
2143       {
2144          if(row)
2145          {
2146             FileSystemNode node = (FileSystemNode)row.tag;
2147             NotifyNodeSelect(listBox.parent.master, this, node);
2148             selection = node;
2149          }
2150          return true;
2151       }
2152
2153       bool NotifyEditing(ListBox listBox, DataRow row)
2154       {
2155          if(row)
2156          {
2157             FileSystemNode node = (FileSystemNode)row.tag;
2158          }
2159          return true;
2160       }
2161
2162       bool NotifyEdited(ListBox listBox, DataRow row)
2163       {
2164          if(row)
2165          {
2166             FileSystemNode node = (FileSystemNode)row.tag;
2167          }
2168          return true;
2169       }
2170
2171       bool NotifyEditDone(ListBox listBox, DataRow row)
2172       {
2173          if(row)
2174          {
2175             FileSystemNode node = (FileSystemNode)row.tag;
2176          }
2177          return true;
2178       }
2179    };
2180
2181    // Edit Menu
2182    Menu editMenu { menu, "Edit", e };
2183    MenuItem itemEditCut
2184    {
2185       editMenu, "Cut\tCtrl+X", t, disabled = true;
2186
2187       bool NotifySelect(MenuItem selection, Modifiers mods)
2188       {
2189          //EditCut();
2190          return true;
2191       }
2192    };
2193    MenuItem itemEditCopy
2194    {
2195       editMenu, "Copy\tCtrl+C", c, disabled = true;
2196
2197       bool NotifySelect(MenuItem selection, Modifiers mods)
2198       {
2199          //EditCopy();
2200          return true;
2201       }
2202    };
2203    MenuItem itemEditPaste
2204    {
2205       editMenu, "Paste\tCtrl+V", p;
2206    
2207       bool NotifySelect(MenuItem selection, Modifiers mods)
2208       {
2209          //EditPaste();
2210          return true;
2211       }
2212    };
2213    MenuItem itemEditDelete
2214    {
2215       editMenu, "Delete\tDel", d, disabled = true;
2216
2217       bool NotifySelect(MenuItem selection, Modifiers mods)
2218       {
2219          //EditDelete();
2220          return true;
2221       }
2222    };
2223
2224    // WHY is this crashing ? 
2225    /-*void OnResize(int width, int height)
2226    {
2227       if(this && nameField)
2228          nameField.width = width - 80;
2229    }*-/
2230
2231    ExplorerTree()
2232    {
2233       tree.AddField(nameField);
2234    }
2235
2236    void Load()
2237    {
2238       FileSystemNode parent;
2239       FileSystemNode node;
2240       FileListing listing { "/" };
2241
2242       tree.Clear();
2243
2244       root = FileSystemNode { type = computer, loaded = true, childrenLoaded = true };
2245    #ifdef __WIN32__
2246       root.name = rootName;
2247    #else
2248       root.name = "/";
2249    #endif
2250       AddTreeNode(root, true, false, false, null, tree);
2251
2252    // How can this make sense for linux? 
2253    #ifdef __WIN32__
2254       while(listing.Find())
2255       {
2256          int len = strlen(listing.name);
2257          char info[MAX_LOCATION];
2258          char name[MAX_LOCATION];
2259          if(listing.stats.attribs.isDrive && 
2260                len > 3 && !strncmp(&listing.name[1], ": [", 3))
2261          {
2262             strncpy(name, listing.name, 2);
2263             name[2] = 0;
2264             strncpy(info, &listing.name[4], len - 5);
2265             info[len - 5] = 0;
2266          }
2267          else
2268          {
2269             strcpy(name, listing.name);
2270             info[0] = 0;
2271          }
2272
2273          parent = MakeFileSystemNode(listing.stats, name);
2274          if(info[0])
2275             parent.info = CopyString(info);
2276          parent.loaded = true;
2277          AddTreeNode(parent, !listing.stats.attribs.isDirectory, false, listing.stats.attribs.isDirectory, root, tree);
2278          if(!listing.stats.attribs.isDirectory)
2279             parent.childrenLoaded = true;
2280       }
2281    #endif
2282       node = FileSystemNode { name = msNetwork, type = network };
2283       AddTreeNode(node, false, false, true, null, tree);
2284       node.row.collapsed = true;
2285       tree.Sort(nameField, 1);
2286       tree.SelectRow(root.row);
2287    }
2288 }
2289
2290 #if 0
2291 public class ClipBoardFiles
2292 {
2293
2294 public:
2295
2296    property
2297
2298 }
2299
2300    // CLIPBOARD
2301    void Copy()
2302    {
2303       if(this)
2304       {
2305          int size = SelSize();
2306          if(size)
2307          {
2308             // Try to allocate memory
2309             ClipBoard clipBoard { };
2310             if(clipBoard.Allocate(size+1))
2311             {
2312                GetSel(clipBoard.memory, true);   
2313                // Save clipboard
2314                clipBoard.Save();
2315             }
2316             delete clipBoard;
2317          }
2318       }
2319    }
2320
2321    void Paste()
2322    {
2323       if(this)
2324       {
2325          ClipBoard clipBoard { };
2326          if(clipBoard.Load())
2327             PutS(clipBoard.memory);
2328          delete clipBoard;
2329       }
2330    }
2331
2332    void Cut()
2333    {
2334       if(this)
2335       {
2336          Copy();
2337          DelSel();
2338          SetViewToCursor(true);
2339          Modified();
2340       }
2341    }
2342
2343 /-*
2344 Private Type DROPFILES
2345    pFiles As Long
2346    pt As POINTAPI
2347    fNC As Long
2348    fWide As Long
2349 End Type
2350 For iCounter = 0 To filelist.ListCount - 1
2351   If filelist.Selected(iCounter) = True Then
2352     strFiles = strFiles & FixPath(filelist.Path) & filelist.List(iCounter) & vbNullChar
2353   End If
2354 Next
2355 'all selected items are now put in strFiles
2356
2357 hGlobal = GlobalAlloc(GHND, Len(DF) + Len(strFiles)) 'put all files to a exclusive number
2358 If hGlobal Then 'if the globalalloc worked
2359   lpGlobal = GlobalLock(hGlobal) 'lock the hGlobal
2360   DF.pFiles = Len(DF) 'set the size of the files
2361   
2362   Call CopyMem(ByVal lpGlobal, DF, Len(DF)) 'copy df to the lpglobal
2363   Call CopyMem(ByVal (lpGlobal + Len(DF)), ByVal strFiles, Len(strFiles)) 'copy strfiles to lpglobal
2364   Call GlobalUnlock(hGlobal) 'unlock hglobal again
2365   
2366   SetClipboardData CF_HDROP, hGlobal 'put files to the clipboard
2367 End If
2368 *-/
2369    bool SaveFile(const char * filePath)
2370    {
2371    }
2372 #endif
2373
2374 #if 0
2375 public class FileTreeNodeBSArray : ArrayBinarySorted
2376 {
2377    type = class(FileSystemNode);
2378 public:
2379    FileSystemNode * const _;
2380    BSloc Add(FileSystemNode item)
2381    {
2382       BSloc result = Find(item);
2383       if(!result.valid)
2384       {
2385          Insert(result.pos, 1);
2386          _[result.pos] = item;
2387       }
2388       return result;
2389    }
2390    BSloc Remove(FileSystemNode item)
2391    {
2392       
2393    }
2394 }
2395 #endif
2396
2397 #if 0
2398 public class FileTreeNodeArray : RedjArray
2399 {
2400    type = class(FileSystemNode);
2401 public:
2402    FileSystemNode * const _;
2403    FileSystemNode * Add(FileSystemNode item)
2404    {
2405       uint pos = _count;
2406       Append(1);
2407       _[pos] = item;
2408       return &_[pos];
2409    }
2410    FileSystemNode * AddBefore(uint position, FileSystemNode item)
2411    {
2412       Insert(position, 1);
2413       _[position] = item;
2414       return &_[position];
2415    }
2416 }
2417 #endif
2418
2419 #if 0
2420 public class ExplorerFileItem : struct
2421 {
2422    char * path;
2423    char * name;
2424    char * info;
2425    char * extension;
2426    _FileType type;
2427    int indent;
2428
2429    Bitmap bitmap;
2430
2431    void OnDisplay(Surface surface, int x, int y, int width, FileSystemBox control, Alignment alignment, DataDisplayFlags displayFlags)
2432    {
2433       int indentSize = (displayFlags.dropBox) ? 0 : 10;
2434       int textOffset;
2435       int len;
2436       char label[MAX_FILENAME];
2437
2438       //float scale = Min((float)clientSize.w / (float)bitmap.width, (float)clientSize.h / (float)bitmap.height);
2439       int w = 16; //(int)(bitmap.width * scale);
2440       int h = 16; //(int)(bitmap.height * scale);
2441    
2442       Bitmap icon;
2443
2444       icon = control.fileIcons[type].bitmap;
2445       if(!icon)
2446       {
2447          if(type == folder || type == folderOpen)
2448             surface.SetForeground(red); //Color { 170, 170, 0 } // REDJ What is that color?
2449          indentSize = 8;
2450       }
2451       textOffset = indent * indentSize + (icon ? (icon.width + 6) : 0);
2452       
2453       if(info)
2454          sprintf(label, "%s [%s]", name, info);
2455       else
2456          strcpy(label, name);
2457       len = strlen(label);
2458
2459       surface.WriteTextDots
2460          (alignment, x + textOffset, y + 2, width - textOffset, label, len);
2461       if(type == pictureFile && control.previewPictures && bitmap)
2462       {
2463 #ifndef __linux__
2464          //surface.Filter(bitmap, (clientSize.w - w) / 2,(clientSize.h - h) / 2, 0,0, w, h, bitmap.width, bitmap.height);
2465          surface.Filter(bitmap, x + indent * indentSize + 2, y, 0, 0, w, h, bitmap.width, bitmap.height);
2466 #else
2467          // Until Filter / Stretch works with X
2468          //surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2,(clientSize.h - bitmap.height) / 2, 0,0, bitmap.width, bitmap.height);
2469          surface.blend = true;
2470          surface.Blit(bitmap, x + indent * indentSize + 2, y,0,0, w, h);
2471 #endif
2472          //bitmap.Free();
2473          //delete bitmap;
2474       }
2475       else if(icon)
2476          surface.Blit(icon, x + indent * indentSize + 2, y,0,0, icon.width, icon.height);
2477    }
2478
2479    int OnCompare(ExplorerFileItem b)
2480    {
2481       int result;
2482       if(type == b.type || (type < folder && b.type < folder) || (type >= drive))
2483          result = strcmpi(name, b.name);
2484       else
2485       {
2486          if(type == folder && b.type < folder) result = -1;
2487          else if(type < folder && b.type == folder) result = 1;
2488       }
2489       return result;
2490    }
2491
2492    void OnCopy(ExplorerFileItem newData)
2493    {
2494       type = newData.type;
2495       indent = newData.indent;
2496       if(newData.name)
2497       {
2498          int len = strlen(newData.name) + 1;
2499          name = new char[len];
2500          CopyBytes(name, newData.name, len);
2501       }
2502    }
2503
2504    bool OnGetDataFromString(char * string)
2505    {
2506       int len = strlen(string) + 1;
2507       name = new char[len];
2508       CopyBytes(name, string, len);
2509       return true;
2510    }
2511
2512    void OnFree()
2513    {
2514       delete path;
2515       delete name;
2516       delete info;
2517       delete extension;
2518       if(bitmap)
2519          bitmap.Free();
2520    }
2521
2522    char * OnGetString(char * string, void * fieldData, bool * needClass)
2523    {
2524       return name;
2525    }
2526 };
2527
2528 public class ExplorerFileItemArray : RedjArray
2529 {
2530    type = class(ExplorerFileItem);
2531 public:
2532    ExplorerFileItem * const _;
2533    ExplorerFileItem * Add(ExplorerFileItem item)
2534    {
2535       uint pos = _count;
2536       Append(1);
2537       _[pos] = item;
2538       return &_[pos];
2539    }
2540    ExplorerFileItem * AddBefore(uint position, ExplorerFileItem item)
2541    {
2542       Insert(position, 1);
2543       _[position] = item;
2544       return &_[position];
2545    }
2546    void Clear()
2547    {
2548       int c;
2549       for(c = 0; c < _count; c++)
2550       {
2551          //_[c].Free()
2552          delete _[c];
2553       }  
2554       count = 0;
2555       size = 0;
2556    }
2557 }
2558
2559 ExplorerFileItem MakeFileItem(const FileAttribs attribs, const char * fileName, const char * filePath, const bool previewPicture, const DisplaySystem displaySystem)
2560 {
2561    int len = strlen(fileName);
2562    char info[MAX_LOCATION];
2563    char name[MAX_LOCATION];
2564    char extension[MAX_EXTENSION];
2565    
2566    ExplorerFileItem item { };
2567
2568    //if(stats.attribs.isFile) // -- should work now
2569    if(attribs.isDirectory)
2570    {
2571       extension[0] = 0;
2572
2573       item.type = (attribs.isDrive) ? drive : folder;
2574       if(attribs.isServer)
2575          item.type = server;
2576       if(attribs.isShare)
2577          item.type = share;
2578       if(attribs.isCDROM)
2579          item.type = cdrom;
2580       if(attribs.isRemote)
2581          item.type = netDrive;
2582       if(attribs.isRemovable) 
2583       {
2584          if(fileName[0] == 'A' || fileName[0] == 'B')
2585             item.type = floppy;
2586          else
2587             item.type = removable;
2588       }
2589    }
2590    else
2591    {
2592       GetExtension(fileName, extension);
2593       //strupr(extension);
2594       strlwr(extension);
2595       
2596       item.type = _FileType::SelectByExtension(extension);
2597    }
2598
2599    if(attribs.isDrive && 
2600          len > 3 && !strncmp(&fileName[1], ": [", 3))
2601    {
2602       strncpy(name, fileName, 2);
2603       name[2] = 0;
2604       strncpy(info, &fileName[4], len - 5);
2605       info[len - 5] = 0;
2606    }
2607    else
2608    {
2609       strcpy(name, fileName);
2610       info[0] = 0;
2611    }
2612
2613    item.path = CopyString(filePath);
2614    item.name = CopyString(name);
2615    if(info[0])
2616       item.info = CopyString(info);
2617    item.extension = CopyString(extension);
2618
2619    if(item.type == pictureFile && previewPicture)
2620    {
2621       item.bitmap = Bitmap { };
2622       item.bitmap.Load(filePath, null, displaySystem);
2623    }
2624
2625    return item;
2626 }
2627 #endif
2628 */
2629
2630 public class FileSystemBoxSelection
2631 {
2632 public:
2633    FileSystemNode node;
2634    Array<FileSystemNode> nodes { };
2635
2636 private:
2637    FileSystemBoxSelection Copy()
2638    {
2639       FileSystemBoxSelection copy { node = node };
2640       for(node : nodes)
2641       {
2642          copy.nodes.Add(node);
2643          incref node;
2644       }
2645       return copy;
2646    }
2647
2648    ~FileSystemBoxSelection()
2649    {
2650       nodes.Free();
2651    }
2652 }
2653
2654 class FileSystemNodeBits
2655 {
2656    bool loaded:1, childrenLoaded:1, isListItem:1;
2657 };
2658
2659 public class FileSystemNode
2660 {
2661
2662 private:
2663    FileSystemNodeBits bits;
2664    char * path;
2665    char * name;
2666    char * extension;
2667    char * label;
2668    char * info;
2669
2670    ~FileSystemNode()
2671    {
2672       Free();
2673    }
2674
2675 public:
2676    /*//LinkElement<FileSystemNode> link;
2677    FileSystemNode parent;
2678
2679    FileSystemNodeType type;
2680
2681    char * name;*/
2682
2683    FileSystemNode prev, next;
2684
2685    int indent;
2686
2687    property bool isListItem { set { bits.isListItem = value; } get { return bits.isListItem; } };
2688
2689    property char * path
2690    {
2691       set { delete path; if(value && value[0]) path = CopyString(value); }
2692       get { return path; } isset { return path && path[0]; }
2693    }
2694    property char * name
2695    {
2696       set { delete name; if(value && value[0]) name = CopyString(value); }
2697       get { return name; } isset { return name && name[0]; }
2698    }
2699    property char * extension
2700    {
2701       set { delete extension; if(value && value[0]) extension = CopyString(value); }
2702       get { return extension; } isset { return extension && extension[0]; }
2703    }
2704    property char * label
2705    {
2706       set { delete label; if(value && value[0]) label = CopyString(value); }
2707       get { return label; } isset { return label && label[0]; }
2708    }
2709    property char * info
2710    {
2711       set { delete info; if(value && value[0]) info = CopyString(value); }
2712       get { return info; } isset { return info && info[0]; }
2713    }
2714
2715    DataRow row;
2716    OldList children;
2717    _FileType type;
2718    FileSystemNode parent;
2719
2720    FileStats stats;
2721
2722    Bitmap bitmap;
2723
2724    int cmpIcon;
2725    bool cmpNot;
2726    Array<int> exists; // would use (see) BoolArrayInt to pack this into an int if could be accessed as an array
2727
2728    void GetPath(String outputPath)
2729    {  
2730       if(path)
2731          strcpy(outputPath, path);
2732       else if(parent)
2733       {
2734          FileSystemNode up;
2735          if(name)
2736             strcpy(outputPath, name);
2737          for(up = parent; up; up = up.parent)
2738          {
2739             char temp[MAX_LOCATION];
2740             strcpy(temp, up.name);
2741             PathCat(temp, outputPath);
2742             strcpy(outputPath, temp);
2743          }
2744          /*else
2745          {
2746    /-*#ifdef __WIN32__
2747             strcpy(outputPath, "/");
2748    #else*-/
2749             //strcpy(outputPath, name);
2750             strcpy(outputPath, path);
2751             PathCat(outputPath, name);
2752    //#endif
2753          }*/
2754       }
2755    }
2756
2757    bool IsChildOf(FileSystemNode node)
2758    {
2759       FileSystemNode test;
2760       for(test = parent; test; test = test.parent)
2761          if(test == node)
2762             return true;
2763       return false;
2764    }
2765
2766    void DuplicateChildren(bool recursive, bool forceExpanded, FileSystemNode addTo, FileSystemBox fsb)
2767    {
2768       if(children.first)
2769       {
2770          FileSystemNode child;
2771          
2772          for(child = children.first; child; child = child.next)
2773          {
2774             FileSystemNode copy { };
2775             copy.name = child.name; //CopyString(child.name);
2776             copy.type = child.type;
2777             fsb.AddTreeNode(copy, child.bits.loaded, false, false, addTo);
2778             if(forceExpanded)
2779                copy.row.collapsed = false;
2780             if(recursive)
2781                child.DuplicateChildren(recursive, forceExpanded, copy, fsb);
2782          }
2783       }
2784    }
2785    
2786    void EnsureVisible(bool expand)
2787    {
2788       if(parent)
2789          parent.EnsureVisible(true);
2790       if(expand)
2791          row.collapsed = false;
2792       // TODO: row.EnsureVisible(); // making the row visible by scrolling
2793    }
2794
2795    void OnFree()
2796    {
2797       //delete name;
2798    }
2799
2800    void Free()
2801    {
2802       FileSystemNode child;
2803       for(; (child = children.first); )
2804       {
2805          child.Free();
2806          children.Delete(child);
2807       }
2808       //if(name)
2809       delete path;
2810       delete name;
2811       delete extension;
2812       delete label;
2813       delete info;
2814    }
2815
2816    void Delete()
2817    {
2818       Free();
2819       if(parent)
2820          parent.children.Delete(this);
2821    }
2822
2823    void OnDisplay(Surface surface, int x, int y, int width, FileSystemBox fsb, Alignment alignment, DataDisplayFlags displayFlags)
2824    {
2825       //int indentSize = (displayFlags.dropBox) ? 0 : 10;
2826       int indent = 16;
2827       int xStart;
2828       int len;
2829       int w, h;
2830       //int textOffset;
2831       char * alt;
2832       char text[MAX_LOCATION];
2833       bool comp;
2834
2835       Bitmap icon;
2836       Bitmap diffIcon;
2837       Bitmap notIcon;
2838
2839       if(!this)
2840          return;
2841       
2842       comp = fsb.comparedPaths && fsb.comparedPaths.count > 1;
2843       icon = fsb.fileIcons[type].bitmap;
2844       alt = bits.isListItem ? path : name;
2845       if(comp && !fsb.bits.columnsCompareStyle && cmpIcon)
2846       {
2847          /*
2848          diffIcon = Bitmap { };
2849          diffIcon.AllocateDD(
2850                surface.display.displaySystem,
2851                fsb.compIcons[cmpIcon].bitmap.width,
2852                fsb.compIcons[cmpIcon].bitmap.height);
2853          if(fsb.compIcons[cmpIcon].bitmap)
2854             diffIcon.Copy(fsb.compIcons[cmpIcon].bitmap);
2855          */
2856          diffIcon = fsb.compIcons[cmpIcon-1].bitmap;
2857          notIcon = fsb.compIcons[countOfCompIconNames-1].bitmap;
2858       }
2859       //xStart = indent * indent + x + (icon ? (icon.width + 5) : 0);
2860       xStart = x + (icon ? (icon.width + 5) : 0) + (comp ? 18*(fsb.bits.columnsCompareStyle ? fsb.comparedPaths.count : 1) : 0);
2861
2862       if(!alt)
2863          return;
2864
2865       if(info)
2866          sprintf(text, "%s [%s]", label ? label : alt, info);
2867       else
2868          strcpy(text, label ? label : alt); //"%d-%d/%s", stats.inode, stats.nlink
2869          //sprintf(text, "%d-%d/%s", stats.inode, stats.nlink, label ? label : alt);
2870       len = strlen(text);
2871       
2872       if(!icon)
2873       {
2874          if(type == folder || type == folderOpen)
2875             surface.SetForeground(yellow);
2876          //indentSize = 8;
2877          indent = 8;
2878       }
2879       //textOffset = indent * indentSize + (icon ? (icon.width + 4) : 0);
2880       
2881       surface.SetForeground(displayFlags.selected ? fsb.selectionText : fsb.foreground);
2882       surface.TextOpacity(false);
2883       surface.TextExtent(text, len, &w, &h);
2884       h = Max(h, 16);
2885     
2886       // Draw the current row stipple
2887       if(displayFlags.selected)
2888          //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
2889          //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
2890          surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
2891       
2892       //surface.WriteTextDots(alignment, x + textOffset, y + 2, width - textOffset, alt, strlen(alt));
2893       surface.WriteTextDots(alignment, xStart, y + 2, width, text, len);
2894
2895       if(!guiApp.textMode)
2896       {
2897          if(displayFlags.current)
2898          {
2899             if(displayFlags.active)
2900             {
2901                surface.LineStipple(0x5555);
2902                if(displayFlags.selected)
2903                   surface.SetForeground(0xFFFFFF80);
2904                else
2905                   surface.SetForeground(black);
2906             }
2907             else
2908             {
2909                surface.SetForeground(selectionColor);
2910             }
2911             surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
2912             surface.LineStipple(0);
2913          }
2914
2915          if(comp)
2916          {
2917             if(!fsb.bits.columnsCompareStyle && diffIcon)
2918             {
2919                w = diffIcon.width;
2920                h = diffIcon.height;
2921                /*if(cmpNot && notIcon)
2922                {
2923                   Surface s = diffIcon.GetSurface(0,0, {w,h});
2924                   s.SetForeground(white);
2925                   s.Blit(notIcon, x,y, 0,0, w,h);
2926                   delete s;
2927                }*/
2928                surface.SetForeground(white);
2929                surface.Blit(diffIcon, x,y, 0,0, w,h);
2930                if(cmpNot && notIcon)
2931                   surface.Blit(notIcon, x,y, 0,0, w,h);
2932                x+=18;
2933                //delete diffIcon;
2934             }
2935             else if(fsb.bits.columnsCompareStyle && exists && exists.count)
2936             {
2937                int c, d;
2938                for(c = d = 0; c < fsb.comparedPaths.count; c++)
2939                {
2940                   if(d == exists.count || exists[d] != c)
2941                      x+=18;
2942                   else
2943                   {
2944                      diffIcon = fsb.compIcons[c].bitmap;
2945                      if(diffIcon)
2946                      {
2947                         w = diffIcon.width;
2948                         h = diffIcon.height;
2949                         surface.SetForeground(white);
2950                         surface.Blit(diffIcon, x,y, 0,0, w,h);
2951                      }
2952                      x+=18;
2953                      d++;
2954                   }
2955                }
2956                /*
2957                for(c = d = 0; c < exists.count; c++)
2958                {
2959                   if(exists[c] != d)
2960                   {
2961                      d = exists[c]+1;
2962                      x+=18*(exists[c]-d);
2963                   }
2964                   else
2965                   {
2966                      diffIcon = fsb.compIcons[exists[c]].bitmap;
2967                      if(diffIcon)
2968                      {
2969                         w = diffIcon.width;
2970                         h = diffIcon.height;
2971                         surface.SetForeground(white);
2972                         surface.Blit(diffIcon, x,y, 0,0, w,h);
2973                      }
2974                      d++;
2975                      x+=18;
2976                   }
2977                }
2978                if(exists.count < fsb.comparedPaths.count && exists[exists.count-1] != d)
2979                {
2980                   x+=18*(exists[exists.count-1]-d);
2981                }
2982                */
2983             }
2984             else if(fsb.bits.columnsCompareStyle)
2985             {
2986                x+=18*fsb.comparedPaths.count;
2987             }
2988          }
2989          if(icon)
2990          {
2991             w = icon.width;
2992             h = icon.height;
2993          }
2994          if(type == pictureFile && fsb.previewPictures && bitmap)
2995          {
2996             surface.SetForeground(white);
2997             surface.blend = true;
2998    //#ifndef __linux__
2999             //surface.Filter(bitmap, (clientSize.w - w) / 2,(clientSize.h - h) / 2, 0,0, w, h, bitmap.width, bitmap.height);
3000             //surface.Filter(bitmap, x + indent/* * indentSize*/ + 2, y, 0, 0, w, h, bitmap.width, bitmap.height);
3001             surface.Filter(bitmap, x,y,0,0, w, h, bitmap.width, bitmap.height);
3002    //#else
3003             // Until Filter / Stretch works with X
3004             //surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2,(clientSize.h - bitmap.height) / 2, 0,0, bitmap.width, bitmap.height);
3005    //         surface.blend = true;
3006             //surface.Blit(bitmap, x + indent/* * indentSize*/ + 2, y,0,0, w, h);
3007             //surface.Blit(bitmap, x,y,0,0, bitmap.width, bitmap.height);
3008    //#endif
3009             //bitmap.Free();
3010             //delete bitmap;
3011          }
3012          else if(icon)
3013          {
3014             //surface.blend = true;
3015             //surface.alphaWrite = blend;
3016             surface.SetForeground(white);
3017             //surface.Blit(icon, x + indent * indentSize, y,0,0, icon.width, icon.height);
3018             surface.Blit(icon, x,y, 0,0, w,h);
3019          }
3020       }
3021    }
3022
3023    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
3024    {
3025       EditBox editBox
3026       {
3027          dataBox, anchor = { 0, 0, 0, 0 };
3028          borderStyle = none;
3029          //borderStyle = contour;
3030          opacity = 1.0f;
3031          //background = white;
3032          //autoSize = true;
3033          contents = name;
3034       };
3035       //dataBox.borderStyle = none;
3036       dataBox.borderStyle = contour;
3037       dataBox.background = white;
3038       //dataBox.opacity = 0.0f;
3039       editBox.Create();
3040       return editBox;
3041    }
3042
3043    bool OnSaveEdit(EditBox editBox, void * object)
3044    {
3045       bool changed = false;
3046       if(editBox.modifiedDocument)
3047       {
3048 #if 0
3049          // how the heck did this work for PathBox? :S
3050          //String::OnFree();
3051          //changed = _class._vTbl[__ecereVMethodID_class_OnGetDataFromString](_class, &this, editBox.contents);
3052          PrintLn(name);
3053          //if(strcmp(editBox.contents, this.name))
3054          ;
3055          /*{
3056             //changed = NotifyNodeRename(this.master, this, node);
3057             changed = true;
3058             if(changed && RenameFile(name, editBox.contents))
3059             {
3060                name = editBox.contents;
3061             }
3062             else
3063             {
3064                changed = false;
3065             }
3066          }*/
3067 #endif
3068       }
3069       return changed;
3070    }
3071
3072    int OnCompare(FileSystemNode b)
3073    {
3074       int result;
3075       FileSystemNode a = this;
3076       if(a.type == b.type || (a.type < folder && b.type < folder) || (a.type >= drive))
3077       {
3078          if(!a.name || !b.name)
3079             PrintLn("error: FileSystemNode::OnCompare -- null-named node");
3080          result = strcmpi(a.name, b.name);
3081       }
3082       else
3083       {
3084          if(a.type == folder && b.type < folder) result = -1;
3085          else if(a.type < folder && b.type == folder) result = 1;
3086          else result = 0;
3087       }
3088       return result;
3089    }
3090
3091 #if 0
3092    //int OnCompare(FileSystemNode b)
3093    //{
3094       //int result;
3095       //FileSystemNode a = this;
3096       //if(a.parent < b.parent) result = -1;
3097       //else if(a.parent > b.parent) result = 1;
3098       //else
3099          //result = fstrcmp(a.name, b.name);
3100       //return result;
3101    //}
3102 #endif
3103
3104    bool OnGetDataFromString(char * string)
3105    {
3106 #if 0
3107       if(string && *string)
3108       {
3109          int len = strlen(string) + 1;
3110          name = new char[len];
3111          CopyBytes(name, string, len);
3112          return true;
3113       }
3114 #endif
3115       return false;
3116    }
3117
3118    char * OnGetString(char * tempString, FileSystemToolWindow fileSysToolWnd, bool * needClass)
3119    {
3120       return name ? name : "";
3121    }
3122 }
3123
3124 /*FileSystemNode MakeFileSystemNode(const FileStats stats, const char * name)
3125 {
3126    FileSystemNode node { stats = stats };
3127    node.name = CopyString(name);
3128    if(!node.name)
3129       node.name = null;
3130    if(stats.attribs.isDirectory)
3131    {
3132       node.type = (stats.attribs.isDrive) ? drive : folder;
3133       if(stats.attribs.isServer) node.type = server;
3134       if(stats.attribs.isShare) node.type = share;
3135       if(stats.attribs.isCDROM) node.type = cdrom;
3136       if(stats.attribs.isRemote) node.type = netDrive;
3137       if(stats.attribs.isRemovable) 
3138       {
3139          if(name[0] == 'A' || name[0] == 'B')
3140             node.type = floppy;
3141          else
3142             node.type = removable;
3143       }
3144    }
3145    else
3146    {
3147       char extension[MAX_EXTENSION];
3148       GetExtension(node.name, extension);
3149       node.type = _FileType::SelectByExtension(extension);
3150    }
3151    return node;
3152 }*/
3153
3154 FileSystemNode MakeFileSystemNode(
3155    const FileStats stats,
3156    const char * name,
3157    const char * path,
3158    const bool pathAddName,
3159    const bool previewPicture,
3160    const bool isListItem,
3161    const DisplaySystem displaySystem)
3162 {
3163    int len = strlen(name);
3164    char info[MAX_LOCATION];
3165    char name2[MAX_LOCATION];
3166    char extension[MAX_EXTENSION];
3167    
3168    FileSystemNode node { stats = stats };
3169
3170    /*if(!pathAddName)
3171    {
3172       char o[MAX_LOCATION];
3173       //char r[MAX_LOCATION];
3174       //StripLastDirectory(path, o);
3175       GetLastDirectory(path, o);
3176       if(fstrcmp(name, o))
3177       //if(!FileExists(path))
3178          PrintLn("Stop!");
3179    }*/
3180    //if(stats.attribs.isFile) // TODO fix this in ecere -- WTH -- this has been fixed :/
3181    if(stats.attribs.isDirectory)
3182    {
3183       extension[0] = '\0';
3184
3185       node.type = (stats.attribs.isDrive) ? drive : folder;
3186       if(stats.attribs.isServer) node.type = server;
3187       if(stats.attribs.isShare) node.type = share;
3188       if(stats.attribs.isCDROM) node.type = cdrom;
3189       if(stats.attribs.isRemote) node.type = netDrive;
3190       if(stats.attribs.isRemovable) 
3191       {
3192          if(name[0] == 'A' || name[0] == 'B')
3193             node.type = floppy;
3194          else
3195             node.type = removable;
3196       }
3197    }
3198    else
3199    {
3200       GetExtension(name, extension);
3201       strlwr(extension);
3202       
3203       node.type = _FileType::SelectByExtension(extension);
3204    }
3205
3206    if(stats.attribs.isDrive && 
3207          len > 3 && !strncmp(&name[1], ": [", 3))
3208    {
3209       strncpy(name2, name, 2);
3210       name2[2] = 0;
3211       strncpy(info, &name[4], len - 5);
3212       info[len - 5] = 0;
3213    }
3214    else
3215    {
3216       strcpy(name2, name);
3217       info[0] = 0;
3218    }
3219
3220    if(pathAddName)
3221    {
3222       bool isFile = stats.attribs.isFile;
3223       bool isFolder = stats.attribs.isDirectory;
3224       char full[MAX_LOCATION];
3225       strcpy(full, path);
3226       PathCat(full, name);
3227       node.path = full; //CopyString(full);
3228    }
3229    else
3230       node.path = path; //CopyString(path);
3231    node.name = name2; //CopyString(name2);
3232    if(info[0])
3233       node.info = info; //CopyString(info);
3234    node.extension = extension; //CopyString(extension);
3235
3236    if(node.type == pictureFile && previewPicture)
3237    {
3238       node.bitmap = Bitmap { alphaBlend = true };
3239       node.bitmap.Load(path, null, displaySystem);
3240    }
3241
3242    if(isListItem)
3243       node.bits.isListItem = true;
3244
3245    return node;
3246 }
3247
3248 FileSystemNode MakeComparedFileSystemNode(
3249    const FileStats stats,
3250    const char * name,
3251    const char * path,
3252    const bool pathAddName,
3253    const bool previewPicture,
3254    const int cmpIcon,
3255    const bool cmpNot,
3256    const Array<int> exists,
3257    const DisplaySystem displaySystem)
3258 {
3259    FileSystemNode node = MakeFileSystemNode(stats, name, path, pathAddName, previewPicture, false, displaySystem);
3260    if(node)
3261    {
3262       node.cmpIcon = cmpIcon;
3263       node.cmpNot = cmpNot;
3264       node.exists = exists;
3265    }
3266    return node;
3267 }
3268
3269 #if 0 // could we do this?
3270 class BoolArrayInt : int
3271 {
3272    // packing 32 bools in one int exposing them as an array
3273    bool [32]:1; // the :1 specifies the size of each element
3274    // byte [4]:8; // packing 4 bytes in an int exposing them as an arrat
3275 }
3276 // allowing you to access each 32 bits with the following notation:
3277 static void Dummy()
3278 {
3279    int c;
3280    BoolArrayInt a;
3281    a[0] = true;
3282    a[31] = false;
3283    for(c = 0; c < 32; c++)
3284       a[c] = SomFunction(...);
3285 }
3286 #endif
3287 class BoolArrayInt : int
3288 {
3289    bool  _0:1;
3290    bool  _1:1;
3291    bool  _2:1;
3292    bool  _3:1;
3293    bool  _4:1;
3294    bool  _5:1;
3295    bool  _6:1;
3296    bool  _7:1;
3297    bool  _8:1;
3298    bool  _9:1;
3299    bool _10:1;
3300    bool _11:1;
3301    bool _12:1;
3302    bool _13:1;
3303    bool _14:1;
3304    bool _15:1;
3305 }