libede: renamed _FileType::isFolderType to _FileType::isFolder and _FileType::isFileT...
[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);
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 ExplorerControl : Window
141 {
142    bool previewPictures;
143
144    BitmapResource fileIcons[_FileType];
145
146    ExplorerControl()
147    {
148       _FileType c;
149       for(c = 0; c < _FileType::enumSize; c++)
150       {
151          fileIcons[c] = BitmapResource { fileIconNames[c], alphaBlend = true };
152          AddResource(fileIcons[c]);
153       }
154    }
155 }
156
157 #if 0
158 class ExplorerView : ExplorerControl
159 {
160    borderStyle = none;
161    hasHorzScroll = false;
162    hasVertScroll = false;
163
164    virtual void Load(FileSystemNode parent);
165    virtual void Refresh();
166
167    virtual void LaunchNotifyItemSelect(Window master, ExplorerView view, ExplorerFileItem item, ExplorerFileItemArray selectedItems)
168    {
169       view.NotifyItemSelect(master, view, item, selectedItems);
170    }
171
172    virtual bool Window::NotifyItemSelect(ExplorerView view, ExplorerFileItem item, ExplorerFileItemArray selectedItems);
173    virtual bool Window::NotifyItemOpen(ExplorerView view, ExplorerFileItem item);
174
175    ListBox list
176    {
177       master = master, parent = this;
178       //this, master;
179       borderStyle = none;
180       hasHorzScroll = true;
181       hasVertScroll = true;
182       resizable = true;
183       sortable = true;
184       fullRowSelect = false;
185       multiSelect = true;
186
187       anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
188
189       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
190       {
191          ExplorerView view = (ExplorerView)listBox.parent;
192          if(listBox.currentRow)
193          {
194             DataRow listRow;
195             ExplorerFileItemArray selectedItems { growingFactor = 16 };
196             for(listRow = listBox.firstRow; listRow; listRow = listRow.next)
197                if(listRow.selected)
198                   selectedItems.Add((ExplorerFileItem)listRow.tag);
199             //view.NotifyItemSelect(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag);
200             view.LaunchNotifyItemSelect(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag, selectedItems);
201          }
202          return true;
203       }
204
205       bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
206       {
207          ExplorerView view = (ExplorerView)listBox.parent;
208          view.NotifyItemOpen(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag);
209          return false;
210       }
211
212       bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
213       {
214          if((SmartKey)key == enter)
215          {
216             ExplorerView view = (ExplorerView)listBox.parent;
217             view.NotifyItemOpen(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag);
218          }
219          return true;
220       }
221    };
222
223    ExplorerView()
224    {
225    }
226 }
227 #endif
228
229 #if 0
230 class ExplorerViewList : ExplorerView
231 {
232
233    FileSystemNode location;
234
235 public:
236
237    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
238
239    ExplorerViewDetails()
240    {
241       list.AddField(nameField);
242    }
243
244    void Refresh()
245    {
246       Load(location);
247    }
248
249    void Load(FileSystemNode location)
250    {
251       char path[MAX_LOCATION];
252       this.location = location;
253       location.GetPath(path);
254       {
255          FileListing listing { path };
256          
257          ExplorerFileItem item;
258          DataRow row;
259
260          list.Clear();
261
262          while(listing.Find())
263          {
264             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
265
266             row = list.AddRow();
267             row.tag = (int)item;
268             row.SetData(nameField, item);
269          }
270          list.Sort(nameField, 1);
271       }
272    }
273 }
274 #endif
275
276 #if 0
277 class ExplorerViewDetails : ExplorerView
278 {
279    list.hasHeader = true;
280    list.moveFields = true;
281    list.resizable = true;
282    list.sortable = true;
283
284    FileSystemNode location;
285
286 public:
287
288    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
289    DataField typeField { header = "Type", dataType = /*"String"*/ "char *", width = 40 };
290    DataField sizeField { header = "Size", dataType = "FileSize", width = 96, alignment = right };
291
292    ExplorerViewDetails()
293    {
294       list.AddField(nameField);
295       list.AddField(typeField);
296       list.AddField(sizeField);
297    }
298
299    void Refresh()
300    {
301       Load(location);
302    }
303
304    void Load(FileSystemNode location)
305    {
306       char path[MAX_LOCATION];
307       this.location = location;
308       location.GetPath(path);
309       {
310          FileListing listing { path };
311          
312          ExplorerFileItem item;
313          DataRow row;
314
315          list.Clear();
316
317          while(listing.Find())
318          {
319             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
320
321             row = list.AddRow();
322             row.tag = (int)item;
323             row.SetData(nameField, item);
324             row.SetData(typeField, CopyString(item.extension));
325             row.SetData(sizeField, (uint)listing.stats.size);
326          }
327          list.Sort(nameField, 1);
328       }
329    }
330 }
331 #endif
332
333 #if 0
334 class ExplorerViewIcons : ExplorerView
335 {
336
337    FileSystemNode location;
338
339 public:
340
341    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
342
343    ExplorerViewDetails()
344    {
345       list.AddField(nameField);
346    }
347
348    void Refresh()
349    {
350       Load(location);
351    }
352
353    void Load(FileSystemNode location)
354    {
355       char path[MAX_LOCATION];
356       this.location = location;
357       location.GetPath(path);
358       {
359          FileListing listing { path };
360          
361          ExplorerFileItem item;
362          DataRow row;
363
364          list.Clear();
365
366          while(listing.Find())
367          {
368             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
369
370             row = list.AddRow();
371             row.tag = (int)item;
372             row.SetData(nameField, item);
373          }
374          list.Sort(nameField, 1);
375       }
376    }
377 }
378 #endif
379
380 #if 0
381 class ExplorerViewCards : ExplorerView
382 {
383
384    FileSystemNode location;
385
386 public:
387
388    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
389
390    ExplorerViewDetails()
391    {
392       list.AddField(nameField);
393    }
394
395    void Refresh()
396    {
397       Load(location);
398    }
399
400    void Load(FileSystemNode location)
401    {
402       char path[MAX_LOCATION];
403       this.location = location;
404       location.GetPath(path);
405       {
406          FileListing listing { path };
407          
408          ExplorerFileItem item;
409          DataRow row;
410
411          list.Clear();
412
413          while(listing.Find())
414          {
415             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
416
417             row = list.AddRow();
418             row.tag = (int)item;
419             row.SetData(nameField, item);
420          }
421          list.Sort(nameField, 1);
422       }
423    }
424 }
425 #endif
426
427 #if 0
428 public class BitmapArray : RedjArray
429 {
430    type = class(Bitmap);
431 public:
432    Bitmap * const _;
433    Bitmap * Add(Bitmap bitmap)
434    {
435       uint pos = _count;
436       Append(1);
437       _[pos] = bitmap;
438       return &_[pos];
439    }
440    Bitmap * AddBefore(uint position, Bitmap bitmap)
441    {
442       Insert(position, 1);
443       _[position] = bitmap;
444       return &_[position];
445    }
446    void Clear()
447    {
448       int c;
449       for(c = 0; c < _count; c++)
450       {
451          _[c].Free();
452          delete _[c];
453       }  
454       count = 0;
455       size = 0;
456    }
457 }
458 #endif
459
460 #if 0
461 class ExplorerViewShowcase : ExplorerView
462 {
463    list.anchor = Anchor { left = 0, top = 0, bottom = 0 };
464    list.size = Size { w = 200 };
465
466    FileSystemNode location;
467
468 public:
469
470    DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 180, editable = true, userData = this };
471
472    Bitmap bitmap;
473    BitmapArray bitmaps { growingFactor = 16 };
474
475    Window show
476    {
477       this;
478       borderStyle = none;
479       anchor = Anchor { top = 0, right = 0, bottom = 0 };
480
481       void OnRedraw(Surface surface)
482       {
483          ExplorerViewShowcase view = (ExplorerViewShowcase)parent;
484          if(view.bitmap)
485          {
486             int wBmp = view.bitmap.width;
487             int hBmp = view.bitmap.height;
488             int wWnd = clientSize.w;
489             int hWnd = clientSize.h;
490
491             int wList = view.list.size.w + view.split.size.w;
492             
493             float scale = Min((float)(wWnd - 10) / wBmp, (float)(hWnd - 10) / hBmp);
494             
495             int wDraw = (int)(wBmp * scale);
496             int hDraw = (int)(hBmp * scale);
497
498       #ifndef __linux__
499             surface.Filter(view.bitmap, (wWnd - wDraw) / 2, (hWnd - hDraw) / 2, 0, 0, wDraw, hDraw, wBmp, hBmp);
500       #else
501             // Until Filter / Stretch works with X
502             surface.Blit(view.bitmap, (wWnd - wDraw) / 2, (hWnd - hDraw) / 2, 0, 0, wDraw, hDraw);
503       #endif
504          }
505          else
506          {
507             surface.SetForeground(white);
508             surface.Area(0, 0, view.clientSize.w - 1, view.clientSize.h - 1);
509          }
510       }
511    }
512
513    SplitWindow split
514    {
515       this;
516       leftPane = list;
517       rightPane = show;
518       split = 200;
519       tabCycle = true;
520    };
521
522    ExplorerViewDetails()
523    {
524       list.AddField(nameField);
525    }
526
527    void LaunchNotifyItemSelect(Window master, ExplorerViewShowcase view, ExplorerFileItem item, ExplorerFileItemArray selectedItems)
528    {
529       int pos;
530       ExplorerFileItem selItem;
531       if(view.bitmap)
532          view.bitmap.Free();
533       delete view.bitmap;
534       if(item && item.type == pictureFile)
535       {
536          view.bitmap = Bitmap { };
537          view.bitmap.Load(item.path, null, displaySystem);
538       }
539
540       view.bitmaps.Clear();
541       view.bitmaps = BitmapArray { };
542       for(pos = 0; pos < selectedItems.count; pos++)
543       {
544          Bitmap bitmap { };
545          selItem = (ExplorerFileItem)selectedItems._[pos]; 
546          bitmap.Load(selItem.path, null, displaySystem);
547          //view.bitmaps.Add(bitmap);
548       }  
549       if(item && item.type == pictureFile)
550       {
551          view.bitmap = Bitmap { };
552          view.bitmap.Load(item.path, null, displaySystem);
553       }
554
555       view.show.Update(null);
556       view.NotifyItemSelect(master, view, item, selectedItems);
557    }
558
559    void Refresh()
560    {
561       Load(location);
562    }
563
564    void Load(FileSystemNode location)
565    {
566       char path[MAX_LOCATION];
567       this.location = location;
568       location.GetPath(path);
569       {
570          FileListing listing { path };
571          
572          ExplorerFileItem item;
573          DataRow row;
574
575          list.Clear();
576
577          while(listing.Find())
578          {
579             item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem);
580
581             row = list.AddRow();
582             row.tag = (int)item;
583             row.SetData(nameField, item);
584          }
585          list.Sort(nameField, 1);
586       }
587    }
588 }
589 #endif
590
591 #if 0
592 class ExplorerTree : ExplorerControl
593 {
594    hasHorzScroll = false;
595    hasVertScroll = false;
596
597    menu = Menu { };
598
599 public:
600
601    DataField nameField { dataType = "FileSystemNode", width = 240, userData = this };
602
603    FileSystemNode root;
604    FileSystemNode selection;
605
606    virtual bool Window::NotifyNodeSelect(ExplorerTree tree, FileSystemNode node);
607    
608    property FileSystemNode node
609    {
610       get
611       {
612          if(!tree)
613             return null;
614          if(!tree.currentRow)
615             return null;
616          if(!tree.currentRow.tag)
617             return null;
618          return (FileSystemNode)tree.currentRow.tag;
619       }
620    }
621
622    void Select(FileSystemNode node)
623    {
624       if(node.row)
625       {
626          node.EnsureVisible(false);
627          tree.SelectRow(node.row);
628       }
629    }
630
631    FileSystemNode Find(const char * name, FileSystemNode parent)
632    {
633       FileSystemNode node;
634       FileSystemNode start = parent ? parent : root;
635       if(!start.loaded || !start.childrenLoaded)
636          NodeLoad(start, tree);
637       for(node = start.children.first; node; node = node.next)
638          if(node.name && !strcmpi(node.name, name))
639             return node;
640       return null;
641    }
642
643    ListBox tree
644    {
645       master = master, parent = this;
646       //this, master;
647       borderStyle = none;
648       hasHorzScroll = true;
649       hasVertScroll = true;
650       fullRowSelect = false;
651       treeNodees = true;
652       collapseControl = true;
653       rootCollapseButton = true;
654
655       anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
656
657       // WHY is this not working ?
658       /*void OnResize(int width, int height)
659       {
660          if(vertScroll.visible)
661             nameField.width = width - vertScroll.size.w;
662          else
663             nameField.width = width;
664       }*/
665
666       bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed)
667       {
668          if(row)
669          {
670             FileSystemNode node = (FileSystemNode)row.tag;
671             FileSystemNode child;
672             if(collapsed)
673             {
674                /*
675                for(child = node.children.last; child; child = node.children.last)
676                {
677                   listBox.DeleteRow(child.row);
678                   child.Free();
679                   delete child;
680                }
681                node.childrenLoaded = false;
682                */
683             }
684             else
685             {
686                if(!node.loaded || !node.childrenLoaded)
687                   NodeLoad(node, tree);
688                for(child = node.children.first; child && child.next; child = child.next);
689                if(child)
690                   child.EnsureVisible(false);
691             }
692          }
693          return true;
694       }
695       
696       bool NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods)
697       {
698          DataRow row = listBox.currentRow;
699          if(row)
700          {
701             FileSystemNode node = (FileSystemNode)row.tag;
702             if(node)
703             {
704                PopupMenu popup;
705                Menu menu { };
706
707                MenuItem { menu, "Cut\tCtrl+X", t, NotifySelect = null, disabled = false };
708                MenuItem { menu, "Copy\tCtrl+C", c, NotifySelect = null, disabled = false };
709                MenuItem { menu, "Paste\tCtrl+V", p, NotifySelect = null, disabled = false /*!clipboard*/ };
710                MenuItem { menu, "Delete\tDel", d, NotifySelect = null, disabled = false };
711                //MenuDivider { menu };
712
713                popup = PopupMenu
714                   {
715                      master = this, menu = menu,
716                      position = { 
717                         x + clientStart.x + absPosition.x - guiApp.desktop.position.x, 
718                         y + clientStart.y + absPosition.y - guiApp.desktop.position.y }
719                   };
720                popup.Create();
721             }
722          }
723          return true;
724       }
725
726       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
727       {
728          if(row)
729          {
730             FileSystemNode node = (FileSystemNode)row.tag;
731             NotifyNodeSelect(listBox.parent.master, this, node);
732             selection = node;
733          }
734          return true;
735       }
736
737       bool NotifyEditing(ListBox listBox, DataRow row)
738       {
739          if(row)
740          {
741             FileSystemNode node = (FileSystemNode)row.tag;
742          }
743          return true;
744       }
745
746       bool NotifyEdited(ListBox listBox, DataRow row)
747       {
748          if(row)
749          {
750             FileSystemNode node = (FileSystemNode)row.tag;
751          }
752          return true;
753       }
754
755       bool NotifyEditDone(ListBox listBox, DataRow row)
756       {
757          if(row)
758          {
759             FileSystemNode node = (FileSystemNode)row.tag;
760          }
761          return true;
762       }
763    };
764
765    // Edit Menu
766    Menu editMenu { menu, "Edit", e };
767    MenuItem itemEditCut
768    {
769       editMenu, "Cut\tCtrl+X", t, disabled = true;
770
771       bool NotifySelect(MenuItem selection, Modifiers mods)
772       {
773          //EditCut();
774          return true;
775       }
776    };
777    MenuItem itemEditCopy
778    {
779       editMenu, "Copy\tCtrl+C", c, disabled = true;
780
781       bool NotifySelect(MenuItem selection, Modifiers mods)
782       {
783          //EditCopy();
784          return true;
785       }
786    };
787    MenuItem itemEditPaste
788    {
789       editMenu, "Paste\tCtrl+V", p;
790    
791       bool NotifySelect(MenuItem selection, Modifiers mods)
792       {
793          //EditPaste();
794          return true;
795       }
796    };
797    MenuItem itemEditDelete
798    {
799       editMenu, "Delete\tDel", d, disabled = true;
800
801       bool NotifySelect(MenuItem selection, Modifiers mods)
802       {
803          //EditDelete();
804          return true;
805       }
806    };
807
808    // WHY is this crashing ? 
809    /*void OnResize(int width, int height)
810    {
811       if(this && nameField)
812          nameField.width = width - 80;
813    }*/
814
815    ExplorerTree()
816    {
817       tree.AddField(nameField);
818    }
819
820    void Load()
821    {
822       FileSystemNode parent;
823       FileSystemNode node;
824       FileListing listing { "/" };
825
826       tree.Clear();
827
828       root = FileSystemNode { type = computer, loaded = true, childrenLoaded = true };
829    #ifdef __WIN32__
830       root.name = rootName;
831    #else
832       root.name = "/";
833    #endif
834       AddNode(root, true, false, null, tree);
835
836    // How can this make sense for linux? 
837    #ifdef __WIN32__
838       while(listing.Find())
839       {
840          int len = strlen(listing.name);
841          char info[MAX_LOCATION];
842          char name[MAX_LOCATION];
843          if(listing.stats.attribs.isDrive && 
844                len > 3 && !strncmp(&listing.name[1], ": [", 3))
845          {
846             strncpy(name, listing.name, 2);
847             name[2] = 0;
848             strncpy(info, &listing.name[4], len - 5);
849             info[len - 5] = 0;
850          }
851          else
852          {
853             strcpy(name, listing.name);
854             info[0] = 0;
855          }
856
857          parent = MakeFileNode(listing.stats, name);
858          if(info[0])
859             parent.info = CopyString(info);
860          parent.loaded = true;
861          AddNode(parent, !listing.stats.attribs.isDirectory, listing.stats.attribs.isDirectory, root, tree);
862          if(!listing.stats.attribs.isDirectory)
863             parent.childrenLoaded = true;
864       }
865
866       node = FileSystemNode { name = msNetwork, type = network };
867       AddNode(node, false, true, null, tree);
868       node.row.collapsed = true;
869       tree.Sort(nameField, 1);
870       tree.SelectRow(root.row);
871    #endif
872    }
873
874 /*
875 public class ClipBoardFiles
876 {
877
878 public:
879
880    property
881
882 }
883
884    // CLIPBOARD
885    void Copy()
886    {
887       if(this)
888       {
889          int size = SelSize();
890          if(size)
891          {
892             // Try to allocate memory
893             ClipBoard clipBoard { };
894             if(clipBoard.Allocate(size+1))
895             {
896                GetSel(clipBoard.memory, true);   
897                // Save clipboard
898                clipBoard.Save();
899             }
900             delete clipBoard;
901          }
902       }
903    }
904
905    void Paste()
906    {
907       if(this)
908       {
909          ClipBoard clipBoard { };
910          if(clipBoard.Load())
911             PutS(clipBoard.memory);
912          delete clipBoard;
913       }
914    }
915
916    void Cut()
917    {
918       if(this)
919       {
920          Copy();
921          DelSel();
922          SetViewToCursor(true);
923          Modified();
924       }
925    }
926
927 Private Type DROPFILES
928    pFiles As Long
929    pt As POINTAPI
930    fNC As Long
931    fWide As Long
932 End Type
933 For iCounter = 0 To filelist.ListCount - 1
934   If filelist.Selected(iCounter) = True Then
935     strFiles = strFiles & FixPath(filelist.Path) & filelist.List(iCounter) & vbNullChar
936   End If
937 Next
938 'all selected items are now put in strFiles
939
940 hGlobal = GlobalAlloc(GHND, Len(DF) + Len(strFiles)) 'put all files to a exclusive number
941 If hGlobal Then 'if the globalalloc worked
942   lpGlobal = GlobalLock(hGlobal) 'lock the hGlobal
943   DF.pFiles = Len(DF) 'set the size of the files
944   
945   Call CopyMem(ByVal lpGlobal, DF, Len(DF)) 'copy df to the lpglobal
946   Call CopyMem(ByVal (lpGlobal + Len(DF)), ByVal strFiles, Len(strFiles)) 'copy strfiles to lpglobal
947   Call GlobalUnlock(hGlobal) 'unlock hglobal again
948   
949   SetClipboardData CF_HDROP, hGlobal 'put files to the clipboard
950 End If
951
952    bool SaveFile(const char * filePath)
953    {
954    }
955 */
956
957 }
958 #endif
959
960 #if 0
961 public class FileTreeNodeBSArray : ArrayBinarySorted
962 {
963    type = class(FileSystemNode);
964 public:
965    FileSystemNode * const _;
966    BSloc Add(FileSystemNode item)
967    {
968       BSloc result = Find(item);
969       if(!result.valid)
970       {
971          Insert(result.pos, 1);
972          _[result.pos] = item;
973       }
974       return result;
975    }
976    BSloc Remove(FileSystemNode item)
977    {
978       
979    }
980 }
981 #endif
982
983 #if 0
984 public class FileTreeNodeArray : RedjArray
985 {
986    type = class(FileSystemNode);
987 public:
988    FileSystemNode * const _;
989    FileSystemNode * Add(FileSystemNode item)
990    {
991       uint pos = _count;
992       Append(1);
993       _[pos] = item;
994       return &_[pos];
995    }
996    FileSystemNode * AddBefore(uint position, FileSystemNode item)
997    {
998       Insert(position, 1);
999       _[position] = item;
1000       return &_[position];
1001    }
1002 }
1003 #endif
1004
1005 #if 0
1006 public class ExplorerFileItem : struct
1007 {
1008    char * path;
1009    char * name;
1010    char * info;
1011    char * extension;
1012    _FileType type;
1013    int indent;
1014
1015    Bitmap bitmap;
1016
1017    void OnDisplay(Surface surface, int x, int y, int width, ExplorerControl control, Alignment alignment, DataDisplayFlags displayFlags)
1018    {
1019       int indentSize = (displayFlags.dropBox) ? 0 : 10;
1020       int textOffset;
1021       int len;
1022       char label[MAX_FILENAME];
1023
1024       //float scale = Min((float)clientSize.w / (float)bitmap.width, (float)clientSize.h / (float)bitmap.height);
1025       int w = 16; //(int)(bitmap.width * scale);
1026       int h = 16; //(int)(bitmap.height * scale);
1027    
1028       Bitmap icon;
1029
1030       icon = control.fileIcons[type].bitmap;
1031       if(!icon)
1032       {
1033          if(type == folder || type == folderOpen)
1034             surface.SetForeground(red); //Color { 170, 170, 0 } // REDJ What is that color?
1035          indentSize = 8;
1036       }
1037       textOffset = indent * indentSize + (icon ? (icon.width + 6) : 0);
1038       
1039       if(info)
1040          sprintf(label, "%s [%s]", name, info);
1041       else
1042          strcpy(label, name);
1043       len = strlen(label);
1044
1045       surface.WriteTextDots
1046          (alignment, x + textOffset, y + 2, width - textOffset, label, len);
1047       if(type == pictureFile && control.previewPictures && bitmap)
1048       {
1049 #ifndef __linux__
1050          //surface.Filter(bitmap, (clientSize.w - w) / 2,(clientSize.h - h) / 2, 0,0, w, h, bitmap.width, bitmap.height);
1051          surface.Filter(bitmap, x + indent * indentSize + 2, y, 0, 0, w, h, bitmap.width, bitmap.height);
1052 #else
1053          // Until Filter / Stretch works with X
1054          //surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2,(clientSize.h - bitmap.height) / 2, 0,0, bitmap.width, bitmap.height);
1055          surface.blend = true;
1056          surface.Blit(bitmap, x + indent * indentSize + 2, y,0,0, w, h);
1057 #endif
1058          //bitmap.Free();
1059          //delete bitmap;
1060       }
1061       else if(icon)
1062          surface.Blit(icon, x + indent * indentSize + 2, y,0,0, icon.width, icon.height);
1063    }
1064
1065    int OnCompare(ExplorerFileItem b)
1066    {
1067       int result;
1068       if(type == b.type || (type < folder && b.type < folder) || (type >= drive))
1069          result = strcmpi(name, b.name);
1070       else
1071       {
1072          if(type == folder && b.type < folder) result = -1;
1073          else if(type < folder && b.type == folder) result = 1;
1074       }
1075       return result;
1076    }
1077
1078    void OnCopy(ExplorerFileItem newData)
1079    {
1080       type = newData.type;
1081       indent = newData.indent;
1082       if(newData.name)
1083       {
1084          int len = strlen(newData.name) + 1;
1085          name = new char[len];
1086          CopyBytes(name, newData.name, len);
1087       }
1088    }
1089
1090    bool OnGetDataFromString(char * string)
1091    {
1092       int len = strlen(string) + 1;
1093       name = new char[len];
1094       CopyBytes(name, string, len);
1095       return true;
1096    }
1097
1098    void OnFree()
1099    {
1100       delete path;
1101       delete name;
1102       delete info;
1103       delete extension;
1104       if(bitmap)
1105          bitmap.Free();
1106    }
1107
1108    char * OnGetString(char * string, void * fieldData, bool * needClass)
1109    {
1110       return name;
1111    }
1112 };
1113
1114 public class ExplorerFileItemArray : RedjArray
1115 {
1116    type = class(ExplorerFileItem);
1117 public:
1118    ExplorerFileItem * const _;
1119    ExplorerFileItem * Add(ExplorerFileItem item)
1120    {
1121       uint pos = _count;
1122       Append(1);
1123       _[pos] = item;
1124       return &_[pos];
1125    }
1126    ExplorerFileItem * AddBefore(uint position, ExplorerFileItem item)
1127    {
1128       Insert(position, 1);
1129       _[position] = item;
1130       return &_[position];
1131    }
1132    void Clear()
1133    {
1134       int c;
1135       for(c = 0; c < _count; c++)
1136       {
1137          //_[c].Free()
1138          delete _[c];
1139       }  
1140       count = 0;
1141       size = 0;
1142    }
1143 }
1144
1145 ExplorerFileItem MakeFileItem(const FileAttribs attribs, const char * fileName, const char * filePath, const bool previewPicture, const DisplaySystem displaySystem)
1146 {
1147    int len = strlen(fileName);
1148    char info[MAX_LOCATION];
1149    char name[MAX_LOCATION];
1150    char extension[MAX_EXTENSION];
1151    
1152    ExplorerFileItem item { };
1153
1154    //if(attribs.isFile) // TODO fix this in ecere
1155    if(attribs.isDirectory)
1156    {
1157       extension[0] = 0;
1158
1159       item.type = (attribs.isDrive) ? drive : folder;
1160       if(attribs.isServer)
1161          item.type = server;
1162       if(attribs.isShare)
1163          item.type = share;
1164       if(attribs.isCDROM)
1165          item.type = cdrom;
1166       if(attribs.isRemote)
1167          item.type = netDrive;
1168       if(attribs.isRemovable) 
1169       {
1170          if(fileName[0] == 'A' || fileName[0] == 'B')
1171             item.type = floppy;
1172          else
1173             item.type = removable;
1174       }
1175    }
1176    else
1177    {
1178       GetExtension(fileName, extension);
1179       //strupr(extension);
1180       strlwr(extension);
1181       
1182       item.type = _FileType::SelectByExtension(extension);
1183    }
1184
1185    if(attribs.isDrive && 
1186          len > 3 && !strncmp(&fileName[1], ": [", 3))
1187    {
1188       strncpy(name, fileName, 2);
1189       name[2] = 0;
1190       strncpy(info, &fileName[4], len - 5);
1191       info[len - 5] = 0;
1192    }
1193    else
1194    {
1195       strcpy(name, fileName);
1196       info[0] = 0;
1197    }
1198
1199    item.path = CopyString(filePath);
1200    item.name = CopyString(name);
1201    if(info[0])
1202       item.info = CopyString(info);
1203    item.extension = CopyString(extension);
1204
1205    if(item.type == pictureFile && previewPicture)
1206    {
1207       item.bitmap = Bitmap { };
1208       item.bitmap.Load(filePath, null, displaySystem);
1209    }
1210
1211    return item;
1212 }
1213 #endif
1214
1215 public class FileSystemNode : struct
1216 {
1217    FileSystemNode prev, next;
1218
1219    bool loaded, childrenLoaded;
1220    int indent;
1221    char * name;
1222    char * info;
1223    DataRow row;
1224    OldList children;
1225    _FileType type;
1226    FileSystemNode parent;
1227
1228    FileStats stats;
1229
1230    void GetPath(String outputPath)
1231    {  
1232       FileSystemNode up;
1233       if(parent)
1234       {
1235          strcpy(outputPath, name);
1236          for(up = parent; up; up = up.parent)
1237          {
1238             char temp[MAX_LOCATION];
1239             strcpy(temp, up.name);
1240             PathCat(temp, outputPath);
1241             strcpy(outputPath, temp);
1242          }
1243       }
1244       else
1245 #ifdef __WIN32__
1246          strcpy(outputPath, "/");
1247 #else
1248          strcpy(outputPath, name);
1249 #endif
1250
1251    }
1252
1253    bool IsChildOf(FileSystemNode node)
1254    {
1255       FileSystemNode test;
1256       for(test = parent; test; test = test.parent)
1257          if(test == node)
1258             return true;
1259       return false;
1260    }
1261
1262    void DuplicateChildren(bool recursive, bool forceExpanded, FileSystemNode addTo, ListBox tree)
1263    {
1264       if(children.first)
1265       {
1266          FileSystemNode child;
1267          
1268          for(child = children.first; child; child = child.next)
1269          {
1270             FileSystemNode copy { };
1271             copy.name = CopyString(child.name);
1272             copy.type = child.type;
1273             AddNode(copy, child.loaded, false, addTo, tree);
1274             if(forceExpanded)
1275                copy.row.collapsed = false;
1276             if(recursive)
1277                child.DuplicateChildren(recursive, forceExpanded, copy, tree);
1278          }
1279       }
1280    }
1281    
1282    void EnsureVisible(bool expand)
1283    {
1284       if(parent)
1285          parent.EnsureVisible(true);
1286       if(expand)
1287          row.collapsed = false;
1288       // TODO: row.EnsureVisible(); // making the row visible by scrolling
1289    }
1290
1291    void OnFree()
1292    {
1293       //delete name;
1294    }
1295
1296    void Free()
1297    {
1298       FileSystemNode child;
1299       for(; (child = children.first); )
1300       {
1301          child.Free();
1302          children.Delete(child);
1303       }
1304       //if(name)
1305       delete name;
1306       delete info;
1307    }
1308
1309    void Delete()
1310    {
1311       Free();
1312       if(parent)
1313          parent.children.Delete(this);
1314    }
1315
1316    void OnDisplay(Surface surface, int x, int y, int width, ExplorerControl control, Alignment alignment, DataDisplayFlags displayFlags)
1317    {
1318       //int indentSize = (displayFlags.dropBox) ? 0 : 10;
1319       int indent = 16;
1320       int xStart;
1321       int len;
1322       int w, h;
1323       //int textOffset;
1324       char label[MAX_FILENAME];
1325
1326       Bitmap icon;
1327
1328       if(!this)
1329          return;
1330       
1331       icon = control.fileIcons[type].bitmap;
1332       //xStart = indent * indent + x + (icon ? (icon.width + 5) : 0);
1333       xStart = x + (icon ? (icon.width + 5) : 0);
1334
1335       if(!name)
1336          return;
1337
1338       if(info)
1339          sprintf(label, "%s [%s]", name, info);
1340       else
1341          strcpy(label, name);
1342       len = strlen(label);
1343       
1344       if(!icon)
1345       {
1346          if(type == folder || type == folderOpen)
1347             surface.SetForeground(yellow);
1348          //indentSize = 8;
1349          indent = 8;
1350       }
1351       //textOffset = indent * indentSize + (icon ? (icon.width + 4) : 0);
1352       
1353       surface.TextOpacity(false);
1354       surface.TextExtent(label, len, &w, &h);
1355       h = Max(h, 16);
1356     
1357       // Draw the current row stipple
1358       if(displayFlags.selected)
1359          //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1360          //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1361          surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1362       
1363       //surface.WriteTextDots(alignment, x + textOffset, y + 2, width - textOffset, name, strlen(name));
1364       surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1365
1366       if(!guiApp.textMode)
1367       {
1368          if(displayFlags.current)
1369          {
1370             if(displayFlags.active)
1371             {
1372                surface.LineStipple(0x5555);
1373                if(displayFlags.selected)
1374                   surface.SetForeground(0xFFFFFF80);
1375                else
1376                   surface.SetForeground(black);
1377             }
1378             else
1379             {
1380                surface.SetForeground(selectionColor);
1381             }
1382             surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1383             surface.LineStipple(0);
1384          }
1385
1386          if(icon)
1387          {
1388             //surface.blend = true;
1389             //surface.alphaWrite = blend;
1390             surface.SetForeground(white);
1391             //surface.Blit(icon, x + indent * indentSize, y,0,0, icon.width, icon.height);
1392             surface.Blit(icon, x,y,0,0, icon.width, icon.height);
1393          }
1394       }
1395    }
1396
1397    int OnCompare(FileSystemNode b)
1398    {
1399       int result;
1400       if(type == b.type || (type < folder && b.type < folder) || (type >= drive))
1401          result = strcmpi(name, b.name);
1402       else
1403       {
1404          if(type == folder && b.type < folder) result = -1;
1405          else if(type < folder && b.type == folder) result = 1;
1406       }
1407       return result;
1408    }
1409
1410    char * OnGetString(char * tempString, FileSystemToolWindow fileSysToolWnd, bool * needClass)
1411    {
1412       return name ? name : "";
1413    }
1414 };
1415
1416 FileSystemNode MakeFileNode(const FileStats stats, const char * name)
1417 {
1418    FileSystemNode fileTreeNode { stats = stats };
1419    fileTreeNode.name = CopyString(name);
1420    if(!fileTreeNode.name)
1421       fileTreeNode.name = null;
1422    if(stats.attribs.isDirectory)
1423    {
1424       fileTreeNode.type = (stats.attribs.isDrive) ? drive : folder;
1425       if(stats.attribs.isServer) fileTreeNode.type = server;
1426       if(stats.attribs.isShare) fileTreeNode.type = share;
1427       if(stats.attribs.isCDROM) fileTreeNode.type = cdrom;
1428       if(stats.attribs.isRemote) fileTreeNode.type = netDrive;
1429       if(stats.attribs.isRemovable) 
1430       {
1431          if(name[0] == 'A' || name[0] == 'B')
1432             fileTreeNode.type = floppy;
1433          else
1434             fileTreeNode.type = removable;
1435       }
1436    }
1437    else
1438    {
1439       char extension[MAX_EXTENSION];
1440       GetExtension(fileTreeNode.name, extension);
1441       fileTreeNode.type = _FileType::SelectByExtension(extension);
1442    }
1443    return fileTreeNode;
1444 }
1445
1446 void AddNode(FileSystemNode node, bool loaded, bool addLoader, FileSystemNode addTo, ListBox tree)
1447 {
1448    DataRow row = (addTo && addTo.row) ? addTo.row.AddRow() : tree.AddRow();
1449    if(addTo)
1450    {
1451       node.parent = addTo;
1452       node.indent = addTo.indent + 1;
1453       addTo.children.Add(node);
1454    }
1455    row.tag = (int)node;
1456    node.row = row;
1457    row.SetData(null, node);
1458
1459    node.loaded = loaded;
1460    if(addLoader)
1461       //AddNode(FileSystemNode { }, false, false, node, tree); // why would this create a compile error?
1462       AddNode(FileSystemNode { type = none }, false, false, node, tree);
1463
1464    if(node.indent > 0)
1465       row.collapsed = true;
1466    else if(node.type == folder)
1467       node.type = folderOpen;
1468 }
1469
1470 void NodeLoad(FileSystemNode node, ListBox tree)
1471 {
1472    if(!node.loaded)
1473    {
1474       char path[MAX_LOCATION];
1475       node.GetPath(path);
1476       {
1477          FileListing listing { path };
1478          if(node.children.count == 1)
1479          DeleteNode(node.children.first, tree);
1480
1481          while(listing.Find())
1482          {
1483             if(listing.stats.attribs.isDirectory)
1484             {
1485                FileSystemNode child = MakeFileNode(listing.stats, listing.name);
1486                AddNode(child, true, false, node, tree);
1487                NodeChildLoad(child, node, tree);
1488             }
1489          }
1490       }
1491       node.childrenLoaded = true;
1492       node.loaded = true;
1493       node.row.SortSubRows(false);
1494    }
1495    else if(!node.childrenLoaded)
1496    {
1497       FileSystemNode child;
1498       if(node.children.first)
1499       {
1500          for(child = node.children.first; child; child = child.next)
1501          {
1502             if(!child.loaded)
1503                NodeLoad(child, tree);
1504             else if(!child.childrenLoaded)
1505                NodeChildLoad(child, node, tree);
1506          }
1507          node.childrenLoaded = true;
1508          node.row.SortSubRows(false);
1509       }
1510    }
1511 }
1512
1513 static void NodeChildLoad(FileSystemNode parent, FileSystemNode node, ListBox tree)
1514 {
1515    char path[MAX_LOCATION];
1516    parent.GetPath(path);
1517    {
1518       bool added = false;
1519       FileListing listing { path };
1520       while(listing.Find())
1521       {
1522          if(listing.stats.attribs.isDirectory)
1523          {
1524             FileSystemNode child = MakeFileNode(listing.stats, listing.name);
1525             AddNode(child, true, false, parent, tree);
1526             added = true;
1527          }
1528       }
1529       if(!added)
1530          added = true;
1531    }
1532    //parent.childrenLoaded = true;
1533 }
1534
1535 void DeleteNode(FileSystemNode node, ListBox tree)
1536 {
1537    FileSystemNode child;
1538    for(; (child = node.children.first); )
1539       DeleteNode(child, tree);
1540    tree.DeleteRow(node.row);
1541    node.Delete();
1542 }