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