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