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