explorer: fixed trying to access all drives list root tree
[ede] / libede / src / FileSystemBox.ec
1 public import "ecere"
2
3 #ifdef __WIN32__
4 static char * rootName = "Entire Computer";
5 static char * msNetwork = "Microsoft Windows Network";
6 #else
7 static char * rootName = "File System";
8 #endif
9
10 private:
11 define guiApp = ((GuiApplication)__thisModule);  // how to do this in a dll?
12 define selectionColor = guiApp.currentSkin.selectionColor; //Color { 10, 36, 106 };
13
14 static char * fileIconNames[] = 
15 {
16    "<:ecere>mimeTypes/file.png",         /* none */
17
18    "<:ecere>mimeTypes/file.png",         /* normalFile */
19    "<:ecere>mimeTypes/textEcereWorkspace.png",          /* ewsFile */
20    "<:ecere>mimeTypes/textEcereProject.png",      /* epjFile */
21    "<:ecere>mimeTypes/textEcereSource.png",         /* ecFile */
22    "<:ecere>mimeTypes/textEcereHeader.png",         /* ehFile */
23    "<:ecere>mimeTypes/textCSource.png",          /* cFile */
24    "<:ecere>mimeTypes/textCHeader.png",          /* hFile */
25    "<:ecere>mimeTypes/textC++Source.png",        /* cppFile */
26    "<:ecere>mimeTypes/textC++Header.png",        /* hppFile */
27    "<:ecere>mimeTypes/text.png",         /* textFile */
28    "<:ecere>mimeTypes/textHyperTextMarkup.png",              /* webFile */
29    "<:ecere>mimeTypes/image.png",        /* pictureFile */
30    "<:ecere>status/audioVolumeHigh.png",         /* soundFile */
31    "<:ecere>mimeTypes/package.png",      /* archiveFile */
32    "<:ecere>mimeTypes/packageSoftware.png",     /* packageFile */
33    "<:ecere>mimeTypes/packageOpticalDisc.png", /* opticalMediaImageFile */
34
35    "<:ecere>places/folder.png",                    /* folder */
36    "<:ecere>status/folderOpen.png",               /* folderOpen */
37    "<:ecere>devices/computer.png",                 /* computer */
38    "<:ecere>devices/driveHardDisk.png",           /* drive */
39    "<:ecere>places/driveRemote.png",              /* netDrive */
40    "<:ecere>devices/mediaOptical.png",            /* cdrom */
41    "<:ecere>devices/driveRemovableMedia.png",    /* removable */
42    "<:ecere>devices/mediaFloppy.png",             /* floppy */
43    "<:ecere>places/networkWorkgroup.png",         /* network */
44    "<:ecere>places/networkServer.png",            /* server */
45    "<:ecere>places/folderRemote.png",             /* share */
46
47    "<:ecere>mimeTypes/package.png",      /* treeLoader */
48    "<:ecere>places/startHere.png",                /* lineNumbers */
49    
50    ""
51 };
52
53 public enum _FileType
54 {
55    none,
56    
57    normalFile, ewsFile, epjFile, ecFile, ehFile, cFile, hFile, cppFile, hppFile,
58    textFile, webFile, pictureFile, soundFile,
59    archiveFile, packageFile, opticalMediaImageFile, /* these (all previous) are sort equal */
60    
61    folder, folderOpen, computer,
62    drive, netDrive, cdrom, removable, floppy, network, server, share, // these are sort equal
63    
64    // utilities
65    treeLoader,
66    lineNumbers;
67
68    /*property char * 
69    {
70       set
71       {
72          this = SelectByExtension(value);
73       }
74    }*/
75
76    public property bool isFolder
77    {
78       get { return this >= folder && this <= share; }
79    }
80
81    public property bool isFile
82    {
83       get { return this >= normalFile && this <= opticalMediaImageFile; }
84    }
85
86    _FileType ::SelectByExtension(char * extension)
87    {
88       if(!strcmpi(extension, "ews"))
89          return ewsFile;
90       else if(!strcmpi(extension, "epj"))
91          return epjFile;
92       else if(!strcmpi(extension, "ec"))
93          return ecFile;
94       else if(!strcmpi(extension, "eh"))
95          return ehFile;
96       else if(!strcmpi(extension, "cpp") ||
97             !strcmpi(extension, "cc") || !strcmpi(extension, "cxx"))
98          return cppFile;
99       else if(!strcmpi(extension, "hpp") ||
100             !strcmpi(extension, "hh") || !strcmpi(extension, "hxx"))
101          return hppFile;
102       else if(!strcmpi(extension, "c"))
103          return cFile;
104       else if(!strcmpi(extension, "h"))
105          return hFile;
106       else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
107             !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
108          return textFile;
109       else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
110             !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
111             !strcmpi(extension, "js"))
112          return webFile;
113       else if(!strcmpi(extension, "bmp") || !strcmpi(extension, "pcx") ||
114             !strcmpi(extension, "jpg") || !strcmpi(extension, "jpeg") ||
115             !strcmpi(extension, "gif") || !strcmpi(extension, "png") ||
116             !strcmpi(extension, "ico"))
117          return pictureFile;
118       else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
119             !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
120          return soundFile;
121       else if(!strcmpi(extension, "ear") || !strcmpi(extension, "7z") ||
122             !strcmpi(extension, "rar") || !strcmpi(extension, "zip") ||
123             !strcmpi(extension, "gz") || !strcmpi(extension, "bz2") ||
124             !strcmpi(extension, "tar") || !strcmpi(extension, "arj") ||
125             !strcmpi(extension, "lza") || !strcmpi(extension, "lzh") ||
126             !strcmpi(extension, "cpio") || !strcmpi(extension, "z"))
127          return archiveFile;
128       else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
129             !strcmpi(extension, "rpm"))
130          return packageFile;
131       else if(!strcmpi(extension, "iso") || !strcmpi(extension, "mds") ||
132             !strcmpi(extension, "cue") || !strcmpi(extension, "bin") ||
133             !strcmpi(extension, "ccd") || !strcmpi(extension, "bwt") ||
134             !strcmpi(extension, "cdi") || !strcmpi(extension, "nrg"))
135          return opticalMediaImageFile;
136       return normalFile;
137    }
138 };
139
140 class FileSystemBoxBits
141 {
142    bool foldersOnly:1, filesOnly:1, details:1, treeBranches:1, previewPictures:1, navigateFolders:1;
143    //bool header:1, freeSelect:1, fullRowSelect:1, multiSelect:1, autoScroll:1, alwaysHL : 1, moveRows:1, resizable:1;
144    //bool moveFields:1, clearHeader:1, alwaysEdit:1, collapse:1, treeBranch:1, rootCollapse:1, heightSet:1;
145    //bool sortable:1, noDragging:1, fillLastField:1, expandOnAdd:1;
146 };
147
148 public class FileSystemBox : Window // should we not derive from ListBox instead?
149 /*
150    this stuff from the listbox would be nicely exposed...
151       fullRowSelect = false;
152       treeBranches = true;
153       collapseControl = true;
154       rootCollapseButton = true;
155       sortable = true;
156 */
157 {
158    borderStyle = deep;
159    hasHorzScroll = false;
160    hasVertScroll = false;
161
162    menu = Menu { };
163
164 public:
165    FileSystemNode root;
166    FileSystemNode selection;
167
168    virtual bool Window::NotifyNodeSelect(FileSystemBox box, FileSystemNode node);
169    virtual bool Window::NotifyNodeOpen(FileSystemBox box, FileSystemNode node);
170    
171    property char * path
172    {
173       set
174       {
175          delete path;
176          if(value && value[0])
177             path = CopyString(value);
178          if(locationBox)
179             locationBox.path = value;
180          if(created)
181             Load();
182       }
183
184       get { return path; }
185       //isset { return path && path[0]; }
186    }
187
188    property bool foldersOnly { set { bits.foldersOnly = value; bits.filesOnly = !value; } get { return bits.foldersOnly; } };
189    property bool filesOnly { set { bits.filesOnly = value; bits.foldersOnly = !value; } get { return bits.filesOnly; } };
190    property bool previewPictures { set { bits.previewPictures = value; } get { return bits.previewPictures; } };
191    property char * extensions { set { delete extensions; if(value && value[0]) extensions = CopyString(value); } get { return extensions; } }
192    property bool details { set { bits.details = value; } get { return bits.details; } };
193    property bool treeBranches
194    {
195       set
196       {
197          bits.treeBranches = value;
198          list.treeBranches = value;
199          list.collapseControl = value;
200          list.rootCollapseButton = value;
201       }
202       get { return bits.treeBranches; }
203    };
204    property bool navigateFolders { set { bits.navigateFolders = value; bits.foldersOnly = !value; } get { return bits.navigateFolders; } };
205    
206    property FileSystemNode node
207    {
208       get
209       {
210          if(!list)
211             return null;
212          if(!list.currentRow)
213             return null;
214          if(!list.currentRow.tag)
215             return null;
216          return (FileSystemNode)list.currentRow.tag;
217       }
218    }
219
220    PathBox locationBox;
221
222    void Select(FileSystemNode node)
223    {
224       if(node.row)
225       {
226          node.EnsureVisible(false);
227          list.SelectRow(node.row);
228       }
229    }
230
231    FileSystemNode Find(const char * name, FileSystemNode parent)
232    {
233       FileSystemNode node;
234       FileSystemNode start = parent ? parent : root;
235       if(!start.loaded || !start.childrenLoaded)
236          LoadTreeNode(start);
237       for(node = start.children.first; node; node = node.next)
238          if(node.name && !strcmpi(node.name, name))
239             return node;
240       return null;
241    }
242
243    void Refresh()
244    {
245       Load();
246    }
247
248 private:
249    FileSystemBoxBits bits;
250
251    char * path;
252    char * extensions;
253
254    BitmapResource fileIcons[_FileType];
255
256    FileSystemBox()
257    {
258       char wd[MAX_LOCATION];
259       GetWorkingDir(wd, sizeof(wd));
260       property::path = wd;
261       
262       InitFileIcons();
263       list.AddField(nameField);
264    }
265    ~FileSystemBox()
266    {
267       delete extensions;
268       delete path;
269    }
270    void InitFileIcons()
271    {
272       _FileType c;
273       for(c = 0; c < _FileType::enumSize; c++)
274       {
275          fileIcons[c] = BitmapResource { fileIconNames[c], alphaBlend = true };
276          AddResource(fileIcons[c]);
277       }
278    }
279
280    DataField nameField { dataType = "FileSystemNode", width = 240, userData = this, freeData = false };
281    DataField typeField { header = "Type", dataType = /*"String"*/ "char *", width = 40, freeData = false };
282    DataField sizeField { header = "Size", dataType = "FileSize", width = 96, alignment = right, freeData = false };
283
284    bool OnPostCreate()
285    {
286       Load();
287       return true;
288    }
289
290    ListBox list
291    {
292       this;
293
294       borderStyle = none;
295       hasHorzScroll = true;
296       hasVertScroll = true;
297       fullRowSelect = false;
298       sortable = true;
299
300       anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
301
302       // WHY is this not working ?
303       /*void OnResize(int width, int height)
304       {
305          if(vertScroll.visible)
306             nameField.width = width - vertScroll.size.w;
307          else
308             nameField.width = width;
309       }*/
310
311       bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed)
312       {
313          if(row)
314          {
315             FileSystemNode node = (FileSystemNode)row.tag;
316             FileSystemNode child;
317             if(collapsed)
318             {
319                /*
320                for(child = node.children.last; child; child = node.children.last)
321                {
322                   listBox.DeleteRow(child.row);
323                   child.Free();
324                   delete child;
325                }
326                node.childrenLoaded = false;
327                */
328             }
329             else
330             {
331                if(!node.loaded || !node.childrenLoaded)
332                {
333                   LoadTreeNode(node);
334                   //list.Sort(nameField, 1);
335                   //node.
336                }
337                for(child = node.children.first; child && child.next; child = child.next);
338                if(child)
339                   child.EnsureVisible(false);
340             }
341          }
342          return true;
343       }
344       
345       bool NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods)
346       {
347          DataRow row = listBox.currentRow;
348          if(row)
349          {
350             FileSystemNode node = (FileSystemNode)row.tag;
351             if(node)
352             {
353                PopupMenu popup;
354                Menu menu { };
355
356                MenuItem { menu, "Cut\tCtrl+X", t, NotifySelect = null, disabled = false };
357                MenuItem { menu, "Copy\tCtrl+C", c, NotifySelect = null, disabled = false };
358                MenuItem { menu, "Paste\tCtrl+V", p, NotifySelect = null, disabled = false /*!clipboard*/ };
359                MenuItem { menu, "Delete\tDel", d, NotifySelect = null, disabled = false };
360                //MenuDivider { menu };
361
362                popup = PopupMenu
363                   {
364                      master = this, menu = menu,
365                      position = { 
366                         x + clientStart.x + absPosition.x - guiApp.desktop.position.x, 
367                         y + clientStart.y + absPosition.y - guiApp.desktop.position.y }
368                   };
369                popup.Create();
370             }
371          }
372          return true;
373       }
374
375       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
376       {
377          if(row)
378          {
379             FileSystemNode node = (FileSystemNode)row.tag;
380             NotifyNodeSelect(listBox.parent.master, this, node);
381             selection = node;
382          }
383          return true;
384       }
385
386       bool NotifyEditing(ListBox listBox, DataRow row)
387       {
388          if(row)
389          {
390             FileSystemNode node = (FileSystemNode)row.tag;
391          }
392          return true;
393       }
394
395       bool NotifyEdited(ListBox listBox, DataRow row)
396       {
397          if(row)
398          {
399             FileSystemNode node = (FileSystemNode)row.tag;
400          }
401          return true;
402       }
403
404       bool NotifyEditDone(ListBox listBox, DataRow row)
405       {
406          if(row)
407          {
408             FileSystemNode node = (FileSystemNode)row.tag;
409          }
410          return true;
411       }
412
413       bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
414       {
415          return OpenNode();
416       }
417
418       bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
419       {
420          bool result;
421          if((SmartKey)key == enter)
422             result = OpenNode();
423          else
424             result = true;
425          return true;
426       }
427    };
428
429    bool OpenNode()
430    {
431       bool result;
432       if(selection && selection.type.isFolder && bits.navigateFolders)
433       {
434          property::path = selection.path;
435          result = true;
436       }
437       else
438          result = NotifyNodeOpen(this.master, this, selection);
439       return result;
440    }
441
442    // Edit Menu
443    Menu editMenu { menu, "Edit", e };
444    MenuItem itemEditCut
445    {
446       editMenu, "Cut\tCtrl+X", t, disabled = true;
447
448       bool NotifySelect(MenuItem selection, Modifiers mods)
449       {
450          //EditCut();
451          return true;
452       }
453    };
454    MenuItem itemEditCopy
455    {
456       editMenu, "Copy\tCtrl+C", c, disabled = true;
457
458       bool NotifySelect(MenuItem selection, Modifiers mods)
459       {
460          //EditCopy();
461          return true;
462       }
463    };
464    MenuItem itemEditPaste
465    {
466       editMenu, "Paste\tCtrl+V", p;
467    
468       bool NotifySelect(MenuItem selection, Modifiers mods)
469       {
470          //EditPaste();
471          return true;
472       }
473    };
474    MenuItem itemEditDelete
475    {
476       editMenu, "Delete\tDel", d, disabled = true;
477
478       bool NotifySelect(MenuItem selection, Modifiers mods)
479       {
480          //EditDelete();
481          return true;
482       }
483    };
484
485    // WHY is this crashing ? 
486    /*void OnResize(int width, int height)
487    {
488       if(this && nameField)
489          nameField.width = width - 80;
490    }*/
491
492    void Load()
493    {
494       // TODO: fix this!
495       // this is crashing in for designer when details = true // can't save the file, always yields a crash
496       /*if(list && created)
497       {
498          list.ClearFields();
499          list.AddField(nameField);
500          if(bits.details)
501          {
502             list.AddField(typeField);
503             list.AddField(sizeField);
504          }
505       }*/
506       if(bits.treeBranches)
507          LoadTree();
508       else
509          LoadList();
510    }
511
512    void LoadList()
513    {
514       FileListing listing { path, extensions = extensions };
515
516       list.Clear();
517       while(listing.Find())
518       {
519          if((!bits.foldersOnly && !bits.filesOnly) ||
520             (bits.foldersOnly && listing.stats.attribs.isDirectory) ||
521             (bits.filesOnly && !listing.stats.attribs.isDirectory/*listing.stats.attribs.isFile*/)) // TOCHECK: isFile broken?
522          {
523             FileSystemNode node = MakeFileSystemNode(listing.stats, listing.name, listing.path, bits.previewPictures, displaySystem);
524             DataRow row = list.AddRow();
525             row.tag = (int)node;
526             row.SetData(nameField, node);
527             if(bits.details)
528             {
529                row.SetData(typeField, node.extension);
530                row.SetData(sizeField, (void *)node.stats.size);
531             }
532          }
533       }
534       list.Sort(nameField, 1);
535    }
536
537    void LoadTree()
538    {
539       //char startPath[MAX_LOCATION];
540       FileSystemNode parent;
541       FileSystemNode node;
542       FileListing listing { path, extensions = extensions };
543       
544       /*if(!path)
545          GetWorkingDir(startPath, sizeof(startPath));
546       else
547          strcpy(path, startPath);*/
548       
549       list.Clear();
550
551       delete root;
552    #ifdef __WIN32__
553       root = FileSystemNode { type = computer, loaded = true, childrenLoaded = true };
554       root.name = rootName;
555       AddTreeNode(root, true, false, null);
556    #else
557       root = MakeFileSystemNode(FileStats { attribs = FileExists(path)}, path, path, bits.previewPictures, displaySystem);
558       //root.name = "/";
559       root.type = computer;
560       AddTreeNode(root, false, true, null);
561    #endif
562
563    #ifdef __WIN32__
564       while(listing.Find())
565       {
566          int len = strlen(listing.name);
567          char info[MAX_LOCATION];
568          char name[MAX_LOCATION];
569          if(listing.stats.attribs.isDrive && 
570                len > 3 && !strncmp(&listing.name[1], ": [", 3))
571          {
572             strncpy(name, listing.name, 2);
573             name[2] = 0;
574             strncpy(info, &listing.name[4], len - 5);
575             info[len - 5] = 0;
576          }
577          else
578          {
579             strcpy(name, listing.name);
580             info[0] = 0;
581          }
582
583          parent = MakeFileSystemNode(listing.stats, name);
584          if(info[0])
585             parent.info = CopyString(info);
586          parent.loaded = true;
587          AddTreeNode(parent, !listing.stats.attribs.isDirectory, listing.stats.attribs.isDirectory, root, this);
588          if(!listing.stats.attribs.isDirectory)
589             parent.childrenLoaded = true;
590       }
591
592       node = FileSystemNode { name = msNetwork, type = network };
593       AddTreeNode(node, false, true, null, this);
594       node.row.collapsed = true;
595       Sort(nameField, 1);
596       SelectRow(root.row);
597    #endif
598       LoadTreeNode(root);
599       list.Sort(nameField, 1);
600    }
601
602    void LoadTreeNode(FileSystemNode node)
603    {
604       if(!node.loaded)
605       {
606          char path[MAX_LOCATION];
607          node.GetPath(path);
608          {
609             FileListing listing { path, extensions = extensions };
610             if(node.children.count == 1)
611             DeleteNode(node.children.first);
612
613             while(listing.Find())
614             {
615                if((!bits.foldersOnly && !bits.filesOnly) ||
616                   (bits.foldersOnly && listing.stats.attribs.isDirectory) ||
617                   (bits.filesOnly && !listing.stats.attribs.isDirectory/*listing.stats.attribs.isFile*/)) // TOCHECK: isFile broken?
618                {
619                   FileSystemNode child = MakeFileSystemNode(listing.stats, listing.name, listing.path, bits.previewPictures, displaySystem);
620                   AddTreeNode(child, true, false, node);
621                   NodeChildLoad(child, node);
622                }
623             }
624          }
625          node.childrenLoaded = true;
626          node.loaded = true;
627          node.row.SortSubRows(false);
628       }
629       else if(!node.childrenLoaded)
630       {
631          FileSystemNode child;
632          if(node.children.first)
633          {
634             for(child = node.children.first; child; child = child.next)
635             {
636                if(!child.loaded)
637                   LoadTreeNode(child);
638                else if(!child.childrenLoaded)
639                   NodeChildLoad(child, node);
640             }
641             node.childrenLoaded = true;
642             node.row.SortSubRows(false);
643          }
644       }
645    }
646
647    void NodeChildLoad(FileSystemNode parent, FileSystemNode node)
648    {
649       char path[MAX_LOCATION];
650       parent.GetPath(path);
651       {
652          bool added = false;
653          FileListing listing { path, extensions = extensions };
654          while(listing.Find())
655          {
656             if((!bits.foldersOnly && !bits.filesOnly) ||
657                (bits.foldersOnly && listing.stats.attribs.isDirectory) ||
658                (bits.filesOnly && !listing.stats.attribs.isDirectory/*listing.stats.attribs.isFile*/)) // TOCHECK: isFile broken?
659             {
660                FileSystemNode child = MakeFileSystemNode(listing.stats, listing.name, listing.path, bits.previewPictures, displaySystem);
661                AddTreeNode(child, true, false, parent);
662                added = true;
663             }
664          }
665          if(!added)
666             added = true;
667       }
668       //parent.childrenLoaded = true;
669    }
670
671    void AddTreeNode(FileSystemNode node, bool loaded, bool addLoader, FileSystemNode addTo)
672    {
673       DataRow row = (addTo && addTo.row) ? addTo.row.AddRow() : list.AddRow();
674       if(addTo)
675       {
676          node.parent = addTo;
677          node.indent = addTo.indent + 1;
678          addTo.children.Add(node);
679       }
680       row.tag = (int)node;
681       node.row = row;
682       row.SetData(null, node);
683
684       node.loaded = loaded;
685       if(addLoader)
686          //AddTreeNode(FileSystemNode { }, false, false, node); // why would this create a compile error?
687          AddTreeNode(FileSystemNode { type = none }, false, false, node);
688
689       if(node.indent > 0)
690          row.collapsed = true;
691       else if(node.type == folder)
692          node.type = folderOpen;
693    }
694
695    void DeleteNode(FileSystemNode node)
696    {
697       FileSystemNode child;
698       for(; (child = node.children.first); )
699          DeleteNode(child);
700       list.DeleteRow(node.row);
701       node.Delete();
702    }
703 }
704
705 /*
706 #if 0
707 class ExplorerView : FileSystemBox
708 {
709    borderStyle = none;
710    hasHorzScroll = false;
711    hasVertScroll = false;
712
713    virtual void Load(FileSystemNode parent);
714    virtual void Refresh();
715
716    virtual void LaunchNotifyItemSelect(Window master, ExplorerView view, ExplorerFileItem item, ExplorerFileItemArray selectedItems)
717    {
718       view.NotifyItemSelect(master, view, item, selectedItems);
719    }
720
721    virtual bool Window::NotifyItemSelect(ExplorerView view, ExplorerFileItem item, ExplorerFileItemArray selectedItems);
722    virtual bool Window::NotifyItemOpen(ExplorerView view, ExplorerFileItem item);
723
724    ListBox list
725    {
726       master = master, parent = this;
727       //this, master;
728       borderStyle = none;
729       hasHorzScroll = true;
730       hasVertScroll = true;
731       resizable = true;
732       sortable = true;
733       fullRowSelect = false;
734       multiSelect = true;
735
736       anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
737
738       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
739       {
740          ExplorerView view = (ExplorerView)listBox.parent;
741          if(listBox.currentRow)
742          {
743             DataRow listRow;
744             ExplorerFileItemArray selectedItems { growingFactor = 16 };
745             for(listRow = listBox.firstRow; listRow; listRow = listRow.next)
746                if(listRow.selected)
747                   selectedItems.Add((ExplorerFileItem)listRow.tag);
748             //view.NotifyItemSelect(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag);
749             view.LaunchNotifyItemSelect(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag, selectedItems);
750          }
751          return true;
752       }
753
754       bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
755       {
756          ExplorerView view = (ExplorerView)listBox.parent;
757          view.NotifyItemOpen(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag);
758          return false;
759       }
760
761       bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
762       {
763          if((SmartKey)key == enter)
764          {
765             ExplorerView view = (ExplorerView)listBox.parent;
766             view.NotifyItemOpen(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag);
767          }
768          return true;
769       }
770    };
771
772    ExplorerView()
773    {
774    }
775 }
776 #endif
777
778 #if 0
779 class ExplorerViewList : ExplorerView
780 {
781
782    FileSystemNode location;
783
784 public:
785
786    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
787
788    ExplorerViewDetails()
789    {
790       list.AddField(nameField);
791    }
792
793    void Refresh()
794    {
795       Load(location);
796    }
797
798    void Load(FileSystemNode location)
799    {
800       char path[MAX_LOCATION];
801       this.location = location;
802       location.GetPath(path);
803       {
804          FileListing listing { path };
805          
806          ExplorerFileItem item;
807          DataRow row;
808
809          list.Clear();
810
811          while(listing.Find())
812          {
813             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
814
815             row = list.AddRow();
816             row.tag = (int)item;
817             row.SetData(nameField, item);
818          }
819          list.Sort(nameField, 1);
820       }
821    }
822 }
823 #endif
824
825 #if 0
826 class ExplorerViewDetails : ExplorerView
827 {
828    list.hasHeader = true;
829    list.moveFields = true;
830    list.resizable = true;
831    list.sortable = true;
832
833    FileSystemNode location;
834
835 public:
836
837    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
838    DataField typeField { header = "Type", dataType = /-*"String"*-/ "char *", width = 40 };
839    DataField sizeField { header = "Size", dataType = "FileSize", width = 96, alignment = right };
840
841    ExplorerViewDetails()
842    {
843       list.AddField(nameField);
844       list.AddField(typeField);
845       list.AddField(sizeField);
846    }
847
848    void Refresh()
849    {
850       Load(location);
851    }
852
853    void Load(FileSystemNode location)
854    {
855       char path[MAX_LOCATION];
856       this.location = location;
857       location.GetPath(path);
858       {
859          FileListing listing { path };
860          
861          ExplorerFileItem item;
862          DataRow row;
863
864          list.Clear();
865
866          while(listing.Find())
867          {
868             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
869
870             row = list.AddRow();
871             row.tag = (int)item;
872             row.SetData(nameField, item);
873             row.SetData(typeField, CopyString(item.extension));
874             row.SetData(sizeField, (uint)listing.stats.size);
875          }
876          list.Sort(nameField, 1);
877       }
878    }
879 }
880 #endif
881
882 #if 0
883 class ExplorerViewIcons : ExplorerView
884 {
885
886    FileSystemNode location;
887
888 public:
889
890    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
891
892    ExplorerViewDetails()
893    {
894       list.AddField(nameField);
895    }
896
897    void Refresh()
898    {
899       Load(location);
900    }
901
902    void Load(FileSystemNode location)
903    {
904       char path[MAX_LOCATION];
905       this.location = location;
906       location.GetPath(path);
907       {
908          FileListing listing { path };
909          
910          ExplorerFileItem item;
911          DataRow row;
912
913          list.Clear();
914
915          while(listing.Find())
916          {
917             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
918
919             row = list.AddRow();
920             row.tag = (int)item;
921             row.SetData(nameField, item);
922          }
923          list.Sort(nameField, 1);
924       }
925    }
926 }
927 #endif
928
929 #if 0
930 class ExplorerViewCards : ExplorerView
931 {
932
933    FileSystemNode location;
934
935 public:
936
937    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
938
939    ExplorerViewDetails()
940    {
941       list.AddField(nameField);
942    }
943
944    void Refresh()
945    {
946       Load(location);
947    }
948
949    void Load(FileSystemNode location)
950    {
951       char path[MAX_LOCATION];
952       this.location = location;
953       location.GetPath(path);
954       {
955          FileListing listing { path };
956          
957          ExplorerFileItem item;
958          DataRow row;
959
960          list.Clear();
961
962          while(listing.Find())
963          {
964             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
965
966             row = list.AddRow();
967             row.tag = (int)item;
968             row.SetData(nameField, item);
969          }
970          list.Sort(nameField, 1);
971       }
972    }
973 }
974 #endif
975
976 #if 0
977 public class BitmapArray : RedjArray
978 {
979    type = class(Bitmap);
980 public:
981    Bitmap * const _;
982    Bitmap * Add(Bitmap bitmap)
983    {
984       uint pos = _count;
985       Append(1);
986       _[pos] = bitmap;
987       return &_[pos];
988    }
989    Bitmap * AddBefore(uint position, Bitmap bitmap)
990    {
991       Insert(position, 1);
992       _[position] = bitmap;
993       return &_[position];
994    }
995    void Clear()
996    {
997       int c;
998       for(c = 0; c < _count; c++)
999       {
1000          _[c].Free();
1001          delete _[c];
1002       }  
1003       count = 0;
1004       size = 0;
1005    }
1006 }
1007 #endif
1008
1009 #if 0
1010 class ExplorerViewShowcase : ExplorerView
1011 {
1012    list.anchor = Anchor { left = 0, top = 0, bottom = 0 };
1013    list.size = Size { w = 200 };
1014
1015    FileSystemNode location;
1016
1017 public:
1018
1019    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 180, editable = true, userData = this };
1020
1021    Bitmap bitmap;
1022    BitmapArray bitmaps { growingFactor = 16 };
1023
1024    Window show
1025    {
1026       this;
1027       borderStyle = none;
1028       anchor = Anchor { top = 0, right = 0, bottom = 0 };
1029
1030       void OnRedraw(Surface surface)
1031       {
1032          ExplorerViewShowcase view = (ExplorerViewShowcase)parent;
1033          if(view.bitmap)
1034          {
1035             int wBmp = view.bitmap.width;
1036             int hBmp = view.bitmap.height;
1037             int wWnd = clientSize.w;
1038             int hWnd = clientSize.h;
1039
1040             int wList = view.list.size.w + view.split.size.w;
1041             
1042             float scale = Min((float)(wWnd - 10) / wBmp, (float)(hWnd - 10) / hBmp);
1043             
1044             int wDraw = (int)(wBmp * scale);
1045             int hDraw = (int)(hBmp * scale);
1046
1047       #ifndef __linux__
1048             surface.Filter(view.bitmap, (wWnd - wDraw) / 2, (hWnd - hDraw) / 2, 0, 0, wDraw, hDraw, wBmp, hBmp);
1049       #else
1050             // Until Filter / Stretch works with X
1051             surface.Blit(view.bitmap, (wWnd - wDraw) / 2, (hWnd - hDraw) / 2, 0, 0, wDraw, hDraw);
1052       #endif
1053          }
1054          else
1055          {
1056             surface.SetForeground(white);
1057             surface.Area(0, 0, view.clientSize.w - 1, view.clientSize.h - 1);
1058          }
1059       }
1060    }
1061
1062    SplitWindow split
1063    {
1064       this;
1065       leftPane = list;
1066       rightPane = show;
1067       split = 200;
1068       tabCycle = true;
1069    };
1070
1071    ExplorerViewDetails()
1072    {
1073       list.AddField(nameField);
1074    }
1075
1076    void LaunchNotifyItemSelect(Window master, ExplorerViewShowcase view, ExplorerFileItem item, ExplorerFileItemArray selectedItems)
1077    {
1078       int pos;
1079       ExplorerFileItem selItem;
1080       if(view.bitmap)
1081          view.bitmap.Free();
1082       delete view.bitmap;
1083       if(item && item.type == pictureFile)
1084       {
1085          view.bitmap = Bitmap { };
1086          view.bitmap.Load(item.path, null, displaySystem);
1087       }
1088
1089       view.bitmaps.Clear();
1090       view.bitmaps = BitmapArray { };
1091       for(pos = 0; pos < selectedItems.count; pos++)
1092       {
1093          Bitmap bitmap { };
1094          selItem = (ExplorerFileItem)selectedItems._[pos]; 
1095          bitmap.Load(selItem.path, null, displaySystem);
1096          //view.bitmaps.Add(bitmap);
1097       }  
1098       if(item && item.type == pictureFile)
1099       {
1100          view.bitmap = Bitmap { };
1101          view.bitmap.Load(item.path, null, displaySystem);
1102       }
1103
1104       view.show.Update(null);
1105       view.NotifyItemSelect(master, view, item, selectedItems);
1106    }
1107
1108    void Refresh()
1109    {
1110       Load(location);
1111    }
1112
1113    void Load(FileSystemNode location)
1114    {
1115       char path[MAX_LOCATION];
1116       this.location = location;
1117       location.GetPath(path);
1118       {
1119          FileListing listing { path };
1120          
1121          ExplorerFileItem item;
1122          DataRow row;
1123
1124          list.Clear();
1125
1126          while(listing.Find())
1127          {
1128             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
1129
1130             row = list.AddRow();
1131             row.tag = (int)item;
1132             row.SetData(nameField, item);
1133          }
1134          list.Sort(nameField, 1);
1135       }
1136    }
1137 }
1138 #endif
1139
1140 #if 0
1141 class ExplorerTree : FileSystemBox
1142 {
1143    hasHorzScroll = false;
1144    hasVertScroll = false;
1145
1146    menu = Menu { };
1147
1148 public:
1149
1150    DataField nameField { dataType = "FileSystemNode", width = 240, userData = this };
1151
1152    FileSystemNode root;
1153    FileSystemNode selection;
1154
1155    virtual bool Window::NotifyNodeSelect(ExplorerTree tree, FileSystemNode node);
1156    
1157    property FileSystemNode node
1158    {
1159       get
1160       {
1161          if(!tree)
1162             return null;
1163          if(!tree.currentRow)
1164             return null;
1165          if(!tree.currentRow.tag)
1166             return null;
1167          return (FileSystemNode)tree.currentRow.tag;
1168       }
1169    }
1170
1171    void Select(FileSystemNode node)
1172    {
1173       if(node.row)
1174       {
1175          node.EnsureVisible(false);
1176          tree.SelectRow(node.row);
1177       }
1178    }
1179
1180    FileSystemNode Find(const char * name, FileSystemNode parent)
1181    {
1182       FileSystemNode node;
1183       FileSystemNode start = parent ? parent : root;
1184       if(!start.loaded || !start.childrenLoaded)
1185          LoadTreeNode(start, tree);
1186       for(node = start.children.first; node; node = node.next)
1187          if(node.name && !strcmpi(node.name, name))
1188             return node;
1189       return null;
1190    }
1191
1192    ListBox tree
1193    {
1194       master = master, parent = this;
1195       //this, master;
1196       borderStyle = none;
1197       hasHorzScroll = true;
1198       hasVertScroll = true;
1199       fullRowSelect = false;
1200       treeNodees = true;
1201       collapseControl = true;
1202       rootCollapseButton = true;
1203
1204       anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
1205
1206       // WHY is this not working ?
1207       /-*void OnResize(int width, int height)
1208       {
1209          if(vertScroll.visible)
1210             nameField.width = width - vertScroll.size.w;
1211          else
1212             nameField.width = width;
1213       }*-/
1214
1215       bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed)
1216       {
1217          if(row)
1218          {
1219             FileSystemNode node = (FileSystemNode)row.tag;
1220             FileSystemNode child;
1221             if(collapsed)
1222             {
1223                /-*
1224                for(child = node.children.last; child; child = node.children.last)
1225                {
1226                   listBox.DeleteRow(child.row);
1227                   child.Free();
1228                   delete child;
1229                }
1230                node.childrenLoaded = false;
1231                *-/
1232             }
1233             else
1234             {
1235                if(!node.loaded || !node.childrenLoaded)
1236                   LoadTreeNode(node, tree);
1237                for(child = node.children.first; child && child.next; child = child.next);
1238                if(child)
1239                   child.EnsureVisible(false);
1240             }
1241          }
1242          return true;
1243       }
1244       
1245       bool NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods)
1246       {
1247          DataRow row = listBox.currentRow;
1248          if(row)
1249          {
1250             FileSystemNode node = (FileSystemNode)row.tag;
1251             if(node)
1252             {
1253                PopupMenu popup;
1254                Menu menu { };
1255
1256                MenuItem { menu, "Cut\tCtrl+X", t, NotifySelect = null, disabled = false };
1257                MenuItem { menu, "Copy\tCtrl+C", c, NotifySelect = null, disabled = false };
1258                MenuItem { menu, "Paste\tCtrl+V", p, NotifySelect = null, disabled = false /-*!clipboard*-/ };
1259                MenuItem { menu, "Delete\tDel", d, NotifySelect = null, disabled = false };
1260                //MenuDivider { menu };
1261
1262                popup = PopupMenu
1263                   {
1264                      master = this, menu = menu,
1265                      position = { 
1266                         x + clientStart.x + absPosition.x - guiApp.desktop.position.x, 
1267                         y + clientStart.y + absPosition.y - guiApp.desktop.position.y }
1268                   };
1269                popup.Create();
1270             }
1271          }
1272          return true;
1273       }
1274
1275       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
1276       {
1277          if(row)
1278          {
1279             FileSystemNode node = (FileSystemNode)row.tag;
1280             NotifyNodeSelect(listBox.parent.master, this, node);
1281             selection = node;
1282          }
1283          return true;
1284       }
1285
1286       bool NotifyEditing(ListBox listBox, DataRow row)
1287       {
1288          if(row)
1289          {
1290             FileSystemNode node = (FileSystemNode)row.tag;
1291          }
1292          return true;
1293       }
1294
1295       bool NotifyEdited(ListBox listBox, DataRow row)
1296       {
1297          if(row)
1298          {
1299             FileSystemNode node = (FileSystemNode)row.tag;
1300          }
1301          return true;
1302       }
1303
1304       bool NotifyEditDone(ListBox listBox, DataRow row)
1305       {
1306          if(row)
1307          {
1308             FileSystemNode node = (FileSystemNode)row.tag;
1309          }
1310          return true;
1311       }
1312    };
1313
1314    // Edit Menu
1315    Menu editMenu { menu, "Edit", e };
1316    MenuItem itemEditCut
1317    {
1318       editMenu, "Cut\tCtrl+X", t, disabled = true;
1319
1320       bool NotifySelect(MenuItem selection, Modifiers mods)
1321       {
1322          //EditCut();
1323          return true;
1324       }
1325    };
1326    MenuItem itemEditCopy
1327    {
1328       editMenu, "Copy\tCtrl+C", c, disabled = true;
1329
1330       bool NotifySelect(MenuItem selection, Modifiers mods)
1331       {
1332          //EditCopy();
1333          return true;
1334       }
1335    };
1336    MenuItem itemEditPaste
1337    {
1338       editMenu, "Paste\tCtrl+V", p;
1339    
1340       bool NotifySelect(MenuItem selection, Modifiers mods)
1341       {
1342          //EditPaste();
1343          return true;
1344       }
1345    };
1346    MenuItem itemEditDelete
1347    {
1348       editMenu, "Delete\tDel", d, disabled = true;
1349
1350       bool NotifySelect(MenuItem selection, Modifiers mods)
1351       {
1352          //EditDelete();
1353          return true;
1354       }
1355    };
1356
1357    // WHY is this crashing ? 
1358    /-*void OnResize(int width, int height)
1359    {
1360       if(this && nameField)
1361          nameField.width = width - 80;
1362    }*-/
1363
1364    ExplorerTree()
1365    {
1366       tree.AddField(nameField);
1367    }
1368
1369    void Load()
1370    {
1371       FileSystemNode parent;
1372       FileSystemNode node;
1373       FileListing listing { "/" };
1374
1375       tree.Clear();
1376
1377       root = FileSystemNode { type = computer, loaded = true, childrenLoaded = true };
1378    #ifdef __WIN32__
1379       root.name = rootName;
1380    #else
1381       root.name = "/";
1382    #endif
1383       AddTreeNode(root, true, false, null, tree);
1384
1385    // How can this make sense for linux? 
1386    #ifdef __WIN32__
1387       while(listing.Find())
1388       {
1389          int len = strlen(listing.name);
1390          char info[MAX_LOCATION];
1391          char name[MAX_LOCATION];
1392          if(listing.stats.attribs.isDrive && 
1393                len > 3 && !strncmp(&listing.name[1], ": [", 3))
1394          {
1395             strncpy(name, listing.name, 2);
1396             name[2] = 0;
1397             strncpy(info, &listing.name[4], len - 5);
1398             info[len - 5] = 0;
1399          }
1400          else
1401          {
1402             strcpy(name, listing.name);
1403             info[0] = 0;
1404          }
1405
1406          parent = MakeFileSystemNode(listing.stats, name);
1407          if(info[0])
1408             parent.info = CopyString(info);
1409          parent.loaded = true;
1410          AddTreeNode(parent, !listing.stats.attribs.isDirectory, listing.stats.attribs.isDirectory, root, tree);
1411          if(!listing.stats.attribs.isDirectory)
1412             parent.childrenLoaded = true;
1413       }
1414    #endif
1415       node = FileSystemNode { name = msNetwork, type = network };
1416       AddTreeNode(node, false, true, null, tree);
1417       node.row.collapsed = true;
1418       tree.Sort(nameField, 1);
1419       tree.SelectRow(root.row);
1420    }
1421 }
1422
1423 #if 0
1424 public class ClipBoardFiles
1425 {
1426
1427 public:
1428
1429    property
1430
1431 }
1432
1433    // CLIPBOARD
1434    void Copy()
1435    {
1436       if(this)
1437       {
1438          int size = SelSize();
1439          if(size)
1440          {
1441             // Try to allocate memory
1442             ClipBoard clipBoard { };
1443             if(clipBoard.Allocate(size+1))
1444             {
1445                GetSel(clipBoard.memory, true);   
1446                // Save clipboard
1447                clipBoard.Save();
1448             }
1449             delete clipBoard;
1450          }
1451       }
1452    }
1453
1454    void Paste()
1455    {
1456       if(this)
1457       {
1458          ClipBoard clipBoard { };
1459          if(clipBoard.Load())
1460             PutS(clipBoard.memory);
1461          delete clipBoard;
1462       }
1463    }
1464
1465    void Cut()
1466    {
1467       if(this)
1468       {
1469          Copy();
1470          DelSel();
1471          SetViewToCursor(true);
1472          Modified();
1473       }
1474    }
1475
1476 /-*
1477 Private Type DROPFILES
1478    pFiles As Long
1479    pt As POINTAPI
1480    fNC As Long
1481    fWide As Long
1482 End Type
1483 For iCounter = 0 To filelist.ListCount - 1
1484   If filelist.Selected(iCounter) = True Then
1485     strFiles = strFiles & FixPath(filelist.Path) & filelist.List(iCounter) & vbNullChar
1486   End If
1487 Next
1488 'all selected items are now put in strFiles
1489
1490 hGlobal = GlobalAlloc(GHND, Len(DF) + Len(strFiles)) 'put all files to a exclusive number
1491 If hGlobal Then 'if the globalalloc worked
1492   lpGlobal = GlobalLock(hGlobal) 'lock the hGlobal
1493   DF.pFiles = Len(DF) 'set the size of the files
1494   
1495   Call CopyMem(ByVal lpGlobal, DF, Len(DF)) 'copy df to the lpglobal
1496   Call CopyMem(ByVal (lpGlobal + Len(DF)), ByVal strFiles, Len(strFiles)) 'copy strfiles to lpglobal
1497   Call GlobalUnlock(hGlobal) 'unlock hglobal again
1498   
1499   SetClipboardData CF_HDROP, hGlobal 'put files to the clipboard
1500 End If
1501 *-/
1502    bool SaveFile(const char * filePath)
1503    {
1504    }
1505 #endif
1506
1507 #if 0
1508 public class FileTreeNodeBSArray : ArrayBinarySorted
1509 {
1510    type = class(FileSystemNode);
1511 public:
1512    FileSystemNode * const _;
1513    BSloc Add(FileSystemNode item)
1514    {
1515       BSloc result = Find(item);
1516       if(!result.valid)
1517       {
1518          Insert(result.pos, 1);
1519          _[result.pos] = item;
1520       }
1521       return result;
1522    }
1523    BSloc Remove(FileSystemNode item)
1524    {
1525       
1526    }
1527 }
1528 #endif
1529
1530 #if 0
1531 public class FileTreeNodeArray : RedjArray
1532 {
1533    type = class(FileSystemNode);
1534 public:
1535    FileSystemNode * const _;
1536    FileSystemNode * Add(FileSystemNode item)
1537    {
1538       uint pos = _count;
1539       Append(1);
1540       _[pos] = item;
1541       return &_[pos];
1542    }
1543    FileSystemNode * AddBefore(uint position, FileSystemNode item)
1544    {
1545       Insert(position, 1);
1546       _[position] = item;
1547       return &_[position];
1548    }
1549 }
1550 #endif
1551
1552 #if 0
1553 public class ExplorerFileItem : struct
1554 {
1555    char * path;
1556    char * name;
1557    char * info;
1558    char * extension;
1559    _FileType type;
1560    int indent;
1561
1562    Bitmap bitmap;
1563
1564    void OnDisplay(Surface surface, int x, int y, int width, FileSystemBox control, Alignment alignment, DataDisplayFlags displayFlags)
1565    {
1566       int indentSize = (displayFlags.dropBox) ? 0 : 10;
1567       int textOffset;
1568       int len;
1569       char label[MAX_FILENAME];
1570
1571       //float scale = Min((float)clientSize.w / (float)bitmap.width, (float)clientSize.h / (float)bitmap.height);
1572       int w = 16; //(int)(bitmap.width * scale);
1573       int h = 16; //(int)(bitmap.height * scale);
1574    
1575       Bitmap icon;
1576
1577       icon = control.fileIcons[type].bitmap;
1578       if(!icon)
1579       {
1580          if(type == folder || type == folderOpen)
1581             surface.SetForeground(red); //Color { 170, 170, 0 } // REDJ What is that color?
1582          indentSize = 8;
1583       }
1584       textOffset = indent * indentSize + (icon ? (icon.width + 6) : 0);
1585       
1586       if(info)
1587          sprintf(label, "%s [%s]", name, info);
1588       else
1589          strcpy(label, name);
1590       len = strlen(label);
1591
1592       surface.WriteTextDots
1593          (alignment, x + textOffset, y + 2, width - textOffset, label, len);
1594       if(type == pictureFile && control.previewPictures && bitmap)
1595       {
1596 #ifndef __linux__
1597          //surface.Filter(bitmap, (clientSize.w - w) / 2,(clientSize.h - h) / 2, 0,0, w, h, bitmap.width, bitmap.height);
1598          surface.Filter(bitmap, x + indent * indentSize + 2, y, 0, 0, w, h, bitmap.width, bitmap.height);
1599 #else
1600          // Until Filter / Stretch works with X
1601          //surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2,(clientSize.h - bitmap.height) / 2, 0,0, bitmap.width, bitmap.height);
1602          surface.blend = true;
1603          surface.Blit(bitmap, x + indent * indentSize + 2, y,0,0, w, h);
1604 #endif
1605          //bitmap.Free();
1606          //delete bitmap;
1607       }
1608       else if(icon)
1609          surface.Blit(icon, x + indent * indentSize + 2, y,0,0, icon.width, icon.height);
1610    }
1611
1612    int OnCompare(ExplorerFileItem b)
1613    {
1614       int result;
1615       if(type == b.type || (type < folder && b.type < folder) || (type >= drive))
1616          result = strcmpi(name, b.name);
1617       else
1618       {
1619          if(type == folder && b.type < folder) result = -1;
1620          else if(type < folder && b.type == folder) result = 1;
1621       }
1622       return result;
1623    }
1624
1625    void OnCopy(ExplorerFileItem newData)
1626    {
1627       type = newData.type;
1628       indent = newData.indent;
1629       if(newData.name)
1630       {
1631          int len = strlen(newData.name) + 1;
1632          name = new char[len];
1633          CopyBytes(name, newData.name, len);
1634       }
1635    }
1636
1637    bool OnGetDataFromString(char * string)
1638    {
1639       int len = strlen(string) + 1;
1640       name = new char[len];
1641       CopyBytes(name, string, len);
1642       return true;
1643    }
1644
1645    void OnFree()
1646    {
1647       delete path;
1648       delete name;
1649       delete info;
1650       delete extension;
1651       if(bitmap)
1652          bitmap.Free();
1653    }
1654
1655    char * OnGetString(char * string, void * fieldData, bool * needClass)
1656    {
1657       return name;
1658    }
1659 };
1660
1661 public class ExplorerFileItemArray : RedjArray
1662 {
1663    type = class(ExplorerFileItem);
1664 public:
1665    ExplorerFileItem * const _;
1666    ExplorerFileItem * Add(ExplorerFileItem item)
1667    {
1668       uint pos = _count;
1669       Append(1);
1670       _[pos] = item;
1671       return &_[pos];
1672    }
1673    ExplorerFileItem * AddBefore(uint position, ExplorerFileItem item)
1674    {
1675       Insert(position, 1);
1676       _[position] = item;
1677       return &_[position];
1678    }
1679    void Clear()
1680    {
1681       int c;
1682       for(c = 0; c < _count; c++)
1683       {
1684          //_[c].Free()
1685          delete _[c];
1686       }  
1687       count = 0;
1688       size = 0;
1689    }
1690 }
1691
1692 ExplorerFileItem MakeFileItem(const FileAttribs attribs, const char * fileName, const char * filePath, const bool previewPicture, const DisplaySystem displaySystem)
1693 {
1694    int len = strlen(fileName);
1695    char info[MAX_LOCATION];
1696    char name[MAX_LOCATION];
1697    char extension[MAX_EXTENSION];
1698    
1699    ExplorerFileItem item { };
1700
1701    //if(attribs.isFile) // TODO fix this in ecere
1702    if(attribs.isDirectory)
1703    {
1704       extension[0] = 0;
1705
1706       item.type = (attribs.isDrive) ? drive : folder;
1707       if(attribs.isServer)
1708          item.type = server;
1709       if(attribs.isShare)
1710          item.type = share;
1711       if(attribs.isCDROM)
1712          item.type = cdrom;
1713       if(attribs.isRemote)
1714          item.type = netDrive;
1715       if(attribs.isRemovable) 
1716       {
1717          if(fileName[0] == 'A' || fileName[0] == 'B')
1718             item.type = floppy;
1719          else
1720             item.type = removable;
1721       }
1722    }
1723    else
1724    {
1725       GetExtension(fileName, extension);
1726       //strupr(extension);
1727       strlwr(extension);
1728       
1729       item.type = _FileType::SelectByExtension(extension);
1730    }
1731
1732    if(attribs.isDrive && 
1733          len > 3 && !strncmp(&fileName[1], ": [", 3))
1734    {
1735       strncpy(name, fileName, 2);
1736       name[2] = 0;
1737       strncpy(info, &fileName[4], len - 5);
1738       info[len - 5] = 0;
1739    }
1740    else
1741    {
1742       strcpy(name, fileName);
1743       info[0] = 0;
1744    }
1745
1746    item.path = CopyString(filePath);
1747    item.name = CopyString(name);
1748    if(info[0])
1749       item.info = CopyString(info);
1750    item.extension = CopyString(extension);
1751
1752    if(item.type == pictureFile && previewPicture)
1753    {
1754       item.bitmap = Bitmap { };
1755       item.bitmap.Load(filePath, null, displaySystem);
1756    }
1757
1758    return item;
1759 }
1760 #endif
1761 */
1762
1763 public class FileSystemNode : struct
1764 {
1765 public:
1766    /*//LinkElement<FileSystemNode> link;
1767    FileSystemNode parent;
1768
1769    FileSystemNodeType type;
1770
1771    char * name;*/
1772
1773    FileSystemNode prev, next;
1774
1775    bool loaded, childrenLoaded;
1776    int indent;
1777    char * path;
1778    char * name;
1779    char * extension;
1780    char * info;
1781    DataRow row;
1782    OldList children;
1783    _FileType type;
1784    FileSystemNode parent;
1785
1786    FileStats stats;
1787
1788    Bitmap bitmap;
1789
1790    void GetPath(String outputPath)
1791    {  
1792       FileSystemNode up;
1793       if(parent)
1794       {
1795          strcpy(outputPath, name);
1796          for(up = parent; up; up = up.parent)
1797          {
1798             char temp[MAX_LOCATION];
1799             strcpy(temp, up.name);
1800             PathCat(temp, outputPath);
1801             strcpy(outputPath, temp);
1802          }
1803       }
1804       else
1805 #ifdef __WIN32__
1806          strcpy(outputPath, "/");
1807 #else
1808          strcpy(outputPath, name);
1809 #endif
1810
1811    }
1812
1813    bool IsChildOf(FileSystemNode node)
1814    {
1815       FileSystemNode test;
1816       for(test = parent; test; test = test.parent)
1817          if(test == node)
1818             return true;
1819       return false;
1820    }
1821
1822    void DuplicateChildren(bool recursive, bool forceExpanded, FileSystemNode addTo, FileSystemBox fsb)
1823    {
1824       if(children.first)
1825       {
1826          FileSystemNode child;
1827          
1828          for(child = children.first; child; child = child.next)
1829          {
1830             FileSystemNode copy { };
1831             copy.name = CopyString(child.name);
1832             copy.type = child.type;
1833             fsb.AddTreeNode(copy, child.loaded, false, addTo);
1834             if(forceExpanded)
1835                copy.row.collapsed = false;
1836             if(recursive)
1837                child.DuplicateChildren(recursive, forceExpanded, copy, fsb);
1838          }
1839       }
1840    }
1841    
1842    void EnsureVisible(bool expand)
1843    {
1844       if(parent)
1845          parent.EnsureVisible(true);
1846       if(expand)
1847          row.collapsed = false;
1848       // TODO: row.EnsureVisible(); // making the row visible by scrolling
1849    }
1850
1851    void OnFree()
1852    {
1853       //delete name;
1854    }
1855
1856    void Free()
1857    {
1858       FileSystemNode child;
1859       for(; (child = children.first); )
1860       {
1861          child.Free();
1862          children.Delete(child);
1863       }
1864       //if(name)
1865       delete name;
1866       delete info;
1867    }
1868
1869    void Delete()
1870    {
1871       Free();
1872       if(parent)
1873          parent.children.Delete(this);
1874    }
1875
1876    void OnDisplay(Surface surface, int x, int y, int width, FileSystemBox fsb, Alignment alignment, DataDisplayFlags displayFlags)
1877    {
1878       //int indentSize = (displayFlags.dropBox) ? 0 : 10;
1879       int indent = 16;
1880       int xStart;
1881       int len;
1882       int w, h;
1883       //int textOffset;
1884       char label[MAX_FILENAME];
1885
1886       Bitmap icon;
1887
1888       if(!this)
1889          return;
1890       
1891       icon = fsb.fileIcons[type].bitmap;
1892       //xStart = indent * indent + x + (icon ? (icon.width + 5) : 0);
1893       xStart = x + (icon ? (icon.width + 5) : 0);
1894
1895       if(!name)
1896          return;
1897
1898       if(info)
1899          sprintf(label, "%s [%s]", name, info);
1900       else
1901          strcpy(label, name);
1902       len = strlen(label);
1903       
1904       if(!icon)
1905       {
1906          if(type == folder || type == folderOpen)
1907             surface.SetForeground(yellow);
1908          //indentSize = 8;
1909          indent = 8;
1910       }
1911       //textOffset = indent * indentSize + (icon ? (icon.width + 4) : 0);
1912       
1913       surface.TextOpacity(false);
1914       surface.TextExtent(label, len, &w, &h);
1915       h = Max(h, 16);
1916     
1917       // Draw the current row stipple
1918       if(displayFlags.selected)
1919          //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1920          //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1921          surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1922       
1923       //surface.WriteTextDots(alignment, x + textOffset, y + 2, width - textOffset, name, strlen(name));
1924       surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1925
1926       //if(!guiApp.textMode) -- how to do this in a dll?
1927       {
1928          if(displayFlags.current)
1929          {
1930             if(displayFlags.active)
1931             {
1932                surface.LineStipple(0x5555);
1933                if(displayFlags.selected)
1934                   surface.SetForeground(0xFFFFFF80);
1935                else
1936                   surface.SetForeground(black);
1937             }
1938             else
1939             {
1940                surface.SetForeground(selectionColor);
1941             }
1942             surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1943             surface.LineStipple(0);
1944          }
1945
1946          if(icon)
1947          {
1948             w = icon.width;
1949             h = icon.height;
1950          }
1951          if(type == pictureFile && fsb.previewPictures && bitmap)
1952          {
1953             surface.SetForeground(white);
1954             surface.blend = true;
1955    //#ifndef __linux__
1956             //surface.Filter(bitmap, (clientSize.w - w) / 2,(clientSize.h - h) / 2, 0,0, w, h, bitmap.width, bitmap.height);
1957             //surface.Filter(bitmap, x + indent/* * indentSize*/ + 2, y, 0, 0, w, h, bitmap.width, bitmap.height);
1958             surface.Filter(bitmap, x,y,0,0, w, h, bitmap.width, bitmap.height);
1959    //#else
1960             // Until Filter / Stretch works with X
1961             //surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2,(clientSize.h - bitmap.height) / 2, 0,0, bitmap.width, bitmap.height);
1962    //         surface.blend = true;
1963             //surface.Blit(bitmap, x + indent/* * indentSize*/ + 2, y,0,0, w, h);
1964             //surface.Blit(bitmap, x,y,0,0, bitmap.width, bitmap.height);
1965    //#endif
1966             //bitmap.Free();
1967             //delete bitmap;
1968          }
1969          else if(icon)
1970          {
1971             //surface.blend = true;
1972             //surface.alphaWrite = blend;
1973             surface.SetForeground(white);
1974             //surface.Blit(icon, x + indent * indentSize, y,0,0, icon.width, icon.height);
1975             surface.Blit(icon, x,y,0,0, icon.width, icon.height);
1976          }
1977       }
1978    }
1979
1980    int OnCompare(FileSystemNode b)
1981    {
1982       int result;
1983       FileSystemNode a = this;
1984       if(a.type == b.type || (a.type < folder && b.type < folder) || (a.type >= drive))
1985          result = strcmpi(a.name, b.name);
1986       else
1987       {
1988          if(a.type == folder && b.type < folder) result = -1;
1989          else if(a.type < folder && b.type == folder) result = 1;
1990          else result = 0;
1991       }
1992       return result;
1993    }
1994
1995    /*int OnCompare(FileSystemNode b)
1996    {
1997       int result;
1998       FileSystemNode a = this;
1999       if(a.parent < b.parent) result = -1;
2000       else if(a.parent > b.parent) result = 1;
2001       else
2002          result = fstrcmp(a.name, b.name);
2003       return result;
2004    }*/
2005
2006    char * OnGetString(char * tempString, FileSystemToolWindow fileSysToolWnd, bool * needClass)
2007    {
2008       return name ? name : "";
2009    }
2010 }
2011
2012 /*FileSystemNode MakeFileSystemNode(const FileStats stats, const char * name)
2013 {
2014    FileSystemNode node { stats = stats };
2015    node.name = CopyString(name);
2016    if(!node.name)
2017       node.name = null;
2018    if(stats.attribs.isDirectory)
2019    {
2020       node.type = (stats.attribs.isDrive) ? drive : folder;
2021       if(stats.attribs.isServer) node.type = server;
2022       if(stats.attribs.isShare) node.type = share;
2023       if(stats.attribs.isCDROM) node.type = cdrom;
2024       if(stats.attribs.isRemote) node.type = netDrive;
2025       if(stats.attribs.isRemovable) 
2026       {
2027          if(name[0] == 'A' || name[0] == 'B')
2028             node.type = floppy;
2029          else
2030             node.type = removable;
2031       }
2032    }
2033    else
2034    {
2035       char extension[MAX_EXTENSION];
2036       GetExtension(node.name, extension);
2037       node.type = _FileType::SelectByExtension(extension);
2038    }
2039    return node;
2040 }*/
2041 static FileSystemNode MakeFileSystemNode(const FileStats stats,
2042       const char * fileName, const char * filePath,
2043       const bool previewPicture, const DisplaySystem displaySystem)
2044 {
2045    int len = strlen(fileName);
2046    char info[MAX_LOCATION];
2047    char name[MAX_LOCATION];
2048    char extension[MAX_EXTENSION];
2049    
2050    FileSystemNode node { stats = stats };
2051
2052    //if(stats.attribs.isFile) // TODO fix this in ecere
2053    if(stats.attribs.isDirectory)
2054    {
2055       extension[0] = '\0';
2056
2057       node.type = (stats.attribs.isDrive) ? drive : folder;
2058       if(stats.attribs.isServer) node.type = server;
2059       if(stats.attribs.isShare) node.type = share;
2060       if(stats.attribs.isCDROM) node.type = cdrom;
2061       if(stats.attribs.isRemote) node.type = netDrive;
2062       if(stats.attribs.isRemovable) 
2063       {
2064          if(fileName[0] == 'A' || fileName[0] == 'B')
2065             node.type = floppy;
2066          else
2067             node.type = removable;
2068       }
2069    }
2070    else
2071    {
2072       GetExtension(fileName, extension);
2073       strlwr(extension);
2074       
2075       node.type = _FileType::SelectByExtension(extension);
2076    }
2077
2078    if(stats.attribs.isDrive && 
2079          len > 3 && !strncmp(&fileName[1], ": [", 3))
2080    {
2081       strncpy(name, fileName, 2);
2082       name[2] = 0;
2083       strncpy(info, &fileName[4], len - 5);
2084       info[len - 5] = 0;
2085    }
2086    else
2087    {
2088       strcpy(name, fileName);
2089       info[0] = 0;
2090    }
2091
2092    node.path = CopyString(filePath);
2093    node.name = CopyString(name);
2094    if(info[0])
2095       node.info = CopyString(info);
2096    node.extension = CopyString(extension);
2097
2098    if(node.type == pictureFile && previewPicture)
2099    {
2100       node.bitmap = Bitmap { alphaBlend = true };
2101       node.bitmap.Load(filePath, null, displaySystem);
2102    }
2103
2104    return node;
2105 }