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