bunch of changes, unfortunate lack of commits
[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).application);
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, pathColumn:1, treeBranches:1, previewPictures:1, navigateFolders:1, autoLoad:1;
143    bool preview:1;
144    //bool header:1, freeSelect:1, fullRowSelect:1, multiSelect:1, autoScroll:1, alwaysHL : 1, moveRows:1, resizable:1;
145    //bool moveFields:1, clearHeader:1, alwaysEdit:1, collapse:1, treeBranch:1, rootCollapse:1, heightSet:1;
146    //bool sortable:1, noDragging:1, fillLastField:1, expandOnAdd:1;
147 };
148
149 public class FileSystemBox : Window // should we not derive from ListBox instead?
150                                     // I say we should, but we can't right now...
151                                     // because ListBox (inside ecere library) is
152                                     // not exposing enough internal machinery...
153                                     // could we not have a different private and
154                                     // public mechanism when deriving a class than
155                                     // we do when simply instanciating a class?
156 /*
157    this stuff from the listbox would be nicely exposed...
158       fullRowSelect = false;
159       treeBranches = true;
160       collapseControl = true;
161       rootCollapseButton = true;
162       sortable = true;
163 */
164 {
165    borderStyle = deep;
166    hasHorzScroll = false;
167    hasVertScroll = false;
168
169    menu = Menu { };
170
171 public:
172    FileSystemNode root;
173    FileSystemBoxSelection selection { };
174
175    virtual bool Window::NotifyNodeSelect(FileSystemBox box, FileSystemBoxSelection selection);
176    //virtual bool Window::NotifyNodeNavigate(FileSystemBox box, FileSystemNode node);
177    virtual bool Window::NotifyNodeOpen(FileSystemBox box, FileSystemBoxSelection selection);
178    
179    property char * path
180    {
181       set
182       {
183          delete path;
184          if(value && value[0])
185             path = CopyString(value);
186          if(locationBox)
187             locationBox.path = value;
188          if(created)
189             Load();
190       }
191
192       get { return path; }
193       //isset { return path && path[0]; }
194    }
195
196    property bool foldersOnly { set { bits.foldersOnly = value; bits.filesOnly = !value; } get { return bits.foldersOnly; } };
197    property bool filesOnly { set { bits.filesOnly = value; bits.foldersOnly = !value; } get { return bits.filesOnly; } };
198    property bool previewPictures { set { bits.previewPictures = value; } get { return bits.previewPictures; } };
199    property char * extensions { set { delete extensions; if(value && value[0]) extensions = CopyString(value); } get { return extensions; } }
200    property bool details { set { bits.details = value; ChangeViewType(); } get { return bits.details; } };
201    property bool pathColumn { set { bits.pathColumn = value; ChangeViewType(); } get { return bits.pathColumn; } };
202    property bool treeBranches
203    {
204       set
205       {
206          bits.treeBranches = value;
207          list.treeBranches = value;
208          list.collapseControl = value;
209          list.rootCollapseButton = value;
210       }
211       get { return bits.treeBranches; }
212    };
213    property Color selectionColor { set { list.selectionColor = value; } get { return list.selectionColor; }/* isset { return selectionColor ? true : false; }*/ };
214    property Color selectionText  { set { list.selectionText = value; } get { return list.selectionText; }/* isset { return selectionText ? true : false; }*/ };
215    property bool navigateFolders { set { bits.navigateFolders = value; bits.filesOnly = !value; } get { return bits.navigateFolders; } };
216    property bool multiSelect { set { list.multiSelect = value; } get { return list.multiSelect; } };
217    property bool autoLoad { set { bits.autoLoad = value; } get { return bits.autoLoad; } };
218    property bool hasHeader { set { list.hasHeader = value; } get { return list.hasHeader; } };
219    property bool preview
220    {
221       set
222       {
223          bits.preview = value;
224          split.leftPane = value ? list : null;
225          split.visible = value;
226          show.visible = value;
227       }
228       get { return bits.preview; }
229    };
230    
231    property FileSystemNode node
232    {
233       get
234       {
235          if(!list)
236             return null;
237          if(!list.currentRow)
238             return null;
239          if(!list.currentRow.tag)
240             return null;
241          return (FileSystemNode)list.currentRow.tag;
242       }
243    }
244
245    PathBox locationBox;
246
247    void Select(FileSystemNode node)
248    {
249       if(node.row)
250       {
251          node.EnsureVisible(false);
252          list.SelectRow(node.row);
253       }
254    }
255
256    void SelectMultipleByPath(Array<String> paths)
257    {
258       DataRow row;
259       bool firstRow = false;
260       Map<String, bool> map { };
261       for(path : paths)
262          map[path] = true;
263       for(row = list.firstRow; row; row = row.next)
264       {
265          FileSystemNode node = (FileSystemNode)row.tag;
266          if(map[node.path])
267          {
268             if(!firstRow)
269             {
270                list.SelectRow(row);
271                firstRow = true;
272             }
273             else
274                row.selected = true;
275          }
276          else
277             row.selected = false;
278       }
279       delete map;
280    }
281
282    FileSystemNode SelectLocation(char * location)
283    {
284       int c;
285       char * temp;
286       char step[MAX_LOCATION];
287
288       //StringArray steps { growingFactor = 4 };
289       Array<String> steps { };
290       FileSystemNode result = null;
291       FileSystemNode node = null;
292
293       temp = CopyString(location);
294       while(temp[0])
295       {
296          GetLastDirectory(temp, step);
297          StripLastDirectory(temp, temp);
298          steps.Add(CopyString(step));
299       }
300
301       for(c = steps.count - 1; c >= 0; c--)
302       {
303          char * t = steps[c];
304          node = Find(steps[c], node);
305          if(!node)
306             break;
307          //Select(node);
308       }
309       if(node)
310       {
311          result = node;
312          Select(result);
313       }
314
315       steps.Free();
316       delete temp;
317       delete steps;
318
319       return result;
320    }
321
322    FileSystemNode Find(const char * name, FileSystemNode parent)
323    {
324       FileSystemNode node = null;
325       FileSystemNode result = null;
326       if(!parent/* && !strcmp(name, "/")*/)
327       {
328          DataRow row;
329          for(row = list.firstRow; row; row = row.next)
330          {
331             node = (FileSystemNode)row.tag;
332             if(node.name && !fstrcmp(node.name, name))
333                break;
334          }
335          if(node)
336             result = node;
337          //result = root;
338       }
339       else
340       {
341          FileSystemNode start = parent ? parent : root;
342          if(!start.bits.loaded || !start.bits.childrenLoaded)
343             LoadTreeNode(start);
344          for(node = start.children.first; node; node = node.next)
345             if(node.name && !fstrcmp(node.name, name))
346                break;
347          if(node)
348             result = node;
349       }
350       return result;
351    }
352
353    void Clear()
354    {
355       list.Clear();
356    }
357
358    void Refresh()
359    {
360       Load();
361    }
362
363 private:
364    FileSystemBoxBits bits;
365
366    char * path;
367    char * extensions;
368
369    BitmapResource fileIcons[_FileType];
370
371    Bitmap bitmap;
372    //BitmapArray bitmaps { growingFactor = 16 };
373
374    FileSystemBox()
375    {
376       char wd[MAX_LOCATION];
377       GetWorkingDir(wd, sizeof(wd));
378       property::path = wd;
379       
380       InitFileIcons();
381       list.AddField(nameField);
382       bits.autoLoad = true;
383    }
384
385    ~FileSystemBox()
386    {
387       delete extensions;
388       delete path;
389    }
390
391    watch(background)
392    {
393       list.background = background;
394    };
395
396    void InitFileIcons()
397    {
398       _FileType c;
399       for(c = 0; c < _FileType::enumSize; c++)
400       {
401          fileIcons[c] = BitmapResource { fileIconNames[c], alphaBlend = true };
402          AddResource(fileIcons[c]);
403       }
404    }
405
406    DataField nameField { header = "Name", dataType = "FileSystemNode", width = 240, userData = this, freeData = false };
407    DataField pathField { header = "Location", dataType = /*"String"*/ "char *", width = 300, freeData = false };
408    DataField typeField { header = "Type", dataType = /*"String"*/ "char *", width = 40, freeData = false };
409    DataField sizeField { header = "Size", dataType = "FileSize", width = 96, alignment = right, freeData = false };
410    DataField modifiedField { header = "Modified", dataType = "SecSince1970", width = 96, alignment = right, freeData = false };
411
412    bool OnPostCreate()
413    {
414       if(bits.autoLoad)
415          Load();
416       return true;
417    }
418
419    ListBox list
420    {
421       this;
422
423       borderStyle = none;
424       hasHorzScroll = true;
425       hasVertScroll = true;
426       fullRowSelect = false;
427       sortable = true;
428       alwaysHighLight = true;
429
430       anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
431
432       // WHY is this not working ?
433       /*void OnResize(int width, int height)
434       {
435          if(vertScroll.visible)
436             nameField.width = width - vertScroll.size.w;
437          else
438             nameField.width = width;
439       }*/
440
441       bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed)
442       {
443          if(row)
444          {
445             FileSystemNode node = (FileSystemNode)row.tag;
446             FileSystemNode child;
447             if(collapsed)
448             {
449                /*
450                for(child = node.children.last; child; child = node.children.last)
451                {
452                   listBox.DeleteRow(child.row);
453                   child.Free();
454                   delete child;
455                }
456                node.childrenLoaded = false;
457                */
458             }
459             else
460             {
461                if(!node.bits.loaded || !node.bits.childrenLoaded)
462                {
463                   LoadTreeNode(node);
464                   //list.Sort(nameField, 1);
465                   //node.
466                }
467                for(child = node.children.first; child && child.next; child = child.next);
468                if(child)
469                   child.EnsureVisible(false);
470             }
471          }
472          return true;
473       }
474       
475       bool NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods)
476       {
477          DataRow row = listBox.currentRow;
478          if(row)
479          {
480             FileSystemNode node = (FileSystemNode)row.tag;
481             if(node)
482             {
483                char * text;
484
485                PopupMenu popup;
486                Menu menu { };
487
488                text = PrintString("Open ", node.path);
489
490                MenuItem { menu, text, o, NotifySelect = MenuOpen, disabled = false };
491                MenuItem { menu, "Cut\tCtrl+X", t, NotifySelect = null, disabled = false };
492                MenuItem { menu, "Copy\tCtrl+C", c, NotifySelect = null, disabled = false };
493                MenuItem { menu, "Paste\tCtrl+V", p, NotifySelect = null, disabled = false /*!clipboard*/ };
494                MenuItem { menu, "Delete\tDel", d, NotifySelect = null, disabled = false };
495                //MenuDivider { menu };
496
497                popup = PopupMenu
498                   {
499                      master = this, menu = menu,
500                      position = { 
501                         x + clientStart.x + absPosition.x - guiApp.desktop.position.x, 
502                         y + clientStart.y + absPosition.y - guiApp.desktop.position.y }
503                   };
504                popup.Create();
505             }
506          }
507          return true;
508       }
509
510       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
511       {
512          OldList rows;
513          OldLink item;
514
515          selection.nodes.Free();
516          list.GetMultiSelection(rows);
517          for(item = rows.first; item; item = item.next)
518          {
519             DataRow row = item.data;
520             FileSystemNode node = (FileSystemNode)row.tag;
521             selection.nodes.Add(node);
522             incref node;
523          }
524          rows.Free(null);
525          if(row)
526             selection.node = (FileSystemNode)row.tag;
527          else
528             selection.node = null;
529
530          if(selection.node && bits.preview)
531          {
532             //int pos;
533             FileSystemNode node = selection.node;
534             /*if(bitmap)
535                bitmap.Free();*/
536             delete bitmap;
537             if(node && node.type == pictureFile)
538             {
539                bitmap = Bitmap { };
540                bitmap.Load(node.path, null, displaySystem);
541             }
542
543             /*bitmaps.Clear();
544             bitmaps = BitmapArray { };
545             for(pos = 0; pos < selectedItems.count; pos++)
546             {
547                Bitmap bitmap { };
548                selItem = (ExplorerFileItem)selectedItems._[pos];
549                bitmap.Load(selItem.path, null, displaySystem);
550                //bitmaps.Add(bitmap);
551             }
552             if(node && node.type == pictureFile)
553             {
554                bitmap = Bitmap { };
555                bitmap.Load(node.path, null, displaySystem);
556             }*/
557
558             show.Update(null);
559             //NotifyItemSelect(master, view, item, selectedItems);
560          }
561
562          NotifyNodeSelect(listBox.parent.master, this, selection);
563          return true;
564       }
565
566       bool NotifyEditing(ListBox listBox, DataRow row)
567       {
568          if(row)
569          {
570             FileSystemNode node = (FileSystemNode)row.tag;
571          }
572          return true;
573       }
574
575       bool NotifyEdited(ListBox listBox, DataRow row)
576       {
577          if(row)
578          {
579             FileSystemNode node = (FileSystemNode)row.tag;
580          }
581          return true;
582       }
583
584       bool NotifyEditDone(ListBox listBox, DataRow row)
585       {
586          if(row)
587          {
588             FileSystemNode node = (FileSystemNode)row.tag;
589          }
590          return true;
591       }
592
593       bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
594       {
595          bool result = !(selection.node && selection.node.type.isFolder && bits.navigateFolders);
596          OpenNode();
597          return result;
598       }
599
600       bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
601       {
602          bool result;
603          if((SmartKey)key == enter)
604             result = OpenNode();
605          else
606             result = true;
607          return true;
608       }
609    };
610
611    PaneSplitter split
612    {
613       this;
614       //leftPane = list;
615       rightPane = show;
616       //split = 200;
617       scaleSplit = 0.5f;
618       tabCycle = true;
619       visible = false;
620    };
621
622    Window show
623    {
624       this;
625       visible = false;
626       borderStyle = none;
627       anchor = Anchor { top = 0, right = 0, bottom = 0 };
628
629       void OnRedraw(Surface surface)
630       {
631          FileSystemBox fsb = (FileSystemBox)parent;
632          if(fsb.bitmap)
633          {
634             int wBmp = fsb.bitmap.width;
635             int hBmp = fsb.bitmap.height;
636             int wWnd = fsb.show.clientSize.w;
637             int hWnd = fsb.show.clientSize.h;
638
639             int wList = 0;//fsb.list.size.w + fsb.split.size.w;
640
641             float scale = Min((float)(wWnd - 10) / wBmp, (float)(hWnd - 10) / hBmp);
642
643             int wDraw = (int)(wBmp * scale);
644             int hDraw = (int)(hBmp * scale);
645
646       #ifndef __linux__
647             surface.Filter(fsb.bitmap, (wWnd - wDraw) / 2, (hWnd - hDraw) / 2, 0, 0, wDraw, hDraw, wBmp, hBmp);
648       #else
649             // Until Filter / Stretch works with X
650             surface.Blit(fsb.bitmap, (wWnd - wBmp) / 2, (hWnd - hBmp) / 2, 0, 0, wBmp, hBmp);
651       #endif
652          }
653          else
654          {
655             surface.SetForeground(white);
656             surface.Area(0, 0, fsb.clientSize.w - 1, fsb.clientSize.h - 1);
657          }
658       }
659    }
660
661    bool MenuOpen(MenuItem selection, Modifiers mods)
662    {
663       OpenNode();
664    }
665
666    bool OpenNode()
667    {
668       bool result;
669       FileSystemBoxSelection selection = this.selection.Copy();
670       FileSystemNode node = selection.node;
671       if(node && node.type.isFolder && bits.navigateFolders)
672          property::path = node.path;
673       result = NotifyNodeOpen(this.master, this, selection);
674       return result;
675    }
676
677    // Edit Menu
678    Menu editMenu { menu, "Edit", e };
679    MenuItem itemEditCut
680    {
681       editMenu, "Cut\tCtrl+X", t, disabled = true;
682
683       bool NotifySelect(MenuItem selection, Modifiers mods)
684       {
685          //EditCut();
686          return true;
687       }
688    };
689    MenuItem itemEditCopy
690    {
691       editMenu, "Copy\tCtrl+C", c, disabled = true;
692
693       bool NotifySelect(MenuItem selection, Modifiers mods)
694       {
695          //EditCopy();
696          return true;
697       }
698    };
699    MenuItem itemEditPaste
700    {
701       editMenu, "Paste\tCtrl+V", p;
702    
703       bool NotifySelect(MenuItem selection, Modifiers mods)
704       {
705          //EditPaste();
706          return true;
707       }
708    };
709    MenuItem itemEditDelete
710    {
711       editMenu, "Delete\tDel", d, disabled = true;
712
713       bool NotifySelect(MenuItem selection, Modifiers mods)
714       {
715          //EditDelete();
716          return true;
717       }
718    };
719
720    // WHY is this crashing ? 
721    /*void OnResize(int width, int height)
722    {
723       if(this && nameField)
724          nameField.width = width - 80;
725    }*/
726
727    void ChangeViewType()
728    {
729       list.Clear();
730       list.ClearFields();
731       list.resizable = bits.details || bits.pathColumn;
732       list.moveFields = bits.details || bits.pathColumn;
733       list.hasHeader = bits.details || bits.pathColumn;
734       list.AddField(nameField);
735       if(bits.pathColumn)
736          list.AddField(pathField);
737       if(bits.details)
738       {
739          list.AddField(typeField);
740          list.AddField(sizeField);
741          list.AddField(modifiedField);
742       }
743    }
744
745    void Load()
746    {
747       // TODO: fix this!
748       // this is crashing in for designer when details = true // can't save the file, always yields a crash
749       /*if(list && created)
750       {
751          list.ClearFields();
752          list.AddField(nameField);
753          if(bits.details)
754          {
755             list.AddField(typeField);
756             list.AddField(sizeField);
757          }
758       }*/
759       if(bits.treeBranches)
760          LoadTree();
761       else
762          LoadList();
763    }
764
765    void LoadList()
766    {
767       FileListing listing { path, extensions = extensions };
768
769       list.Clear();
770       while(listing.Find())
771       {
772          if((!bits.foldersOnly && !bits.filesOnly) ||
773             (bits.foldersOnly && listing.stats.attribs.isDirectory) ||
774             (bits.filesOnly && listing.stats.attribs.isFile))
775          {
776             FileSystemNode node = MakeFileSystemNode(listing.stats, listing.name, listing.path, false, bits.previewPictures, displaySystem);
777             AddNode(node);
778          }
779       }
780       list.Sort(nameField, 1);
781    }
782
783    void LoadTree()
784    {
785       bool isRoot = !strcmp(path, "/");
786       char name[MAX_LOCATION];
787       FileSystemNode parent;
788       FileSystemNode node;
789       FileListing listing { path, extensions = extensions };
790
791       if(!isRoot)
792          GetLastDirectory(path, name);
793       else
794          name[0] = '\0';
795       
796       /*if(!path)
797          GetWorkingDir(startPath, sizeof(startPath));
798       else
799          strcpy(path, startPath);*/
800       
801       list.Clear();
802
803       delete root;
804    #ifdef __WIN32__
805       if(isRoot)
806       {
807          root = FileSystemNode { bits.loaded = true, bits.childrenLoaded = true };
808          AddTreeNode(root, true, false, null);
809          while(listing.Find())
810          {
811             int len = strlen(listing.name);
812             char info[MAX_LOCATION];
813             char name[MAX_LOCATION];
814             if(listing.stats.attribs.isDrive &&
815                   len > 3 && !strncmp(&listing.name[1], ": [", 3))
816             {
817                strncpy(name, listing.name, 2);
818                name[2] = 0;
819                strncpy(info, &listing.name[4], len - 5);
820                info[len - 5] = 0;
821             }
822             else
823             {
824                strcpy(name, listing.name);
825                info[0] = 0;
826             }
827
828             parent = MakeFileSystemNode(listing.stats, name, listing.path, false, bits.previewPictures, displaySystem);
829             if(info[0])
830                parent.info = info; //CopyString(info);
831             parent.bits.loaded = true;
832             AddTreeNode(parent, !listing.stats.attribs.isDirectory, listing.stats.attribs.isDirectory, root);
833             if(!listing.stats.attribs.isDirectory)
834                parent.bits.childrenLoaded = true;
835          }
836
837          node = FileSystemNode { name = msNetwork, type = network };
838          AddTreeNode(node, false, true, null);
839          node.row.collapsed = true;
840       }
841       else
842    #endif
843       {
844          root = MakeFileSystemNode(FileStats { attribs = FileExists(path)}, name, path, false, bits.previewPictures, displaySystem);
845          AddTreeNode(root, false, true, null);
846          LoadTreeNode(root);
847       }
848
849       if(isRoot)
850       {
851          root.type = computer;
852          root.label = rootName;
853       }
854
855       list.Sort(nameField, 1);
856       list.SelectRow(root.row);
857    }
858
859    void LoadTreeNode(FileSystemNode node)
860    {
861       if(!node.bits.loaded)
862       {
863          char path[MAX_LOCATION];
864          node.GetPath(path);
865          {
866             FileListing listing { path, extensions = extensions };
867             if(node.children.count == 1)
868                DeleteNode(node.children.first);
869
870             while(listing.Find())
871             {
872                if(!listing.stats.attribs.isRemovable && ((!bits.foldersOnly && !bits.filesOnly) ||
873                   (bits.foldersOnly && listing.stats.attribs.isDirectory) ||
874                   (bits.filesOnly && listing.stats.attribs.isFile)))
875                {
876                   FileSystemNode child = MakeFileSystemNode(listing.stats, listing.name, listing.path, false, bits.previewPictures, displaySystem);
877                   AddTreeNode(child, true, false, node);
878                   NodeChildLoad(child, node);
879                }
880             }
881          }
882          node.bits.childrenLoaded = true;
883          node.bits.loaded = true;
884          node.row.SortSubRows(false);
885       }
886       else if(!node.bits.childrenLoaded)
887       {
888          FileSystemNode child;
889          if(node.children.first)
890          {
891             for(child = node.children.first; child; child = child.next)
892             {
893                if(!child.bits.loaded)
894                   LoadTreeNode(child);
895                else if(!child.bits.childrenLoaded)
896                   NodeChildLoad(child, node);
897             }
898             node.bits.childrenLoaded = true;
899             node.row.SortSubRows(false);
900          }
901       }
902    }
903
904    void NodeChildLoad(FileSystemNode parent, FileSystemNode node)
905    {
906       char path[MAX_LOCATION];
907       parent.GetPath(path);
908       {
909          bool added = false;
910          FileListing listing { path, extensions = extensions };
911          while(listing.Find())
912          {
913             if((!bits.foldersOnly && !bits.filesOnly) ||
914                (bits.foldersOnly && listing.stats.attribs.isDirectory) ||
915                (bits.filesOnly && listing.stats.attribs.isFile))
916             {
917                FileSystemNode child = MakeFileSystemNode(listing.stats, listing.name, listing.path, false, bits.previewPictures, displaySystem);
918                AddTreeNode(child, listing.stats.attribs.isFile, !listing.stats.attribs.isFile, parent);
919                added = true;
920             }
921          }
922          if(!added)
923             added = true;
924       }
925       parent.bits.childrenLoaded = true;
926    }
927
928    void AddNode(FileSystemNode node)
929    {
930       DataRow row = list.AddRow();
931       row.tag = (int)node;
932       node.row = row;
933       incref node;
934       row.SetData(nameField, node);
935       if(bits.pathColumn)
936          row.SetData(pathField, node.path);
937       if(bits.details)
938       {
939          if(node.type.isFile)
940          {
941             row.SetData(typeField, node.extension);
942             row.SetData(sizeField, /*(void *)*/node.stats.size);
943          }
944          row.SetData(modifiedField, node.stats.modified);
945       }
946    }
947
948    void AddTreeNode(FileSystemNode node, bool loaded, bool addLoader, FileSystemNode addTo)
949    {
950       DataRow row = (addTo && addTo.row) ? addTo.row.AddRow() : list.AddRow();
951       if(addTo)
952       {
953          node.parent = addTo;
954          node.indent = addTo.indent + 1;
955          addTo.children.Add(node);
956       }
957       row.tag = (int)node;
958       node.row = row;
959       row.SetData(null, node);
960       if(bits.pathColumn)
961          row.SetData(pathField, node.path);
962       if(bits.details)
963       {
964          if(node.type.isFile)
965          {
966             row.SetData(typeField, node.extension);
967             row.SetData(sizeField, /*(void *)*/node.stats.size);
968          }
969          row.SetData(modifiedField, node.stats.modified);
970       }
971
972       node.bits.loaded = loaded;
973       if(addLoader)
974          //AddTreeNode(FileSystemNode { }, false, false, node); // why would this create a compile error?
975          AddTreeNode(FileSystemNode { type = none }, false, false, node);
976
977       if(node.indent > 0)
978          row.collapsed = true;
979       else if(node.type == folder)
980          node.type = folderOpen;
981    }
982
983    void DeleteNode(FileSystemNode node)
984    {
985       FileSystemNode child;
986       if(treeBranches)
987       {
988          for(; (child = node.children.first); )
989             DeleteNode(child);
990       }
991       list.DeleteRow(node.row);
992       node.Delete();
993       //delete node;
994       //Update(null);
995    }
996 }
997
998 /*
999 #if 0
1000 class ExplorerView : FileSystemBox
1001 {
1002    borderStyle = none;
1003    hasHorzScroll = false;
1004    hasVertScroll = false;
1005
1006    virtual void Load(FileSystemNode parent);
1007    virtual void Refresh();
1008
1009    virtual void LaunchNotifyItemSelect(Window master, ExplorerView view, ExplorerFileItem item, ExplorerFileItemArray selectedItems)
1010    {
1011       view.NotifyItemSelect(master, view, item, selectedItems);
1012    }
1013
1014    virtual bool Window::NotifyItemSelect(ExplorerView view, ExplorerFileItem item, ExplorerFileItemArray selectedItems);
1015    virtual bool Window::NotifyItemOpen(ExplorerView view, ExplorerFileItem item);
1016
1017    ListBox list
1018    {
1019       master = master, parent = this;
1020       //this, master;
1021       borderStyle = none;
1022       hasHorzScroll = true;
1023       hasVertScroll = true;
1024       resizable = true;
1025       sortable = true;
1026       fullRowSelect = false;
1027       multiSelect = true;
1028
1029       anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
1030
1031       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
1032       {
1033          ExplorerView view = (ExplorerView)listBox.parent;
1034          if(listBox.currentRow)
1035          {
1036             DataRow listRow;
1037             ExplorerFileItemArray selectedItems { growingFactor = 16 };
1038             for(listRow = listBox.firstRow; listRow; listRow = listRow.next)
1039                if(listRow.selected)
1040                   selectedItems.Add((ExplorerFileItem)listRow.tag);
1041             //view.NotifyItemSelect(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag);
1042             view.LaunchNotifyItemSelect(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag, selectedItems);
1043          }
1044          return true;
1045       }
1046
1047       bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
1048       {
1049          ExplorerView view = (ExplorerView)listBox.parent;
1050          view.NotifyItemOpen(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag);
1051          return false;
1052       }
1053
1054       bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
1055       {
1056          if((SmartKey)key == enter)
1057          {
1058             ExplorerView view = (ExplorerView)listBox.parent;
1059             view.NotifyItemOpen(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag);
1060          }
1061          return true;
1062       }
1063    };
1064
1065    ExplorerView()
1066    {
1067    }
1068 }
1069 #endif
1070
1071 #if 0
1072 class ExplorerViewList : ExplorerView
1073 {
1074
1075    FileSystemNode location;
1076
1077 public:
1078
1079    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
1080
1081    ExplorerViewDetails()
1082    {
1083       list.AddField(nameField);
1084    }
1085
1086    void Refresh()
1087    {
1088       Load(location);
1089    }
1090
1091    void Load(FileSystemNode location)
1092    {
1093       char path[MAX_LOCATION];
1094       this.location = location;
1095       location.GetPath(path);
1096       {
1097          FileListing listing { path };
1098          
1099          ExplorerFileItem item;
1100          DataRow row;
1101
1102          list.Clear();
1103
1104          while(listing.Find())
1105          {
1106             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
1107
1108             row = list.AddRow();
1109             row.tag = (int)item;
1110             row.SetData(nameField, item);
1111          }
1112          list.Sort(nameField, 1);
1113       }
1114    }
1115 }
1116 #endif
1117
1118 #if 0
1119 class ExplorerViewDetails : ExplorerView
1120 {
1121    list.hasHeader = true;
1122    list.moveFields = true;
1123    list.resizable = true;
1124    list.sortable = true;
1125
1126    FileSystemNode location;
1127
1128 public:
1129
1130    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
1131    DataField typeField { header = "Type", dataType = /-*"String"*-/ "char *", width = 40 };
1132    DataField sizeField { header = "Size", dataType = "FileSize", width = 96, alignment = right };
1133
1134    ExplorerViewDetails()
1135    {
1136       list.AddField(nameField);
1137       list.AddField(typeField);
1138       list.AddField(sizeField);
1139    }
1140
1141    void Refresh()
1142    {
1143       Load(location);
1144    }
1145
1146    void Load(FileSystemNode location)
1147    {
1148       char path[MAX_LOCATION];
1149       this.location = location;
1150       location.GetPath(path);
1151       {
1152          FileListing listing { path };
1153          
1154          ExplorerFileItem item;
1155          DataRow row;
1156
1157          list.Clear();
1158
1159          while(listing.Find())
1160          {
1161             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
1162
1163             row = list.AddRow();
1164             row.tag = (int)item;
1165             row.SetData(nameField, item);
1166             row.SetData(typeField, CopyString(item.extension));
1167             row.SetData(sizeField, (uint)listing.stats.size);
1168          }
1169          list.Sort(nameField, 1);
1170       }
1171    }
1172 }
1173 #endif
1174
1175 #if 0
1176 class ExplorerViewIcons : ExplorerView
1177 {
1178
1179    FileSystemNode location;
1180
1181 public:
1182
1183    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
1184
1185    ExplorerViewDetails()
1186    {
1187       list.AddField(nameField);
1188    }
1189
1190    void Refresh()
1191    {
1192       Load(location);
1193    }
1194
1195    void Load(FileSystemNode location)
1196    {
1197       char path[MAX_LOCATION];
1198       this.location = location;
1199       location.GetPath(path);
1200       {
1201          FileListing listing { path };
1202          
1203          ExplorerFileItem item;
1204          DataRow row;
1205
1206          list.Clear();
1207
1208          while(listing.Find())
1209          {
1210             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
1211
1212             row = list.AddRow();
1213             row.tag = (int)item;
1214             row.SetData(nameField, item);
1215          }
1216          list.Sort(nameField, 1);
1217       }
1218    }
1219 }
1220 #endif
1221
1222 #if 0
1223 class ExplorerViewCards : ExplorerView
1224 {
1225
1226    FileSystemNode location;
1227
1228 public:
1229
1230    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
1231
1232    ExplorerViewDetails()
1233    {
1234       list.AddField(nameField);
1235    }
1236
1237    void Refresh()
1238    {
1239       Load(location);
1240    }
1241
1242    void Load(FileSystemNode location)
1243    {
1244       char path[MAX_LOCATION];
1245       this.location = location;
1246       location.GetPath(path);
1247       {
1248          FileListing listing { path };
1249          
1250          ExplorerFileItem item;
1251          DataRow row;
1252
1253          list.Clear();
1254
1255          while(listing.Find())
1256          {
1257             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
1258
1259             row = list.AddRow();
1260             row.tag = (int)item;
1261             row.SetData(nameField, item);
1262          }
1263          list.Sort(nameField, 1);
1264       }
1265    }
1266 }
1267 #endif
1268
1269 #if 0
1270 public class BitmapArray : RedjArray
1271 {
1272    type = class(Bitmap);
1273 public:
1274    Bitmap * const _;
1275    Bitmap * Add(Bitmap bitmap)
1276    {
1277       uint pos = _count;
1278       Append(1);
1279       _[pos] = bitmap;
1280       return &_[pos];
1281    }
1282    Bitmap * AddBefore(uint position, Bitmap bitmap)
1283    {
1284       Insert(position, 1);
1285       _[position] = bitmap;
1286       return &_[position];
1287    }
1288    void Clear()
1289    {
1290       int c;
1291       for(c = 0; c < _count; c++)
1292       {
1293          _[c].Free();
1294          delete _[c];
1295       }  
1296       count = 0;
1297       size = 0;
1298    }
1299 }
1300 #endif
1301
1302 #if 0
1303 class ExplorerViewShowcase : ExplorerView
1304 {
1305    list.anchor = Anchor { left = 0, top = 0, bottom = 0 };
1306    list.size = Size { w = 200 };
1307
1308    FileSystemNode location;
1309
1310 public:
1311
1312    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 180, editable = true, userData = this };
1313
1314    Bitmap bitmap;
1315    BitmapArray bitmaps { growingFactor = 16 };
1316
1317    Window show
1318    {
1319       this;
1320       borderStyle = none;
1321       anchor = Anchor { top = 0, right = 0, bottom = 0 };
1322
1323       void OnRedraw(Surface surface)
1324       {
1325          ExplorerViewShowcase view = (ExplorerViewShowcase)parent;
1326          if(view.bitmap)
1327          {
1328             int wBmp = view.bitmap.width;
1329             int hBmp = view.bitmap.height;
1330             int wWnd = clientSize.w;
1331             int hWnd = clientSize.h;
1332
1333             int wList = view.list.size.w + view.split.size.w;
1334             
1335             float scale = Min((float)(wWnd - 10) / wBmp, (float)(hWnd - 10) / hBmp);
1336             
1337             int wDraw = (int)(wBmp * scale);
1338             int hDraw = (int)(hBmp * scale);
1339
1340       #ifndef __linux__
1341             surface.Filter(view.bitmap, (wWnd - wDraw) / 2, (hWnd - hDraw) / 2, 0, 0, wDraw, hDraw, wBmp, hBmp);
1342       #else
1343             // Until Filter / Stretch works with X
1344             surface.Blit(view.bitmap, (wWnd - wDraw) / 2, (hWnd - hDraw) / 2, 0, 0, wDraw, hDraw);
1345       #endif
1346          }
1347          else
1348          {
1349             surface.SetForeground(white);
1350             surface.Area(0, 0, view.clientSize.w - 1, view.clientSize.h - 1);
1351          }
1352       }
1353    }
1354
1355    SplitWindow split
1356    {
1357       this;
1358       leftPane = list;
1359       rightPane = show;
1360       split = 200;
1361       tabCycle = true;
1362    };
1363
1364    ExplorerViewDetails()
1365    {
1366       list.AddField(nameField);
1367    }
1368
1369    void LaunchNotifyItemSelect(Window master, ExplorerViewShowcase view, ExplorerFileItem item, ExplorerFileItemArray selectedItems)
1370    {
1371       int pos;
1372       ExplorerFileItem selItem;
1373       if(view.bitmap)
1374          view.bitmap.Free();
1375       delete view.bitmap;
1376       if(item && item.type == pictureFile)
1377       {
1378          view.bitmap = Bitmap { };
1379          view.bitmap.Load(item.path, null, displaySystem);
1380       }
1381
1382       view.bitmaps.Clear();
1383       view.bitmaps = BitmapArray { };
1384       for(pos = 0; pos < selectedItems.count; pos++)
1385       {
1386          Bitmap bitmap { };
1387          selItem = (ExplorerFileItem)selectedItems._[pos]; 
1388          bitmap.Load(selItem.path, null, displaySystem);
1389          //view.bitmaps.Add(bitmap);
1390       }  
1391       if(item && item.type == pictureFile)
1392       {
1393          view.bitmap = Bitmap { };
1394          view.bitmap.Load(item.path, null, displaySystem);
1395       }
1396
1397       view.show.Update(null);
1398       view.NotifyItemSelect(master, view, item, selectedItems);
1399    }
1400
1401    void Refresh()
1402    {
1403       Load(location);
1404    }
1405
1406    void Load(FileSystemNode location)
1407    {
1408       char path[MAX_LOCATION];
1409       this.location = location;
1410       location.GetPath(path);
1411       {
1412          FileListing listing { path };
1413          
1414          ExplorerFileItem item;
1415          DataRow row;
1416
1417          list.Clear();
1418
1419          while(listing.Find())
1420          {
1421             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
1422
1423             row = list.AddRow();
1424             row.tag = (int)item;
1425             row.SetData(nameField, item);
1426          }
1427          list.Sort(nameField, 1);
1428       }
1429    }
1430 }
1431 #endif
1432
1433 #if 0
1434 class ExplorerTree : FileSystemBox
1435 {
1436    hasHorzScroll = false;
1437    hasVertScroll = false;
1438
1439    menu = Menu { };
1440
1441 public:
1442
1443    DataField nameField { dataType = "FileSystemNode", width = 240, userData = this };
1444
1445    FileSystemNode root;
1446    FileSystemNode selection;
1447
1448    virtual bool Window::NotifyNodeSelect(ExplorerTree tree, FileSystemNode node);
1449    
1450    property FileSystemNode node
1451    {
1452       get
1453       {
1454          if(!tree)
1455             return null;
1456          if(!tree.currentRow)
1457             return null;
1458          if(!tree.currentRow.tag)
1459             return null;
1460          return (FileSystemNode)tree.currentRow.tag;
1461       }
1462    }
1463
1464    void Select(FileSystemNode node)
1465    {
1466       if(node.row)
1467       {
1468          node.EnsureVisible(false);
1469          tree.SelectRow(node.row);
1470       }
1471    }
1472
1473    FileSystemNode Find(const char * name, FileSystemNode parent)
1474    {
1475       FileSystemNode node;
1476       FileSystemNode start = parent ? parent : root;
1477       if(!start.loaded || !start.childrenLoaded)
1478          LoadTreeNode(start, tree);
1479       for(node = start.children.first; node; node = node.next)
1480          if(node.name && !strcmpi(node.name, name))
1481             return node;
1482       return null;
1483    }
1484
1485    ListBox tree
1486    {
1487       master = master, parent = this;
1488       //this, master;
1489       borderStyle = none;
1490       hasHorzScroll = true;
1491       hasVertScroll = true;
1492       fullRowSelect = false;
1493       treeNodees = true;
1494       collapseControl = true;
1495       rootCollapseButton = true;
1496
1497       anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
1498
1499       // WHY is this not working ?
1500       /-*void OnResize(int width, int height)
1501       {
1502          if(vertScroll.visible)
1503             nameField.width = width - vertScroll.size.w;
1504          else
1505             nameField.width = width;
1506       }*-/
1507
1508       bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed)
1509       {
1510          if(row)
1511          {
1512             FileSystemNode node = (FileSystemNode)row.tag;
1513             FileSystemNode child;
1514             if(collapsed)
1515             {
1516                /-*
1517                for(child = node.children.last; child; child = node.children.last)
1518                {
1519                   listBox.DeleteRow(child.row);
1520                   child.Free();
1521                   delete child;
1522                }
1523                node.childrenLoaded = false;
1524                *-/
1525             }
1526             else
1527             {
1528                if(!node.loaded || !node.childrenLoaded)
1529                   LoadTreeNode(node, tree);
1530                for(child = node.children.first; child && child.next; child = child.next);
1531                if(child)
1532                   child.EnsureVisible(false);
1533             }
1534          }
1535          return true;
1536       }
1537       
1538       bool NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods)
1539       {
1540          DataRow row = listBox.currentRow;
1541          if(row)
1542          {
1543             FileSystemNode node = (FileSystemNode)row.tag;
1544             if(node)
1545             {
1546                PopupMenu popup;
1547                Menu menu { };
1548
1549                MenuItem { menu, "Cut\tCtrl+X", t, NotifySelect = null, disabled = false };
1550                MenuItem { menu, "Copy\tCtrl+C", c, NotifySelect = null, disabled = false };
1551                MenuItem { menu, "Paste\tCtrl+V", p, NotifySelect = null, disabled = false /-*!clipboard*-/ };
1552                MenuItem { menu, "Delete\tDel", d, NotifySelect = null, disabled = false };
1553                //MenuDivider { menu };
1554
1555                popup = PopupMenu
1556                   {
1557                      master = this, menu = menu,
1558                      position = { 
1559                         x + clientStart.x + absPosition.x - guiApp.desktop.position.x, 
1560                         y + clientStart.y + absPosition.y - guiApp.desktop.position.y }
1561                   };
1562                popup.Create();
1563             }
1564          }
1565          return true;
1566       }
1567
1568       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
1569       {
1570          if(row)
1571          {
1572             FileSystemNode node = (FileSystemNode)row.tag;
1573             NotifyNodeSelect(listBox.parent.master, this, node);
1574             selection = node;
1575          }
1576          return true;
1577       }
1578
1579       bool NotifyEditing(ListBox listBox, DataRow row)
1580       {
1581          if(row)
1582          {
1583             FileSystemNode node = (FileSystemNode)row.tag;
1584          }
1585          return true;
1586       }
1587
1588       bool NotifyEdited(ListBox listBox, DataRow row)
1589       {
1590          if(row)
1591          {
1592             FileSystemNode node = (FileSystemNode)row.tag;
1593          }
1594          return true;
1595       }
1596
1597       bool NotifyEditDone(ListBox listBox, DataRow row)
1598       {
1599          if(row)
1600          {
1601             FileSystemNode node = (FileSystemNode)row.tag;
1602          }
1603          return true;
1604       }
1605    };
1606
1607    // Edit Menu
1608    Menu editMenu { menu, "Edit", e };
1609    MenuItem itemEditCut
1610    {
1611       editMenu, "Cut\tCtrl+X", t, disabled = true;
1612
1613       bool NotifySelect(MenuItem selection, Modifiers mods)
1614       {
1615          //EditCut();
1616          return true;
1617       }
1618    };
1619    MenuItem itemEditCopy
1620    {
1621       editMenu, "Copy\tCtrl+C", c, disabled = true;
1622
1623       bool NotifySelect(MenuItem selection, Modifiers mods)
1624       {
1625          //EditCopy();
1626          return true;
1627       }
1628    };
1629    MenuItem itemEditPaste
1630    {
1631       editMenu, "Paste\tCtrl+V", p;
1632    
1633       bool NotifySelect(MenuItem selection, Modifiers mods)
1634       {
1635          //EditPaste();
1636          return true;
1637       }
1638    };
1639    MenuItem itemEditDelete
1640    {
1641       editMenu, "Delete\tDel", d, disabled = true;
1642
1643       bool NotifySelect(MenuItem selection, Modifiers mods)
1644       {
1645          //EditDelete();
1646          return true;
1647       }
1648    };
1649
1650    // WHY is this crashing ? 
1651    /-*void OnResize(int width, int height)
1652    {
1653       if(this && nameField)
1654          nameField.width = width - 80;
1655    }*-/
1656
1657    ExplorerTree()
1658    {
1659       tree.AddField(nameField);
1660    }
1661
1662    void Load()
1663    {
1664       FileSystemNode parent;
1665       FileSystemNode node;
1666       FileListing listing { "/" };
1667
1668       tree.Clear();
1669
1670       root = FileSystemNode { type = computer, loaded = true, childrenLoaded = true };
1671    #ifdef __WIN32__
1672       root.name = rootName;
1673    #else
1674       root.name = "/";
1675    #endif
1676       AddTreeNode(root, true, false, null, tree);
1677
1678    // How can this make sense for linux? 
1679    #ifdef __WIN32__
1680       while(listing.Find())
1681       {
1682          int len = strlen(listing.name);
1683          char info[MAX_LOCATION];
1684          char name[MAX_LOCATION];
1685          if(listing.stats.attribs.isDrive && 
1686                len > 3 && !strncmp(&listing.name[1], ": [", 3))
1687          {
1688             strncpy(name, listing.name, 2);
1689             name[2] = 0;
1690             strncpy(info, &listing.name[4], len - 5);
1691             info[len - 5] = 0;
1692          }
1693          else
1694          {
1695             strcpy(name, listing.name);
1696             info[0] = 0;
1697          }
1698
1699          parent = MakeFileSystemNode(listing.stats, name);
1700          if(info[0])
1701             parent.info = CopyString(info);
1702          parent.loaded = true;
1703          AddTreeNode(parent, !listing.stats.attribs.isDirectory, listing.stats.attribs.isDirectory, root, tree);
1704          if(!listing.stats.attribs.isDirectory)
1705             parent.childrenLoaded = true;
1706       }
1707    #endif
1708       node = FileSystemNode { name = msNetwork, type = network };
1709       AddTreeNode(node, false, true, null, tree);
1710       node.row.collapsed = true;
1711       tree.Sort(nameField, 1);
1712       tree.SelectRow(root.row);
1713    }
1714 }
1715
1716 #if 0
1717 public class ClipBoardFiles
1718 {
1719
1720 public:
1721
1722    property
1723
1724 }
1725
1726    // CLIPBOARD
1727    void Copy()
1728    {
1729       if(this)
1730       {
1731          int size = SelSize();
1732          if(size)
1733          {
1734             // Try to allocate memory
1735             ClipBoard clipBoard { };
1736             if(clipBoard.Allocate(size+1))
1737             {
1738                GetSel(clipBoard.memory, true);   
1739                // Save clipboard
1740                clipBoard.Save();
1741             }
1742             delete clipBoard;
1743          }
1744       }
1745    }
1746
1747    void Paste()
1748    {
1749       if(this)
1750       {
1751          ClipBoard clipBoard { };
1752          if(clipBoard.Load())
1753             PutS(clipBoard.memory);
1754          delete clipBoard;
1755       }
1756    }
1757
1758    void Cut()
1759    {
1760       if(this)
1761       {
1762          Copy();
1763          DelSel();
1764          SetViewToCursor(true);
1765          Modified();
1766       }
1767    }
1768
1769 /-*
1770 Private Type DROPFILES
1771    pFiles As Long
1772    pt As POINTAPI
1773    fNC As Long
1774    fWide As Long
1775 End Type
1776 For iCounter = 0 To filelist.ListCount - 1
1777   If filelist.Selected(iCounter) = True Then
1778     strFiles = strFiles & FixPath(filelist.Path) & filelist.List(iCounter) & vbNullChar
1779   End If
1780 Next
1781 'all selected items are now put in strFiles
1782
1783 hGlobal = GlobalAlloc(GHND, Len(DF) + Len(strFiles)) 'put all files to a exclusive number
1784 If hGlobal Then 'if the globalalloc worked
1785   lpGlobal = GlobalLock(hGlobal) 'lock the hGlobal
1786   DF.pFiles = Len(DF) 'set the size of the files
1787   
1788   Call CopyMem(ByVal lpGlobal, DF, Len(DF)) 'copy df to the lpglobal
1789   Call CopyMem(ByVal (lpGlobal + Len(DF)), ByVal strFiles, Len(strFiles)) 'copy strfiles to lpglobal
1790   Call GlobalUnlock(hGlobal) 'unlock hglobal again
1791   
1792   SetClipboardData CF_HDROP, hGlobal 'put files to the clipboard
1793 End If
1794 *-/
1795    bool SaveFile(const char * filePath)
1796    {
1797    }
1798 #endif
1799
1800 #if 0
1801 public class FileTreeNodeBSArray : ArrayBinarySorted
1802 {
1803    type = class(FileSystemNode);
1804 public:
1805    FileSystemNode * const _;
1806    BSloc Add(FileSystemNode item)
1807    {
1808       BSloc result = Find(item);
1809       if(!result.valid)
1810       {
1811          Insert(result.pos, 1);
1812          _[result.pos] = item;
1813       }
1814       return result;
1815    }
1816    BSloc Remove(FileSystemNode item)
1817    {
1818       
1819    }
1820 }
1821 #endif
1822
1823 #if 0
1824 public class FileTreeNodeArray : RedjArray
1825 {
1826    type = class(FileSystemNode);
1827 public:
1828    FileSystemNode * const _;
1829    FileSystemNode * Add(FileSystemNode item)
1830    {
1831       uint pos = _count;
1832       Append(1);
1833       _[pos] = item;
1834       return &_[pos];
1835    }
1836    FileSystemNode * AddBefore(uint position, FileSystemNode item)
1837    {
1838       Insert(position, 1);
1839       _[position] = item;
1840       return &_[position];
1841    }
1842 }
1843 #endif
1844
1845 #if 0
1846 public class ExplorerFileItem : struct
1847 {
1848    char * path;
1849    char * name;
1850    char * info;
1851    char * extension;
1852    _FileType type;
1853    int indent;
1854
1855    Bitmap bitmap;
1856
1857    void OnDisplay(Surface surface, int x, int y, int width, FileSystemBox control, Alignment alignment, DataDisplayFlags displayFlags)
1858    {
1859       int indentSize = (displayFlags.dropBox) ? 0 : 10;
1860       int textOffset;
1861       int len;
1862       char label[MAX_FILENAME];
1863
1864       //float scale = Min((float)clientSize.w / (float)bitmap.width, (float)clientSize.h / (float)bitmap.height);
1865       int w = 16; //(int)(bitmap.width * scale);
1866       int h = 16; //(int)(bitmap.height * scale);
1867    
1868       Bitmap icon;
1869
1870       icon = control.fileIcons[type].bitmap;
1871       if(!icon)
1872       {
1873          if(type == folder || type == folderOpen)
1874             surface.SetForeground(red); //Color { 170, 170, 0 } // REDJ What is that color?
1875          indentSize = 8;
1876       }
1877       textOffset = indent * indentSize + (icon ? (icon.width + 6) : 0);
1878       
1879       if(info)
1880          sprintf(label, "%s [%s]", name, info);
1881       else
1882          strcpy(label, name);
1883       len = strlen(label);
1884
1885       surface.WriteTextDots
1886          (alignment, x + textOffset, y + 2, width - textOffset, label, len);
1887       if(type == pictureFile && control.previewPictures && bitmap)
1888       {
1889 #ifndef __linux__
1890          //surface.Filter(bitmap, (clientSize.w - w) / 2,(clientSize.h - h) / 2, 0,0, w, h, bitmap.width, bitmap.height);
1891          surface.Filter(bitmap, x + indent * indentSize + 2, y, 0, 0, w, h, bitmap.width, bitmap.height);
1892 #else
1893          // Until Filter / Stretch works with X
1894          //surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2,(clientSize.h - bitmap.height) / 2, 0,0, bitmap.width, bitmap.height);
1895          surface.blend = true;
1896          surface.Blit(bitmap, x + indent * indentSize + 2, y,0,0, w, h);
1897 #endif
1898          //bitmap.Free();
1899          //delete bitmap;
1900       }
1901       else if(icon)
1902          surface.Blit(icon, x + indent * indentSize + 2, y,0,0, icon.width, icon.height);
1903    }
1904
1905    int OnCompare(ExplorerFileItem b)
1906    {
1907       int result;
1908       if(type == b.type || (type < folder && b.type < folder) || (type >= drive))
1909          result = strcmpi(name, b.name);
1910       else
1911       {
1912          if(type == folder && b.type < folder) result = -1;
1913          else if(type < folder && b.type == folder) result = 1;
1914       }
1915       return result;
1916    }
1917
1918    void OnCopy(ExplorerFileItem newData)
1919    {
1920       type = newData.type;
1921       indent = newData.indent;
1922       if(newData.name)
1923       {
1924          int len = strlen(newData.name) + 1;
1925          name = new char[len];
1926          CopyBytes(name, newData.name, len);
1927       }
1928    }
1929
1930    bool OnGetDataFromString(char * string)
1931    {
1932       int len = strlen(string) + 1;
1933       name = new char[len];
1934       CopyBytes(name, string, len);
1935       return true;
1936    }
1937
1938    void OnFree()
1939    {
1940       delete path;
1941       delete name;
1942       delete info;
1943       delete extension;
1944       if(bitmap)
1945          bitmap.Free();
1946    }
1947
1948    char * OnGetString(char * string, void * fieldData, bool * needClass)
1949    {
1950       return name;
1951    }
1952 };
1953
1954 public class ExplorerFileItemArray : RedjArray
1955 {
1956    type = class(ExplorerFileItem);
1957 public:
1958    ExplorerFileItem * const _;
1959    ExplorerFileItem * Add(ExplorerFileItem item)
1960    {
1961       uint pos = _count;
1962       Append(1);
1963       _[pos] = item;
1964       return &_[pos];
1965    }
1966    ExplorerFileItem * AddBefore(uint position, ExplorerFileItem item)
1967    {
1968       Insert(position, 1);
1969       _[position] = item;
1970       return &_[position];
1971    }
1972    void Clear()
1973    {
1974       int c;
1975       for(c = 0; c < _count; c++)
1976       {
1977          //_[c].Free()
1978          delete _[c];
1979       }  
1980       count = 0;
1981       size = 0;
1982    }
1983 }
1984
1985 ExplorerFileItem MakeFileItem(const FileAttribs attribs, const char * fileName, const char * filePath, const bool previewPicture, const DisplaySystem displaySystem)
1986 {
1987    int len = strlen(fileName);
1988    char info[MAX_LOCATION];
1989    char name[MAX_LOCATION];
1990    char extension[MAX_EXTENSION];
1991    
1992    ExplorerFileItem item { };
1993
1994    //if(stats.attribs.isFile) // -- should work now
1995    if(attribs.isDirectory)
1996    {
1997       extension[0] = 0;
1998
1999       item.type = (attribs.isDrive) ? drive : folder;
2000       if(attribs.isServer)
2001          item.type = server;
2002       if(attribs.isShare)
2003          item.type = share;
2004       if(attribs.isCDROM)
2005          item.type = cdrom;
2006       if(attribs.isRemote)
2007          item.type = netDrive;
2008       if(attribs.isRemovable) 
2009       {
2010          if(fileName[0] == 'A' || fileName[0] == 'B')
2011             item.type = floppy;
2012          else
2013             item.type = removable;
2014       }
2015    }
2016    else
2017    {
2018       GetExtension(fileName, extension);
2019       //strupr(extension);
2020       strlwr(extension);
2021       
2022       item.type = _FileType::SelectByExtension(extension);
2023    }
2024
2025    if(attribs.isDrive && 
2026          len > 3 && !strncmp(&fileName[1], ": [", 3))
2027    {
2028       strncpy(name, fileName, 2);
2029       name[2] = 0;
2030       strncpy(info, &fileName[4], len - 5);
2031       info[len - 5] = 0;
2032    }
2033    else
2034    {
2035       strcpy(name, fileName);
2036       info[0] = 0;
2037    }
2038
2039    item.path = CopyString(filePath);
2040    item.name = CopyString(name);
2041    if(info[0])
2042       item.info = CopyString(info);
2043    item.extension = CopyString(extension);
2044
2045    if(item.type == pictureFile && previewPicture)
2046    {
2047       item.bitmap = Bitmap { };
2048       item.bitmap.Load(filePath, null, displaySystem);
2049    }
2050
2051    return item;
2052 }
2053 #endif
2054 */
2055
2056 public class FileSystemBoxSelection
2057 {
2058 public:
2059    FileSystemNode node;
2060    Array<FileSystemNode> nodes { };
2061
2062 private:
2063    FileSystemBoxSelection Copy()
2064    {
2065       FileSystemBoxSelection copy { node = node };
2066       for(node : nodes)
2067       {
2068          copy.nodes.Add(node);
2069          incref node;
2070       }
2071       return copy;
2072    }
2073
2074    ~FileSystemBoxSelection()
2075    {
2076       nodes.Free();
2077    }
2078 }
2079
2080 class FileSystemNodeBits
2081 {
2082    bool loaded:1, childrenLoaded:1, displayPath:1;
2083 };
2084
2085 public class FileSystemNode
2086 {
2087
2088 private:
2089    FileSystemNodeBits bits;
2090    char * path;
2091    char * name;
2092    char * extension;
2093    char * label;
2094    char * info;
2095
2096    ~FileSystemNode()
2097    {
2098       Free();
2099    }
2100
2101 public:
2102    /*//LinkElement<FileSystemNode> link;
2103    FileSystemNode parent;
2104
2105    FileSystemNodeType type;
2106
2107    char * name;*/
2108
2109    FileSystemNode prev, next;
2110
2111    int indent;
2112
2113    property char * path
2114    {
2115       set { delete path; if(value && value[0]) path = CopyString(value); }
2116       get { return path; } isset { return path && path[0]; }
2117    }
2118    property char * name
2119    {
2120       set { delete name; if(value && value[0]) name = CopyString(value); }
2121       get { return name; } isset { return name && name[0]; }
2122    }
2123    property char * extension
2124    {
2125       set { delete extension; if(value && value[0]) extension = CopyString(value); }
2126       get { return extension; } isset { return extension && extension[0]; }
2127    }
2128    property char * label
2129    {
2130       set { delete label; if(value && value[0]) label = CopyString(value); }
2131       get { return label; } isset { return label && label[0]; }
2132    }
2133    property char * info
2134    {
2135       set { delete info; if(value && value[0]) info = CopyString(value); }
2136       get { return info; } isset { return info && info[0]; }
2137    }
2138
2139    DataRow row;
2140    OldList children;
2141    _FileType type;
2142    FileSystemNode parent;
2143
2144    FileStats stats;
2145
2146    Bitmap bitmap;
2147
2148    void GetPath(String outputPath)
2149    {  
2150       if(path)
2151          strcpy(outputPath, path);
2152       else if(parent)
2153       {
2154          FileSystemNode up;
2155          if(name)
2156             strcpy(outputPath, name);
2157          for(up = parent; up; up = up.parent)
2158          {
2159             char temp[MAX_LOCATION];
2160             strcpy(temp, up.name);
2161             PathCat(temp, outputPath);
2162             strcpy(outputPath, temp);
2163          }
2164          /*else
2165          {
2166    /-*#ifdef __WIN32__
2167             strcpy(outputPath, "/");
2168    #else*-/
2169             //strcpy(outputPath, name);
2170             strcpy(outputPath, path);
2171             PathCat(outputPath, name);
2172    //#endif
2173          }*/
2174       }
2175    }
2176
2177    bool IsChildOf(FileSystemNode node)
2178    {
2179       FileSystemNode test;
2180       for(test = parent; test; test = test.parent)
2181          if(test == node)
2182             return true;
2183       return false;
2184    }
2185
2186    void DuplicateChildren(bool recursive, bool forceExpanded, FileSystemNode addTo, FileSystemBox fsb)
2187    {
2188       if(children.first)
2189       {
2190          FileSystemNode child;
2191          
2192          for(child = children.first; child; child = child.next)
2193          {
2194             FileSystemNode copy { };
2195             copy.name = child.name; //CopyString(child.name);
2196             copy.type = child.type;
2197             fsb.AddTreeNode(copy, child.bits.loaded, false, addTo);
2198             if(forceExpanded)
2199                copy.row.collapsed = false;
2200             if(recursive)
2201                child.DuplicateChildren(recursive, forceExpanded, copy, fsb);
2202          }
2203       }
2204    }
2205    
2206    void EnsureVisible(bool expand)
2207    {
2208       if(parent)
2209          parent.EnsureVisible(true);
2210       if(expand)
2211          row.collapsed = false;
2212       // TODO: row.EnsureVisible(); // making the row visible by scrolling
2213    }
2214
2215    void OnFree()
2216    {
2217       //delete name;
2218    }
2219
2220    void Free()
2221    {
2222       FileSystemNode child;
2223       for(; (child = children.first); )
2224       {
2225          child.Free();
2226          children.Delete(child);
2227       }
2228       //if(name)
2229       delete path;
2230       delete name;
2231       delete extension;
2232       delete label;
2233       delete info;
2234    }
2235
2236    void Delete()
2237    {
2238       Free();
2239       if(parent)
2240          parent.children.Delete(this);
2241    }
2242
2243    void OnDisplay(Surface surface, int x, int y, int width, FileSystemBox fsb, Alignment alignment, DataDisplayFlags displayFlags)
2244    {
2245       //int indentSize = (displayFlags.dropBox) ? 0 : 10;
2246       int indent = 16;
2247       int xStart;
2248       int len;
2249       int w, h;
2250       //int textOffset;
2251       char string[MAX_FILENAME];
2252
2253       Bitmap icon;
2254
2255       if(!this)
2256          return;
2257       
2258       icon = fsb.fileIcons[type].bitmap;
2259       //xStart = indent * indent + x + (icon ? (icon.width + 5) : 0);
2260       xStart = x + (icon ? (icon.width + 5) : 0);
2261
2262       if(!name)
2263          return;
2264
2265       if(info)
2266          sprintf(string, "%s [%s]", label ? label : name, info);
2267       else
2268          strcpy(string, label ? label : name);
2269       len = strlen(string);
2270       
2271       if(!icon)
2272       {
2273          if(type == folder || type == folderOpen)
2274             surface.SetForeground(yellow);
2275          //indentSize = 8;
2276          indent = 8;
2277       }
2278       //textOffset = indent * indentSize + (icon ? (icon.width + 4) : 0);
2279       
2280       surface.SetForeground(displayFlags.selected ? fsb.selectionText : fsb.foreground);
2281       surface.TextOpacity(false);
2282       surface.TextExtent(string, len, &w, &h);
2283       h = Max(h, 16);
2284     
2285       // Draw the current row stipple
2286       if(displayFlags.selected)
2287          //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
2288          //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
2289          surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
2290       
2291       //surface.WriteTextDots(alignment, x + textOffset, y + 2, width - textOffset, name, strlen(name));
2292       surface.WriteTextDots(alignment, xStart, y + 2, width, string, len);
2293
2294       if(!guiApp.textMode)
2295       {
2296          if(displayFlags.current)
2297          {
2298             if(displayFlags.active)
2299             {
2300                surface.LineStipple(0x5555);
2301                if(displayFlags.selected)
2302                   surface.SetForeground(0xFFFFFF80);
2303                else
2304                   surface.SetForeground(black);
2305             }
2306             else
2307             {
2308                surface.SetForeground(selectionColor);
2309             }
2310             surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
2311             surface.LineStipple(0);
2312          }
2313
2314          if(icon)
2315          {
2316             w = icon.width;
2317             h = icon.height;
2318          }
2319          if(type == pictureFile && fsb.previewPictures && bitmap)
2320          {
2321             surface.SetForeground(white);
2322             surface.blend = true;
2323    //#ifndef __linux__
2324             //surface.Filter(bitmap, (clientSize.w - w) / 2,(clientSize.h - h) / 2, 0,0, w, h, bitmap.width, bitmap.height);
2325             //surface.Filter(bitmap, x + indent/* * indentSize*/ + 2, y, 0, 0, w, h, bitmap.width, bitmap.height);
2326             surface.Filter(bitmap, x,y,0,0, w, h, bitmap.width, bitmap.height);
2327    //#else
2328             // Until Filter / Stretch works with X
2329             //surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2,(clientSize.h - bitmap.height) / 2, 0,0, bitmap.width, bitmap.height);
2330    //         surface.blend = true;
2331             //surface.Blit(bitmap, x + indent/* * indentSize*/ + 2, y,0,0, w, h);
2332             //surface.Blit(bitmap, x,y,0,0, bitmap.width, bitmap.height);
2333    //#endif
2334             //bitmap.Free();
2335             //delete bitmap;
2336          }
2337          else if(icon)
2338          {
2339             //surface.blend = true;
2340             //surface.alphaWrite = blend;
2341             surface.SetForeground(white);
2342             //surface.Blit(icon, x + indent * indentSize, y,0,0, icon.width, icon.height);
2343             surface.Blit(icon, x,y,0,0, icon.width, icon.height);
2344          }
2345       }
2346    }
2347
2348    int OnCompare(FileSystemNode b)
2349    {
2350       int result;
2351       FileSystemNode a = this;
2352       if(a.type == b.type || (a.type < folder && b.type < folder) || (a.type >= drive))
2353          result = strcmpi(a.name, b.name);
2354       else
2355       {
2356          if(a.type == folder && b.type < folder) result = -1;
2357          else if(a.type < folder && b.type == folder) result = 1;
2358          else result = 0;
2359       }
2360       return result;
2361    }
2362
2363    /*int OnCompare(FileSystemNode b)
2364    {
2365       int result;
2366       FileSystemNode a = this;
2367       if(a.parent < b.parent) result = -1;
2368       else if(a.parent > b.parent) result = 1;
2369       else
2370          result = fstrcmp(a.name, b.name);
2371       return result;
2372    }*/
2373
2374    char * OnGetString(char * tempString, FileSystemToolWindow fileSysToolWnd, bool * needClass)
2375    {
2376       return name ? name : "";
2377    }
2378 }
2379
2380 /*FileSystemNode MakeFileSystemNode(const FileStats stats, const char * name)
2381 {
2382    FileSystemNode node { stats = stats };
2383    node.name = CopyString(name);
2384    if(!node.name)
2385       node.name = null;
2386    if(stats.attribs.isDirectory)
2387    {
2388       node.type = (stats.attribs.isDrive) ? drive : folder;
2389       if(stats.attribs.isServer) node.type = server;
2390       if(stats.attribs.isShare) node.type = share;
2391       if(stats.attribs.isCDROM) node.type = cdrom;
2392       if(stats.attribs.isRemote) node.type = netDrive;
2393       if(stats.attribs.isRemovable) 
2394       {
2395          if(name[0] == 'A' || name[0] == 'B')
2396             node.type = floppy;
2397          else
2398             node.type = removable;
2399       }
2400    }
2401    else
2402    {
2403       char extension[MAX_EXTENSION];
2404       GetExtension(node.name, extension);
2405       node.type = _FileType::SelectByExtension(extension);
2406    }
2407    return node;
2408 }*/
2409
2410 FileSystemNode MakeFileSystemNode(
2411    const FileStats stats,
2412    const char * name,
2413    const char * path,
2414    const bool pathAddName,
2415    const bool previewPicture,
2416    const DisplaySystem displaySystem)
2417 {
2418    int len = strlen(name);
2419    char info[MAX_LOCATION];
2420    char name2[MAX_LOCATION];
2421    char extension[MAX_EXTENSION];
2422    
2423    FileSystemNode node { stats = stats };
2424
2425    /*if(!pathAddName)
2426    {
2427       char o[MAX_LOCATION];
2428       //char r[MAX_LOCATION];
2429       //StripLastDirectory(path, o);
2430       GetLastDirectory(path, o);
2431       if(fstrcmp(name, o))
2432       //if(!FileExists(path))
2433          PrintLn("Stop!");
2434    }*/
2435    //if(stats.attribs.isFile) // TODO fix this in ecere -- WTH -- this has been fixed :/
2436    if(stats.attribs.isDirectory)
2437    {
2438       extension[0] = '\0';
2439
2440       node.type = (stats.attribs.isDrive) ? drive : folder;
2441       if(stats.attribs.isServer) node.type = server;
2442       if(stats.attribs.isShare) node.type = share;
2443       if(stats.attribs.isCDROM) node.type = cdrom;
2444       if(stats.attribs.isRemote) node.type = netDrive;
2445       if(stats.attribs.isRemovable) 
2446       {
2447          if(name[0] == 'A' || name[0] == 'B')
2448             node.type = floppy;
2449          else
2450             node.type = removable;
2451       }
2452    }
2453    else
2454    {
2455       GetExtension(name, extension);
2456       strlwr(extension);
2457       
2458       node.type = _FileType::SelectByExtension(extension);
2459    }
2460
2461    if(stats.attribs.isDrive && 
2462          len > 3 && !strncmp(&name[1], ": [", 3))
2463    {
2464       strncpy(name2, name, 2);
2465       name2[2] = 0;
2466       strncpy(info, &name[4], len - 5);
2467       info[len - 5] = 0;
2468    }
2469    else
2470    {
2471       strcpy(name2, name);
2472       info[0] = 0;
2473    }
2474
2475    if(pathAddName)
2476    {
2477       bool isFile = stats.attribs.isFile;
2478       bool isFolder = stats.attribs.isDirectory;
2479       char full[MAX_LOCATION];
2480       strcpy(full, path);
2481       PathCat(full, name);
2482       node.path = full; //CopyString(full);
2483    }
2484    else
2485       node.path = path; //CopyString(path);
2486    node.name = name2; //CopyString(name2);
2487    if(info[0])
2488       node.info = info; //CopyString(info);
2489    node.extension = extension; //CopyString(extension);
2490
2491    if(node.type == pictureFile && previewPicture)
2492    {
2493       node.bitmap = Bitmap { alphaBlend = true };
2494       node.bitmap.Load(path, null, displaySystem);
2495    }
2496
2497    return node;
2498 }