1 /********************************************************************************
2 *                                                                               *
3 *                     D i r e c t o r y   B o x   O b j e c t                   *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1999,2005 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 of the License, or (at your option) any later version.            *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             *
16 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public              *
19 * License along with this library; if not, write to the Free Software           *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.    *
21 *********************************************************************************
22 * $Id: FXDirBox.cpp,v 1.56 2005/01/16 16:06:06 fox Exp $                        *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "fxkeys.h"
28 #include "FXHash.h"
29 #include "FXThread.h"
30 #include "FXStream.h"
31 #include "FXString.h"
32 #include "FXSize.h"
33 #include "FXPoint.h"
34 #include "FXRectangle.h"
35 #include "FXFile.h"
36 #include "FXSettings.h"
37 #include "FXRegistry.h"
38 #include "FXAccelTable.h"
39 #include "FXObjectList.h"
40 #include "FXApp.h"
41 #include "FXImage.h"
42 #include "FXIcon.h"
43 #include "FXGIFIcon.h"
44 #include "FXBMPIcon.h"
45 #include "FXFont.h"
46 #include "FXDC.h"
47 #include "FXWindow.h"
48 #include "FXFrame.h"
49 #include "FXLabel.h"
50 #include "FXTextField.h"
51 #include "FXButton.h"
52 #include "FXMenuButton.h"
53 #include "FXComposite.h"
54 #include "FXPacker.h"
55 #include "FXShell.h"
56 #include "FXPopup.h"
57 #include "FXScrollBar.h"
58 #include "FXScrollArea.h"
59 #include "FXTreeList.h"
60 #include "FXTreeListBox.h"
61 #include "FXDirBox.h"
62 #include "FXFileDict.h"
63 #include "icons.h"
64 
65 /*
66   Notes:
67   - When setting path, it adds all directories from the top down to
68     the lowest directory.
69   - Share icons with other widgets; upgrade icons to some nicer ones.
70   - Should some of these icons move to FXFileDict?
71   - Need to support ":" directory list separator so we can path not just
72     a single path but a list of paths.
73 */
74 
75 using namespace FX;
76 
77 /*******************************************************************************/
78 
79 namespace FX {
80 
81 
82 // Map
83 FXDEFMAP(FXDirBox) FXDirBoxMap[]={
84   FXMAPFUNC(SEL_CHANGED,FXDirBox::ID_TREE,FXDirBox::onTreeChanged),
85   FXMAPFUNC(SEL_CLICKED,FXDirBox::ID_TREE,FXDirBox::onTreeClicked),
86   FXMAPFUNC(SEL_COMMAND,FXDirBox::ID_SETVALUE,FXDirBox::onCmdSetValue),
87   FXMAPFUNC(SEL_COMMAND,FXDirBox::ID_SETSTRINGVALUE,FXDirBox::onCmdSetStringValue),
88   FXMAPFUNC(SEL_COMMAND,FXDirBox::ID_GETSTRINGVALUE,FXDirBox::onCmdGetStringValue),
89   };
90 
91 
92 // Implementation
FXIMPLEMENT(FXDirBox,FXTreeListBox,FXDirBoxMap,ARRAYNUMBER (FXDirBoxMap))93 FXIMPLEMENT(FXDirBox,FXTreeListBox,FXDirBoxMap,ARRAYNUMBER(FXDirBoxMap))
94 
95 
96 // Directory box
97 FXDirBox::FXDirBox(FXComposite *p,FXObject* tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb):
98   FXTreeListBox(p,tgt,sel,opts,x,y,w,h, pl,pr,pt,pb){
99   associations=NULL;
100   if(!(options&DIRBOX_NO_OWN_ASSOC)) associations=new FXFileDict(getApp());
101   foldericon=new FXGIFIcon(getApp(),minifolder);
102   cdromicon=new FXGIFIcon(getApp(),minicdrom);
103   harddiskicon=new FXGIFIcon(getApp(),miniharddisk);
104   netdriveicon=new FXGIFIcon(getApp(),mininetdrive);
105   floppyicon=new FXGIFIcon(getApp(),minifloppy);
106   nethoodicon=new FXGIFIcon(getApp(),mininethood);
107   zipdiskicon=new FXGIFIcon(getApp(),minizipdrive);
108   setDirectory(PATHSEPSTRING);
109   }
110 
111 
112 // Create
create()113 void FXDirBox::create(){
114   FXTreeListBox::create();
115   foldericon->create();
116   cdromicon->create();
117   harddiskicon->create();
118   netdriveicon->create();
119   floppyicon->create();
120   nethoodicon->create();
121   zipdiskicon->create();
122   }
123 
124 
125 // Detach disconnects the icons
detach()126 void FXDirBox::detach(){
127   foldericon->detach();
128   cdromicon->detach();
129   harddiskicon->detach();
130   netdriveicon->detach();
131   floppyicon->detach();
132   nethoodicon->detach();
133   zipdiskicon->detach();
134   FXTreeListBox::detach();
135   }
136 
137 
138 // Destroy zaps the icons
destroy()139 void FXDirBox::destroy(){
140   foldericon->destroy();
141   cdromicon->destroy();
142   harddiskicon->destroy();
143   netdriveicon->destroy();
144   floppyicon->destroy();
145   nethoodicon->destroy();
146   zipdiskicon->destroy();
147   FXTreeListBox::destroy();
148   }
149 
150 
151 // Set the current item's text from the message
onCmdSetValue(FXObject *,FXSelector,void * ptr)152 long FXDirBox::onCmdSetValue(FXObject*,FXSelector,void* ptr){
153   setDirectory((char*)ptr);
154   return 1;
155   }
156 
157 
158 // Change value
onCmdSetStringValue(FXObject *,FXSelector,void * ptr)159 long FXDirBox::onCmdSetStringValue(FXObject*,FXSelector,void* ptr){
160   setDirectory(*((FXString*)ptr));
161   return 1;
162   }
163 
164 
165 // Obtain value
onCmdGetStringValue(FXObject *,FXSelector,void * ptr)166 long FXDirBox::onCmdGetStringValue(FXObject*,FXSelector,void* ptr){
167   *((FXString*)ptr)=getDirectory();
168   return 1;
169   }
170 
171 
172 // Return item path
getItemPathname(FXTreeItem * item) const173 FXString FXDirBox::getItemPathname(FXTreeItem *item) const {
174   FXString string;
175   if(item){
176     while(item->getParent()){
177       string.prepend(getItemText(item));
178       item=item->getParent();
179       if(item->getParent()) string.prepend(PATHSEPSTRING);
180       }
181     string.prepend(getItemText(item));
182     }
183   return string;
184   }
185 
186 
187 #ifndef WIN32           // UNIX flavor
188 
189 // Return the item from the absolute pathname
getPathnameItem(const FXString & path)190 FXTreeItem* FXDirBox::getPathnameItem(const FXString& path){
191   register FXFileAssoc *fileassoc;
192   register FXTreeItem *item;
193   register FXIcon *icon;
194   register FXint beg=0;
195   register FXint end=0;
196 
197   // Remove old items first
198   clearItems();
199 
200   // Parse past root
201   if(ISPATHSEP(path[0])) end++;
202 
203   // Absolute path?
204   if(beg<end){
205 
206     // Determine associations, icons and type
207     icon=foldericon;
208     if(associations){
209       fileassoc=associations->findDirBinding("/");
210       if(fileassoc && fileassoc->miniicon) icon=fileassoc->miniicon;
211       }
212 
213     // Create item
214     if(id()) icon->create();
215 
216     // Add root
217     item=appendItem(NULL,"/",icon,icon);
218 
219     // Add the rest
220     while(end<path.length()){
221 
222       // Begin of path component
223       beg=end;
224 
225       // Find next path separator
226       while(end<path.length() && !ISPATHSEP(path[end])) end++;
227 
228       // Determine associations, icons and type
229       icon=foldericon;
230       if(associations){
231         fileassoc=associations->findDirBinding(path.left(end).text());
232         if(fileassoc && fileassoc->miniicon) icon=fileassoc->miniicon;
233         }
234 
235       // Add next item under last
236       item=appendItem(item,path.mid(beg,end-beg),icon,icon);
237 
238       // Create item
239       if(id()) icon->create();
240 
241       // Skip over path separator
242       if(end<path.length() && ISPATHSEP(path[end])) end++;
243       }
244 
245     // Return leaf item
246     return item;
247     }
248   return NULL;
249   }
250 
251 #else                   // Windows flavor
252 
253 // Return the item from the absolute pathname
getPathnameItem(const FXString & path)254 FXTreeItem* FXDirBox::getPathnameItem(const FXString& path){
255   register FXFileAssoc *fileassoc;
256   register FXTreeItem *item,*it;
257   register FXIcon *icon;
258   register FXint beg=0;
259   register FXint end=0;
260   FXchar drivename[10];
261   FXuint drivemask;
262 
263   // Remove old items first
264   clearItems();
265 
266   // Parse past root
267   if(ISPATHSEP(path[0])){
268     end++;
269     if(ISPATHSEP(path[1])) end++;
270     }
271   else if(isalpha((FXuchar)path[0]) && path[1]==':'){
272     end+=2;
273     if(ISPATHSEP(path[2])) end++;
274     }
275 
276   // Absolute path?
277   if(beg<end){
278 
279     // Add all roots
280     item=NULL;
281     drivemask=GetLogicalDrives();
282     drivename[1]=':';
283     drivename[2]=PATHSEP;
284     drivename[3]='\0';
285 
286     // Loop over drive letters
287     for(drivename[0]='A'; drivename[0]<='Z'; drivename[0]++){
288       if(drivemask&1){
289 
290         // Default icon based on hardware type
291         switch(GetDriveType(drivename)){
292           case DRIVE_REMOVABLE: icon=(drivename[0]<='B') ? floppyicon : zipdiskicon; break;
293           case DRIVE_FIXED: icon=harddiskicon; break;
294           case DRIVE_REMOTE: icon=netdriveicon; break;
295           case DRIVE_CDROM: icon=cdromicon; break;
296           case DRIVE_RAMDISK: icon=harddiskicon; break;
297           case DRIVE_UNKNOWN: icon=foldericon; break;
298           case DRIVE_NO_ROOT_DIR: icon=foldericon; break;
299           default: icon=foldericon; break;
300           }
301 
302         // Maybe override from associations
303         if(associations){
304           fileassoc=associations->findDirBinding(drivename);
305           if(fileassoc && fileassoc->miniicon) icon=fileassoc->miniicon;
306           }
307 
308         // Create item
309         if(id()) icon->create();
310 
311         // Add another root item
312         it=appendItem(NULL,drivename,icon,icon);
313 
314         // Rest of path under this root
315         if(comparecase(path,drivename,end)==0) item=it;
316         }
317       drivemask>>=1;
318       }
319 /*
320     // Network neighborhood
321     icon=nethoodicon;
322 
323     // Maybe override from associations
324     if(associations){
325       fileassoc=associations->findDirBinding("\\\\");
326       if(fileassoc && fileassoc->miniicon) icon=fileassoc->miniicon;
327       }
328 
329     // Create item
330     if(id()) icon->create();
331 
332     // Add netword neighborhood item
333     it=appendItem(NULL,"\\\\",icon,icon);
334 
335     // Rest of path under this root maybe
336     if(comparecase(path,"\\\\",end)==0) item=it;
337 */
338     // Got root?
339     if(item){
340 
341       // Add the rest
342       while(end<path.length()){
343 
344         // Begin of path component
345         beg=end;
346 
347         // Find next path separator
348         while(end<path.length() && !ISPATHSEP(path[end])) end++;
349 
350         // Determine associations, icons and type
351         icon=foldericon;
352         if(associations){
353           fileassoc=associations->findDirBinding(path.left(end).text());
354           if(fileassoc && fileassoc->miniicon) icon=fileassoc->miniicon;
355           }
356 
357         // Create item
358         if(id()) icon->create();
359 
360         // Add next item under last
361         item=appendItem(item,path.mid(beg,end-beg),icon,icon);
362 
363         // Skip over path separator
364         if(end<path.length() && ISPATHSEP(path[end])) end++;
365         }
366 
367       // Return leaf item
368       return item;
369       }
370     }
371   return NULL;
372   }
373 
374 #endif
375 
376 
377 // Forward clicked message from list to target
onTreeClicked(FXObject *,FXSelector,void * ptr)378 long FXDirBox::onTreeClicked(FXObject*,FXSelector,void* ptr){
379   FXString string=getItemPathname((FXTreeItem*)ptr);
380   button->handle(this,FXSEL(SEL_COMMAND,ID_UNPOST),NULL);    // Unpost the list
381   if(ptr){
382     field->setText(tree->getItemText((FXTreeItem*)ptr));
383     field->setIcon(tree->getItemClosedIcon((FXTreeItem*)ptr));
384     removeItem(((FXTreeItem*)ptr)->getFirst());
385     if(target) target->tryHandle(this,FXSEL(SEL_COMMAND,message),(void*)string.text());
386     }
387   return 1;
388   }
389 
390 
391 // Forward changed message from list to target
onTreeChanged(FXObject *,FXSelector,void * ptr)392 long FXDirBox::onTreeChanged(FXObject*,FXSelector,void* ptr){
393   FXString string=getItemPathname((FXTreeItem*)ptr);
394   if(target) target->tryHandle(this,FXSEL(SEL_CHANGED,message),(void*)string.text());
395   return 1;
396   }
397 
398 
399 // Set directory
setDirectory(const FXString & pathname)400 void FXDirBox::setDirectory(const FXString& pathname){
401   setCurrentItem(getPathnameItem(FXFile::absolute(pathname)));
402   }
403 
404 
405 // Return current directory
getDirectory() const406 FXString FXDirBox::getDirectory() const {
407   return getItemPathname(getCurrentItem());
408   }
409 
410 
411 // Change associations table; force regeneration of the items
412 // in the tree list so all the new bindings take effect
setAssociations(FXFileDict * assocs)413 void FXDirBox::setAssociations(FXFileDict* assocs){
414   if(associations!=assocs){
415     associations=assocs;
416     setDirectory(getDirectory());
417     }
418   }
419 
420 
421 // Save object to stream
save(FXStream & store) const422 void FXDirBox::save(FXStream& store) const {
423   FXTreeListBox::save(store);
424   store << associations;
425   store << foldericon;
426   store << cdromicon;
427   store << harddiskicon;
428   store << netdriveicon;
429   store << floppyicon;
430   store << nethoodicon;
431   store << zipdiskicon;
432   }
433 
434 
435 // Load object from stream
load(FXStream & store)436 void FXDirBox::load(FXStream& store){
437   FXTreeListBox::load(store);
438   store >> associations;
439   store >> foldericon;
440   store >> cdromicon;
441   store >> harddiskicon;
442   store >> netdriveicon;
443   store >> floppyicon;
444   store >> nethoodicon;
445   store >> zipdiskicon;
446   }
447 
448 
449 // Delete it
~FXDirBox()450 FXDirBox::~FXDirBox(){
451   clearItems();
452   if(!(options&DIRBOX_NO_OWN_ASSOC)) delete associations;
453   delete foldericon;
454   delete cdromicon;
455   delete harddiskicon;
456   delete netdriveicon;
457   delete floppyicon;
458   delete nethoodicon;
459   delete zipdiskicon;
460   associations=(FXFileDict*)-1L;
461   foldericon=(FXIcon*)-1L;
462   cdromicon=(FXIcon*)-1L;
463   harddiskicon=(FXIcon*)-1L;
464   netdriveicon=(FXIcon*)-1L;
465   floppyicon=(FXIcon*)-1L;
466   nethoodicon=(FXIcon*)-1L;
467   zipdiskicon=(FXIcon*)-1L;
468   }
469 
470 }
471 
472