1 /********************************************************************************
2 * *
3 * F i l e L i s t O b j e c t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 1998,2020 by Jeroen van der Zijp. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as published by *
10 * the Free Software Foundation; either version 3 of the License, or *
11 * (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 *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/> *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "fxkeys.h"
26 #include "fxascii.h"
27 #include "fxunicode.h"
28 #include "FXArray.h"
29 #include "FXHash.h"
30 #include "FXMutex.h"
31 #include "FXStream.h"
32 #include "FXObjectList.h"
33 #include "FXString.h"
34 #include "FXSize.h"
35 #include "FXPoint.h"
36 #include "FXRectangle.h"
37 #include "FXSystem.h"
38 #include "FXPath.h"
39 #include "FXStat.h"
40 #include "FXFile.h"
41 #include "FXDir.h"
42 #include "FXURL.h"
43 #include "FXStringDictionary.h"
44 #include "FXSettings.h"
45 #include "FXRegistry.h"
46 #include "FXFont.h"
47 #include "FXEvent.h"
48 #include "FXWindow.h"
49 #include "FXApp.h"
50 #include "FXIcon.h"
51 #include "FXGIFIcon.h"
52 #include "FXScrollBar.h"
53 #include "FXIconSource.h"
54 #include "FXShell.h"
55 #include "FXPopup.h"
56 #include "FXMenuPane.h"
57 #include "FXMenuCaption.h"
58 #include "FXMenuCommand.h"
59 #include "FXMenuCascade.h"
60 #include "FXMenuRadio.h"
61 #include "FXMenuCheck.h"
62 #include "FXMenuSeparator.h"
63 #include "FXDictionary.h"
64 #include "FXDictionaryOf.h"
65 #include "FXIconCache.h"
66 #include "FXFileAssociations.h"
67 #include "FXHeader.h"
68 #include "FXIconList.h"
69 #include "FXFileList.h"
70 #include "FXFileProgressDialog.h"
71 #include "FXMessageBox.h"
72 #include "icons.h"
73
74 /*
75 Notes:
76 - Share icons with other widgets; upgrade icons to some nicer ones.
77 - Should some of these icons move to FXFileAssociations?
78 - Clipboard of filenames.
79 - Clipboard, DND, etc. support.
80 - When being dragged over, if hovering over a directory item for some
81 time we need to open it.
82 - We should generate SEL_INSERTED, SEL_DELETED, SEL_CHANGED
83 messages as the FXFileList updates itself from the file system.
84 - The solution currently used to determine whether or not to blend the
85 icon isn't so great; this class shouldn't have to know about FXPNGIcon.
86 - If you land in a large directory with images, things are a tad slow;
87 need to speed this up some how.
88 */
89
90
91 #define OPENDIRDELAY 700000000 // Delay before opening directory
92 #define REFRESHINTERVAL 1000000000 // Interval between refreshes
93 #define REFRESHCOUNT 30 // Refresh every REFRESHCOUNT-th time
94
95 using namespace FX;
96
97 /*******************************************************************************/
98
99 namespace FX {
100
101
102 // Object implementation
103 FXIMPLEMENT(FXFileItem,FXIconItem,NULL,0)
104
105
106 // Map
107 FXDEFMAP(FXFileList) FXFileListMap[]={
108 FXMAPFUNC(SEL_DND_ENTER,0,FXFileList::onDNDEnter),
109 FXMAPFUNC(SEL_DND_LEAVE,0,FXFileList::onDNDLeave),
110 FXMAPFUNC(SEL_DND_DROP,0,FXFileList::onDNDDrop),
111 FXMAPFUNC(SEL_DND_MOTION,0,FXFileList::onDNDMotion),
112 FXMAPFUNC(SEL_DND_REQUEST,0,FXFileList::onDNDRequest),
113 FXMAPFUNC(SEL_BEGINDRAG,0,FXFileList::onBeginDrag),
114 FXMAPFUNC(SEL_DRAGGED,0,FXFileList::onDragged),
115 FXMAPFUNC(SEL_ENDDRAG,0,FXFileList::onEndDrag),
116 FXMAPFUNC(SEL_CLIPBOARD_LOST,0,FXFileList::onClipboardLost),
117 FXMAPFUNC(SEL_CLIPBOARD_REQUEST,0,FXFileList::onClipboardRequest),
118 FXMAPFUNC(SEL_CHORE,FXFileList::ID_PREVIEWCHORE,FXFileList::onPreviewChore),
119 FXMAPFUNC(SEL_TIMEOUT,FXFileList::ID_OPENTIMER,FXFileList::onOpenTimer),
120 FXMAPFUNC(SEL_TIMEOUT,FXFileList::ID_REFRESHTIMER,FXFileList::onRefreshTimer),
121 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_DIRECTORY_UP,FXFileList::onUpdDirectoryUp),
122 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_SORT_BY_NAME,FXFileList::onUpdSortByName),
123 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_SORT_BY_TYPE,FXFileList::onUpdSortByType),
124 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_SORT_BY_SIZE,FXFileList::onUpdSortBySize),
125 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_SORT_BY_TIME,FXFileList::onUpdSortByTime),
126 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_SORT_BY_USER,FXFileList::onUpdSortByUser),
127 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_SORT_BY_GROUP,FXFileList::onUpdSortByGroup),
128 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_SORT_REVERSE,FXFileList::onUpdSortReverse),
129 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_SORT_CASE,FXFileList::onUpdSortCase),
130 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_SET_PATTERN,FXFileList::onUpdSetPattern),
131 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_SET_DIRECTORY,FXFileList::onUpdSetDirectory),
132 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_SHOW_HIDDEN,FXFileList::onUpdShowHidden),
133 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_HIDE_HIDDEN,FXFileList::onUpdHideHidden),
134 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_TOGGLE_HIDDEN,FXFileList::onUpdToggleHidden),
135 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_TOGGLE_IMAGES,FXFileList::onUpdToggleImages),
136 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_HEADER,FXFileList::onUpdHeader),
137 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_CUT_SEL,FXFileList::onUpdHaveSel),
138 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_COPY_SEL,FXFileList::onUpdHaveSel),
139 FXMAPFUNC(SEL_UPDATE,FXFileList::ID_DELETE_SEL,FXFileList::onUpdHaveSel),
140 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_HEADER,FXFileList::onCmdHeader),
141 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_DIRECTORY_UP,FXFileList::onCmdDirectoryUp),
142 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SORT_BY_NAME,FXFileList::onCmdSortByName),
143 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SORT_BY_TYPE,FXFileList::onCmdSortByType),
144 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SORT_BY_SIZE,FXFileList::onCmdSortBySize),
145 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SORT_BY_TIME,FXFileList::onCmdSortByTime),
146 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SORT_BY_USER,FXFileList::onCmdSortByUser),
147 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SORT_BY_GROUP,FXFileList::onCmdSortByGroup),
148 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SORT_REVERSE,FXFileList::onCmdSortReverse),
149 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SORT_CASE,FXFileList::onCmdSortCase),
150 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SET_PATTERN,FXFileList::onCmdSetPattern),
151 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SET_DIRECTORY,FXFileList::onCmdSetDirectory),
152 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SETVALUE,FXFileList::onCmdSetValue),
153 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SETSTRINGVALUE,FXFileList::onCmdSetStringValue),
154 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_GETSTRINGVALUE,FXFileList::onCmdGetStringValue),
155 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_SHOW_HIDDEN,FXFileList::onCmdShowHidden),
156 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_HIDE_HIDDEN,FXFileList::onCmdHideHidden),
157 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_TOGGLE_HIDDEN,FXFileList::onCmdToggleHidden),
158 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_TOGGLE_IMAGES,FXFileList::onCmdToggleImages),
159 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_REFRESH,FXFileList::onCmdRefresh),
160 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_CUT_SEL,FXFileList::onCmdCutSel),
161 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_COPY_SEL,FXFileList::onCmdCopySel),
162 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_DELETE_SEL,FXFileList::onCmdDeleteSel),
163 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_PASTE_SEL,FXFileList::onCmdPasteSel),
164 FXMAPFUNC(SEL_CHORE,FXFileList::ID_DROPASK,FXFileList::onCmdDropAsk),
165 FXMAPFUNC(SEL_CHORE,FXFileList::ID_DROPCOPY,FXFileList::onCmdDropCopy),
166 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_DROPCOPY,FXFileList::onCmdDropCopy),
167 FXMAPFUNC(SEL_CHORE,FXFileList::ID_DROPMOVE,FXFileList::onCmdDropMove),
168 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_DROPMOVE,FXFileList::onCmdDropMove),
169 FXMAPFUNC(SEL_CHORE,FXFileList::ID_DROPLINK,FXFileList::onCmdDropLink),
170 FXMAPFUNC(SEL_COMMAND,FXFileList::ID_DROPLINK,FXFileList::onCmdDropLink),
171 };
172
173
174 // Object implementation
FXIMPLEMENT(FXFileList,FXIconList,FXFileListMap,ARRAYNUMBER (FXFileListMap))175 FXIMPLEMENT(FXFileList,FXIconList,FXFileListMap,ARRAYNUMBER(FXFileListMap))
176
177
178 // For serialization
179 FXFileList::FXFileList(){
180 dropEnable();
181 associations=NULL;
182 iconloader=NULL;
183 list=NULL;
184 big_folder=NULL;
185 mini_folder=NULL;
186 big_doc=NULL;
187 mini_doc=NULL;
188 big_app=NULL;
189 mini_app=NULL;
190 #ifdef WIN32
191 matchmode=FXPath::PathName|FXPath::NoEscape|FXPath::CaseFold;
192 setSortFunc(ascendingCase);
193 #else
194 matchmode=FXPath::PathName|FXPath::NoEscape;
195 setSortFunc(ascending);
196 #endif
197 dropaction=DRAG_COPY;
198 matchmode=0;
199 imagesize=32;
200 timestamp=0;
201 counter=0;
202 clipcut=false;
203 draggable=true;
204 }
205
206
207 // File List
FXFileList(FXComposite * p,FXObject * tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h)208 FXFileList::FXFileList(FXComposite *p,FXObject* tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXIconList(p,tgt,sel,opts,x,y,w,h),directory(PATHSEPSTRING),pattern("*"){
209 dropEnable();
210 appendHeader(tr("Name\tName"),NULL,200);
211 appendHeader(tr("Type\tFile type"),NULL,100);
212 appendHeader(tr("Size\tFile size"),NULL,60);
213 appendHeader(tr("Modified Date\tDate when last modified"),NULL,150);
214 appendHeader(tr("User\tUser name"),NULL,50);
215 appendHeader(tr("Group\tGroup name"),NULL,50);
216 appendHeader(tr("Attributes\tFile attributes"),NULL,100);
217 #ifndef WIN32
218 appendHeader(tr("Link\tSymbolic link to"),NULL,200);
219 #endif
220 associations=NULL;
221 if(!(options&FILELIST_NO_OWN_ASSOC)) associations=new FXFileAssociations(getApp());
222 iconloader=&FXIconSource::defaultIconSource;
223 list=NULL;
224 big_folder=new FXGIFIcon(getApp(),bigfolder);
225 mini_folder=new FXGIFIcon(getApp(),minifolder);
226 big_doc=new FXGIFIcon(getApp(),bigdoc);
227 mini_doc=new FXGIFIcon(getApp(),minidoc);
228 big_app=new FXGIFIcon(getApp(),bigapp);
229 mini_app=new FXGIFIcon(getApp(),miniapp);
230 timeformat=tr(FXSystem::defaultTimeFormat);
231 dropaction=DRAG_COPY;
232 #ifdef WIN32
233 matchmode=FXPath::PathName|FXPath::NoEscape|FXPath::CaseFold;
234 setSortFunc(ascendingCase);
235 #else
236 matchmode=FXPath::PathName|FXPath::NoEscape;
237 setSortFunc(ascending);
238 #endif
239 imagesize=32;
240 timestamp=0;
241 counter=0;
242 clipcut=false;
243 draggable=true;
244 }
245
246
247 // Starts the timer
create()248 void FXFileList::create(){
249 FXIconList::create();
250 getApp()->addTimeout(this,ID_REFRESHTIMER,REFRESHINTERVAL);
251 big_folder->create();
252 mini_folder->create();
253 big_doc->create();
254 mini_doc->create();
255 big_app->create();
256 mini_app->create();
257 }
258
259
260 // Detach disconnects the icons
detach()261 void FXFileList::detach(){
262 FXIconList::detach();
263 getApp()->removeTimeout(this,ID_REFRESHTIMER);
264 getApp()->removeTimeout(this,ID_OPENTIMER);
265 big_folder->detach();
266 mini_folder->detach();
267 big_doc->detach();
268 mini_doc->detach();
269 big_app->detach();
270 mini_app->detach();
271 deleteType=0;
272 urilistType=0;
273 actionType=0;
274 }
275
276
277 // Destroy zaps the icons
destroy()278 void FXFileList::destroy(){
279 FXIconList::destroy();
280 getApp()->removeTimeout(this,ID_REFRESHTIMER);
281 getApp()->removeTimeout(this,ID_OPENTIMER);
282 big_folder->destroy();
283 mini_folder->destroy();
284 big_doc->destroy();
285 mini_doc->destroy();
286 big_app->destroy();
287 mini_app->destroy();
288 }
289
290
291 // Create custom item
createItem(const FXString & text,FXIcon * big,FXIcon * mini,void * ptr)292 FXIconItem *FXFileList::createItem(const FXString& text,FXIcon *big,FXIcon* mini,void* ptr){
293 return new FXFileItem(text,big,mini,ptr);
294 }
295
296 /*******************************************************************************/
297
298
299 // Compare file names
ascending(const FXIconItem * a,const FXIconItem * b)300 FXint FXFileList::ascending(const FXIconItem* a,const FXIconItem* b){
301 FXint diff=static_cast<const FXFileItem*>(b)->isDirectory() - static_cast<const FXFileItem*>(a)->isDirectory();
302 if(diff==0){
303 diff=compareSection(a->label.text(),b->label.text(),0);
304 }
305 return diff;
306 }
307
308
309 // Reversed compare file name
descending(const FXIconItem * a,const FXIconItem * b)310 FXint FXFileList::descending(const FXIconItem* a,const FXIconItem* b){
311 FXint diff=static_cast<const FXFileItem*>(b)->isDirectory() - static_cast<const FXFileItem*>(a)->isDirectory();
312 if(diff==0){
313 diff=compareSection(b->label.text(),a->label.text(),0);
314 }
315 return diff;
316 }
317
318
319 // Compare file names, case insensitive
ascendingCase(const FXIconItem * a,const FXIconItem * b)320 FXint FXFileList::ascendingCase(const FXIconItem* a,const FXIconItem* b){
321 FXint diff=static_cast<const FXFileItem*>(b)->isDirectory() - static_cast<const FXFileItem*>(a)->isDirectory();
322 if(diff==0){
323 diff=compareSectionCase(a->label.text(),b->label.text(),0);
324 }
325 return diff;
326 }
327
328
329 // Reversed compare file name, case insensitive
descendingCase(const FXIconItem * a,const FXIconItem * b)330 FXint FXFileList::descendingCase(const FXIconItem* a,const FXIconItem* b){
331 FXint diff=static_cast<const FXFileItem*>(b)->isDirectory() - static_cast<const FXFileItem*>(a)->isDirectory();
332 if(diff==0){
333 diff=compareSectionCase(b->label.text(),a->label.text(),0);
334 }
335 return diff;
336 }
337
338
339 // Compare file types
ascendingType(const FXIconItem * a,const FXIconItem * b)340 FXint FXFileList::ascendingType(const FXIconItem* a,const FXIconItem* b){
341 FXint diff=static_cast<const FXFileItem*>(b)->isDirectory() - static_cast<const FXFileItem*>(a)->isDirectory();
342 if(diff==0){
343 diff=compareSection(a->label.text(),b->label.text(),1);
344 if(diff==0){
345 diff=compareSection(a->label.text(),b->label.text(),0);
346 }
347 }
348 return diff;
349 }
350
351
352 // Reversed compare file type
descendingType(const FXIconItem * a,const FXIconItem * b)353 FXint FXFileList::descendingType(const FXIconItem* a,const FXIconItem* b){
354 FXint diff=static_cast<const FXFileItem*>(b)->isDirectory() - static_cast<const FXFileItem*>(a)->isDirectory();
355 if(diff==0){
356 diff=compareSection(b->label.text(),a->label.text(),1);
357 if(diff==0){
358 diff=compareSection(b->label.text(),a->label.text(),0);
359 }
360 }
361 return diff;
362 }
363
364
365 // Compare file size
ascendingSize(const FXIconItem * a,const FXIconItem * b)366 FXint FXFileList::ascendingSize(const FXIconItem* a,const FXIconItem* b){
367 FXint diff=static_cast<const FXFileItem*>(b)->isDirectory() - static_cast<const FXFileItem*>(a)->isDirectory();
368 if(diff==0){
369 diff=FXSGNZ(static_cast<const FXFileItem*>(a)->size - static_cast<const FXFileItem*>(b)->size);
370 if(diff==0){
371 diff=compareSection(a->label.text(),b->label.text(),0);
372 }
373 }
374 return diff;
375 }
376
377
378 // Reversed compare file size
descendingSize(const FXIconItem * a,const FXIconItem * b)379 FXint FXFileList::descendingSize(const FXIconItem* a,const FXIconItem* b){
380 FXint diff=static_cast<const FXFileItem*>(b)->isDirectory() - static_cast<const FXFileItem*>(a)->isDirectory();
381 if(diff==0){
382 diff=FXSGNZ(static_cast<const FXFileItem*>(b)->size - static_cast<const FXFileItem*>(a)->size);
383 if(diff==0){
384 diff=compareSection(b->label.text(),a->label.text(),0);
385 }
386 }
387 return diff;
388 }
389
390
391 // Compare file time
ascendingTime(const FXIconItem * a,const FXIconItem * b)392 FXint FXFileList::ascendingTime(const FXIconItem* a,const FXIconItem* b){
393 FXint diff=(FXint)((FXFileItem*)b)->isDirectory() - (FXint)((FXFileItem*)a)->isDirectory();
394 if(diff==0){
395 diff=FXSGNZ(static_cast<const FXFileItem*>(a)->date - static_cast<const FXFileItem*>(b)->date);
396 if(diff==0){
397 diff=compareSection(a->label.text(),b->label.text(),0);
398 }
399 }
400 return diff;
401 }
402
403
404 // Reversed compare file time
descendingTime(const FXIconItem * a,const FXIconItem * b)405 FXint FXFileList::descendingTime(const FXIconItem* a,const FXIconItem* b){
406 FXint diff=(FXint)((FXFileItem*)b)->isDirectory() - (FXint)((FXFileItem*)a)->isDirectory();
407 if(diff==0){
408 diff=FXSGNZ(static_cast<const FXFileItem*>(b)->date - static_cast<const FXFileItem*>(a)->date);
409 if(diff==0){
410 diff=compareSection(b->label.text(),a->label.text(),0);
411 }
412 }
413 return diff;
414 }
415
416
417 // Compare file user
ascendingUser(const FXIconItem * a,const FXIconItem * b)418 FXint FXFileList::ascendingUser(const FXIconItem* a,const FXIconItem* b){
419 FXint diff=static_cast<const FXFileItem*>(b)->isDirectory() - static_cast<const FXFileItem*>(a)->isDirectory();
420 if(diff==0){
421 diff=compareSection(a->label.text(),b->label.text(),4);
422 if(diff==0){
423 diff=compareSection(a->label.text(),b->label.text(),0);
424 }
425 }
426 return diff;
427 }
428
429
430 // Reversed compare file user
descendingUser(const FXIconItem * a,const FXIconItem * b)431 FXint FXFileList::descendingUser(const FXIconItem* a,const FXIconItem* b){
432 FXint diff=static_cast<const FXFileItem*>(b)->isDirectory() - static_cast<const FXFileItem*>(a)->isDirectory();
433 if(diff==0){
434 diff=compareSection(b->label.text(),a->label.text(),4);
435 if(diff==0){
436 diff=compareSection(b->label.text(),a->label.text(),0);
437 }
438 }
439 return diff;
440 }
441
442
443 // Compare file group
ascendingGroup(const FXIconItem * a,const FXIconItem * b)444 FXint FXFileList::ascendingGroup(const FXIconItem* a,const FXIconItem* b){
445 FXint diff=static_cast<const FXFileItem*>(b)->isDirectory() - static_cast<const FXFileItem*>(a)->isDirectory();
446 if(diff==0){
447 diff=compareSection(a->label.text(),b->label.text(),5);
448 if(diff==0){
449 diff=compareSection(a->label.text(),b->label.text(),0);
450 }
451 }
452 return diff;
453 }
454
455
456 // Reversed compare file group
descendingGroup(const FXIconItem * a,const FXIconItem * b)457 FXint FXFileList::descendingGroup(const FXIconItem* a,const FXIconItem* b){
458 FXint diff=static_cast<const FXFileItem*>(b)->isDirectory() - static_cast<const FXFileItem*>(a)->isDirectory();
459 if(diff==0){
460 diff=compareSection(b->label.text(),a->label.text(),5);
461 if(diff==0){
462 diff=compareSection(b->label.text(),a->label.text(),0);
463 }
464 }
465 return diff;
466 }
467
468 /*******************************************************************************/
469
470 // Return uri-list of selected files
getSelectedFiles() const471 FXString FXFileList::getSelectedFiles() const {
472 FXString result;
473 for(FXint i=0; i<getNumItems(); i++){
474 if(isItemSelected(i) && !isItemNavigational(i)){
475 result.append(FXURL::fileToURL(getItemPathname(i)));
476 result.append("\r\n");
477 }
478 }
479 return result;
480 }
481
482
483 // Update if we have selection
onUpdHaveSel(FXObject * sender,FXSelector,void *)484 long FXFileList::onUpdHaveSel(FXObject* sender,FXSelector,void*){
485 for(FXint i=0; i<getNumItems(); i++){
486 if(isItemSelected(i) && !isItemNavigational(i)){
487 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
488 return 1;
489 }
490 }
491 sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
492 return 1;
493 }
494
495 /*******************************************************************************/
496
497 // Delete selection
onCmdDeleteSel(FXObject *,FXSelector,void *)498 long FXFileList::onCmdDeleteSel(FXObject*,FXSelector,void*){
499 FXString delfiles=getSelectedFiles();
500 delete_files(delfiles); // FIXME confirmation would be nice
501 return 1;
502 }
503
504
505 // Paste clipboard
onCmdPasteSel(FXObject *,FXSelector,void *)506 long FXFileList::onCmdPasteSel(FXObject*,FXSelector,void*){
507 FXString files,action;
508 if(getDNDData(FROM_CLIPBOARD,urilistType,files)){
509 if(getDNDData(FROM_CLIPBOARD,actionType,action)){
510 FXTRACE((100,"%s::onCmdPasteSel(): Action: %s Files: %s\n",getClassName(),action.text(),files.text()));
511 if(action[0]=='1'){
512 move_files(directory,files);
513 }
514 else{
515 // FXint count=files.contains("\r\n");
516 // FXTRACE((1,"number of files=%d\n",count));
517 //FXFileProgressDialog fileprogress(this,"Copying Files","Copying 10 files (100MB)",big_folder,DECOR_TITLE|DECOR_BORDER|DECOR_RESIZE,0,0,600,0);
518 //fileprogress.execute();
519 copy_files(directory,files);
520 }
521 return 1;
522 }
523 }
524 getApp()->beep();
525 return 1;
526 }
527
528
529 // Cut
onCmdCutSel(FXObject *,FXSelector,void *)530 long FXFileList::onCmdCutSel(FXObject*,FXSelector,void*){
531 FXDragType types[2]={urilistType,actionType};
532 if(acquireClipboard(types,ARRAYNUMBER(types))){
533 clipfiles=getSelectedFiles();
534 clipcut=true;
535 }
536 return 1;
537 }
538
539
540 // Copy
onCmdCopySel(FXObject *,FXSelector,void *)541 long FXFileList::onCmdCopySel(FXObject*,FXSelector,void*){
542 FXDragType types[2]={urilistType,actionType};
543 if(acquireClipboard(types,ARRAYNUMBER(types))){
544 clipfiles=getSelectedFiles();
545 clipcut=false;
546 }
547 return 1;
548 }
549
550
551 // We lost the selection somehow
onClipboardLost(FXObject * sender,FXSelector sel,void * ptr)552 long FXFileList::onClipboardLost(FXObject* sender,FXSelector sel,void* ptr){
553 FXIconList::onClipboardLost(sender,sel,ptr);
554 FXTRACE((100,"deleting clipfiles\n"));
555 clipfiles=FXString::null;
556 clipcut=false;
557 return 1;
558 }
559
560
561 // Somebody wants our selection
onClipboardRequest(FXObject * sender,FXSelector sel,void * ptr)562 long FXFileList::onClipboardRequest(FXObject* sender,FXSelector sel,void* ptr){
563
564 // Try base class first
565 if(FXIconList::onClipboardRequest(sender,sel,ptr)) return 1;
566
567 // Return list of filenames as a uri-list
568 if(((FXEvent*)ptr)->target==urilistType){
569 FXTRACE((100,"Returning urilistType\n"));
570 setDNDData(FROM_CLIPBOARD,urilistType,clipfiles);
571 return 1;
572 }
573
574 // Return type of clipboard action
575 if(((FXEvent*)ptr)->target==actionType){
576 FXTRACE((100,"Returning actionType\n"));
577 setDNDData(FROM_CLIPBOARD,actionType,clipcut?"1":"0");
578 return 1;
579 }
580
581 return 0;
582 }
583
584 /*******************************************************************************/
585
586
587 // Delete files from the systems
delete_files(const FXString & files)588 void FXFileList::delete_files(const FXString& files){
589 FXString filename;
590 FXint beg,end;
591 for(beg=0; beg<files.length(); beg=end+2){
592 if((end=files.find_first_of("\r\n",beg))<0) end=files.length();
593 filename=FXURL::fileFromURL(files.mid(beg,end-beg));
594 if(!FXFile::removeFiles(filename,true)){
595 if(FXMessageBox::question(this,MBOX_OK_CANCEL,tr("Failed Deleting Files"),tr("Failed to delete file: %s; continue?"),filename.text())==MBOX_CLICKED_CANCEL) break;
596 }
597 }
598 }
599
600
601 // Copy files to directory
copy_files(const FXString & dir,const FXString & files)602 void FXFileList::copy_files(const FXString& dir,const FXString& files){
603 FXString filedst,filesrc;
604 FXuint answer=0;
605 FXint beg,end;
606 FXbool ok;
607 for(beg=0; beg<files.length(); beg=end+2){
608 if((end=files.find_first_of("\r\n",beg))<0) end=files.length();
609 filesrc=FXURL::fileFromURL(files.mid(beg,end-beg));
610 filedst=FXPath::absolute(dir,FXPath::name(filesrc));
611 ok=FXFile::copyFiles(filesrc,filedst,(answer==MBOX_CLICKED_YESALL));
612 if(!ok){
613 if(answer==MBOX_CLICKED_NOALL) continue;
614 if(answer!=MBOX_CLICKED_YESALL){
615 answer=FXMessageBox::question(this,MBOX_YES_YESALL_NO_NOALL_CANCEL,tr("Overwrite File"),tr("Overwrite existing file or directory: %s?"),filedst.text());
616 if(answer==MBOX_CLICKED_CANCEL) break;
617 if(answer==MBOX_CLICKED_NO) continue;
618 if(answer==MBOX_CLICKED_NOALL) continue;
619 ok=FXFile::copyFiles(filesrc,filedst,true);
620 }
621 if(!ok){
622 if(FXMessageBox::question(this,MBOX_OK_CANCEL,tr("Failed Copying File"),tr("Failed to overwrite file: %s; continue?"),filedst.text())==MBOX_CLICKED_OK) continue;
623 break;
624 }
625 }
626 }
627 }
628
629
630 // Move files to directory
move_files(const FXString & dir,const FXString & files)631 void FXFileList::move_files(const FXString& dir,const FXString& files){
632 FXString filedst,filesrc;
633 FXuint answer=0;
634 FXint beg,end;
635 FXbool ok;
636 for(beg=0; beg<files.length(); beg=end+2){
637 if((end=files.find_first_of("\r\n",beg))<0) end=files.length();
638 filesrc=FXURL::fileFromURL(files.mid(beg,end-beg));
639 filedst=FXPath::absolute(dir,FXPath::name(filesrc));
640 ok=FXFile::moveFiles(filesrc,filedst,(answer==MBOX_CLICKED_YESALL));
641 if(!ok){
642 if(answer==MBOX_CLICKED_NOALL) continue;
643 if(answer!=MBOX_CLICKED_YESALL){
644 answer=FXMessageBox::question(this,MBOX_YES_YESALL_NO_NOALL_CANCEL,tr("Overwrite File"),tr("Overwrite existing file or directory: %s?"),filedst.text());
645 if(answer==MBOX_CLICKED_CANCEL) break;
646 if(answer==MBOX_CLICKED_NO) continue;
647 if(answer==MBOX_CLICKED_NOALL) continue;
648 ok=FXFile::moveFiles(filesrc,filedst,true);
649 }
650 if(!ok){
651 if(FXMessageBox::question(this,MBOX_OK_CANCEL,tr("Failed Moving File"),tr("Failed to overwrite file: %s; continue?"),filedst.text())==MBOX_CLICKED_OK) continue;
652 break;
653 }
654 }
655 }
656 }
657
658 #if 0
659 FXProgressDialog progress(this,tr("Copying Files"),FXString::null,PROGRESSDIALOG_NORMAL|PROGRESSDIALOG_CANCEL,0,0,520,0);
660 FXuint ans=MBOX_CLICKED_NO;
661 FXString filedst,filesrc;
662 FXint beg,end,ok;
663 progress.create();
664 progress.show(PLACEMENT_CURSOR);
665 progress.setTotal(dropfiles.contains("\r\n"));
666 progress.setProgress(0);
667 getApp()->flush();
668 getApp()->runModalWhileEvents(&progress,500000000);
669 getApp()->flush();
670 for(beg=0; beg<files.length(); beg=end+2){
671 if(progress.isCancelled()) break;
672 if((end=files.find_first_of("\r\n",beg))<0) end=files.length();
673 filesrc=FXURL::fileFromURL(files.mid(beg,end-beg));
674 filedst=FXPath::absolute(directory,FXPath::name(filesrc));
675 progress.setMessage(tr("Copying file:\n\n")+filesrc);
676 progress.increment(1);
677 getApp()->flush();
678 getApp()->runModalWhileEvents(&progress,500000000);
679 FXThread::sleep(100000000);
680 // FXFile::copyFiles(filesrc,filedst,false);
681 /*
682 ok=FXFile::copyFiles(filesrc,filedst,(ans==MBOX_CLICKED_YESALL));
683 if(!ok && (ans!=MBOX_CLICKED_NOALL)){
684 if(ans!=MBOX_CLICKED_YESALL && ans!=MBOX_CLICKED_NOALL){
685 ans=FXMessageBox::question(this,MBOX_YES_YESALL_NO_NOALL_CANCEL,tr("Overwrite File"),tr("Overwrite existing file or directory: %s?"),filedst.text());
686 if(ans==MBOX_CLICKED_CANCEL) break;
687 if((ans==MBOX_CLICKED_YESALL) || (ans==MBOX_CLICKED_YES)){
688 ok=FXFile::copyFiles(filesrc,filedst,true);
689 }
690 }
691 }
692 */
693 }
694 #endif
695
696 /*******************************************************************************/
697
698 // Copy files to drop directory
onCmdDropCopy(FXObject *,FXSelector,void *)699 long FXFileList::onCmdDropCopy(FXObject*,FXSelector,void*){
700 copy_files(dropdirectory,dropfiles);
701 dropdirectory=FXString::null;
702 dropfiles=FXString::null;
703 dropaction=DRAG_REJECT;
704 return 1;
705 }
706
707
708 // Move files to drop directory
onCmdDropMove(FXObject *,FXSelector,void *)709 long FXFileList::onCmdDropMove(FXObject*,FXSelector,void*){
710 move_files(dropdirectory,dropfiles);
711 dropdirectory=FXString::null;
712 dropfiles=FXString::null;
713 dropaction=DRAG_REJECT;
714 return 1;
715 }
716
717
718 // Link to files from dropdirectory
onCmdDropLink(FXObject *,FXSelector,void *)719 long FXFileList::onCmdDropLink(FXObject*,FXSelector,void*){
720 FXString filedst,filesrc; FXint beg,end;
721 for(beg=0; beg<dropfiles.length(); beg=end+2){
722 if((end=dropfiles.find_first_of("\r\n",beg))<0) end=dropfiles.length();
723 filesrc=FXURL::fileFromURL(dropfiles.mid(beg,end-beg));
724 filedst=FXPath::absolute(dropdirectory,FXPath::name(filesrc));
725 if(!FXFile::symlink(filesrc,filedst)){
726 if(FXMessageBox::question(this,MBOX_OK_CANCEL,tr("Failed Linking File"),tr("Failed to make symbolic link from: %s; continue?"),filedst.text())==MBOX_CLICKED_CANCEL) break;
727 }
728 }
729 dropdirectory=FXString::null;
730 dropfiles=FXString::null;
731 dropaction=DRAG_REJECT;
732 return 1;
733 }
734
735
736 // Deal with the drop that has just occurred
onCmdDropAsk(FXObject *,FXSelector,void * ptr)737 long FXFileList::onCmdDropAsk(FXObject*,FXSelector,void* ptr){
738 FXMenuPane dropmenu(this);
739 FXGIFIcon filemoveicon(getApp(),filemove);
740 FXGIFIcon filecopyicon(getApp(),filecopy);
741 FXGIFIcon filelinkicon(getApp(),filelink);
742 FXGIFIcon filecancelicon(getApp(),filecancel);
743 new FXMenuCommand(&dropmenu,tr("Move Here"),&filemoveicon,this,ID_DROPMOVE);
744 new FXMenuCommand(&dropmenu,tr("Copy Here"),&filecopyicon,this,ID_DROPCOPY);
745 new FXMenuCommand(&dropmenu,tr("Link Here"),&filelinkicon,this,ID_DROPLINK);
746 new FXMenuSeparator(&dropmenu);
747 new FXMenuCommand(&dropmenu,tr("Cancel"),&filecancelicon);
748 dropmenu.create();
749 dropmenu.popup(NULL,((FXEvent*)ptr)->root_x,((FXEvent*)ptr)->root_y);
750 getApp()->runModalWhileShown(&dropmenu);
751 dropdirectory=FXString::null;
752 dropfiles=FXString::null;
753 dropaction=DRAG_REJECT;
754 return 1;
755 }
756
757 /*******************************************************************************/
758
759 // Change directory when hovering over a folder
760 // Remember current directory prior to change
onOpenTimer(FXObject *,FXSelector,void *)761 long FXFileList::onOpenTimer(FXObject*,FXSelector,void*){
762 FXint xx,yy,index; FXuint buttons;
763 getCursorPosition(xx,yy,buttons);
764 index=getItemAt(xx,yy);
765 if(0<=index && isItemDirectory(index)){
766 if(startdirectory.empty()){ startdirectory=getDirectory(); }
767 dropdirectory=getItemPathname(index);
768 setDirectory(dropdirectory,true);
769 }
770 return 1;
771 }
772
773
774 // Handle drag-and-drop enter, remember current directory
onDNDEnter(FXObject * sender,FXSelector sel,void * ptr)775 long FXFileList::onDNDEnter(FXObject* sender,FXSelector sel,void* ptr){
776 FXIconList::onDNDEnter(sender,sel,ptr);
777 return 1;
778 }
779
780
781 // Handle drag-and-drop leave
782 // Restore current directory and scroll position prior drag
onDNDLeave(FXObject * sender,FXSelector sel,void * ptr)783 long FXFileList::onDNDLeave(FXObject* sender,FXSelector sel,void* ptr){
784 FXIconList::onDNDLeave(sender,sel,ptr);
785 getApp()->removeTimeout(this,ID_OPENTIMER);
786 stopAutoScroll();
787 if(!startdirectory.empty()){
788 setDirectory(startdirectory,true);
789 startdirectory=FXString::null;
790 }
791 dropdirectory=FXString::null;
792 dropfiles=FXString::null;
793 dropaction=DRAG_REJECT;
794 return 1;
795 }
796
797
798 // Handle drag-and-drop motion
onDNDMotion(FXObject * sender,FXSelector sel,void * ptr)799 long FXFileList::onDNDMotion(FXObject* sender,FXSelector sel,void* ptr){
800 FXEvent *event=(FXEvent*)ptr;
801 FXint index=-1;
802
803 // Cancel open up timer
804 getApp()->removeTimeout(this,ID_OPENTIMER);
805
806 // Start autoscrolling
807 if(startAutoScroll(event,false)) return 1;
808
809 // Give base class a shot
810 if(FXIconList::onDNDMotion(sender,sel,ptr)) return 1;
811
812 // Dropping list of filenames
813 if(offeredDNDType(FROM_DRAGNDROP,urilistType)){
814
815 // Drop in the background
816 dropdirectory=getDirectory();
817
818 // Drop action to be performed
819 dropaction=inquireDNDAction();
820
821 // We will open up a folder if we can hover over it for a while
822 index=getItemAt(event->win_x,event->win_y);
823 if(0<=index && isItemDirectory(index)){
824
825 // Start open up timer when hovering over item
826 getApp()->addTimeout(this,ID_OPENTIMER,OPENDIRDELAY);
827
828 // Directory where to drop, or directory to open up
829 dropdirectory=getItemPathname(index);
830 }
831
832 // See if dropdirectory is writable
833 if(FXStat::isAccessible(dropdirectory,FXIO::ReadOnly|FXIO::WriteOnly)){
834 acceptDrop(DRAG_ACCEPT);
835 }
836 return 1;
837 }
838 return 0;
839 }
840
841
842 // Handle drag-and-drop drop
onDNDDrop(FXObject * sender,FXSelector sel,void * ptr)843 long FXFileList::onDNDDrop(FXObject* sender,FXSelector sel,void* ptr){
844
845 // Cancel open up timer
846 getApp()->removeTimeout(this,ID_OPENTIMER);
847
848 // Stop scrolling
849 stopAutoScroll();
850
851 // Restore start directory and scroll position
852 if(!startdirectory.empty()){
853 setDirectory(startdirectory,true);
854 startdirectory=FXString::null;
855 }
856
857 // Perhaps target wants to deal with it
858 if(FXIconList::onDNDDrop(sender,sel,ptr)) return 1;
859
860 // Get list of files as uri-list
861 if(getDNDData(FROM_DRAGNDROP,urilistType,dropfiles)){
862 if(!dropfiles.empty()){
863 switch(dropaction){
864 case DRAG_COPY:
865 getApp()->addChore(this,ID_DROPCOPY,ptr);
866 break;
867 case DRAG_MOVE:
868 getApp()->addChore(this,ID_DROPMOVE,ptr);
869 break;
870 case DRAG_LINK:
871 getApp()->addChore(this,ID_DROPLINK,ptr);
872 break;
873 default:
874 getApp()->addChore(this,ID_DROPASK,ptr);
875 break;
876 }
877 return 1;
878 }
879 }
880 return 0;
881 }
882
883
884 // Somebody wants our dragged data
onDNDRequest(FXObject * sender,FXSelector sel,void * ptr)885 long FXFileList::onDNDRequest(FXObject* sender,FXSelector sel,void* ptr){
886
887 // Perhaps the target wants to supply its own data
888 if(FXIconList::onDNDRequest(sender,sel,ptr)) return 1;
889
890 // Return list of filenames as a uri-list
891 if(((FXEvent*)ptr)->target==urilistType){
892 setDNDData(FROM_DRAGNDROP,urilistType,dragfiles);
893 return 1;
894 }
895
896 // Delete selected files
897 if(((FXEvent*)ptr)->target==deleteType){
898 FXTRACE((100,"Delete files not yet implemented\n"));
899 return 1;
900 }
901
902 return 0;
903 }
904
905
906 // Start a drag operation
onBeginDrag(FXObject * sender,FXSelector sel,void * ptr)907 long FXFileList::onBeginDrag(FXObject* sender,FXSelector sel,void* ptr){
908 if(!FXIconList::onBeginDrag(sender,sel,ptr)){
909 beginDrag(&urilistType,1);
910 dragfiles=getSelectedFiles();
911 }
912 return 1;
913 }
914
915
916 // Dragged stuff around
onDragged(FXObject * sender,FXSelector sel,void * ptr)917 long FXFileList::onDragged(FXObject* sender,FXSelector sel,void* ptr){
918 FXEvent* event=(FXEvent*)ptr;
919 if(!FXIconList::onDragged(sender,sel,ptr)){
920 FXDragAction action=DRAG_ASK;
921 if(event->state&CONTROLMASK) action=DRAG_COPY;
922 if(event->state&SHIFTMASK) action=DRAG_MOVE;
923 if(event->state&ALTMASK) action=DRAG_LINK;
924 handleDrag(event->root_x,event->root_y,action);
925 action=didAccept();
926 switch(action){
927 case DRAG_COPY:
928 setDragCursor(getApp()->getDefaultCursor(DEF_DNDCOPY_CURSOR));
929 break;
930 case DRAG_MOVE:
931 setDragCursor(getApp()->getDefaultCursor(DEF_DNDMOVE_CURSOR));
932 break;
933 case DRAG_LINK:
934 setDragCursor(getApp()->getDefaultCursor(DEF_DNDLINK_CURSOR));
935 break;
936 case DRAG_ASK:
937 setDragCursor(getApp()->getDefaultCursor(DEF_DNDASK_CURSOR));
938 break;
939 default:
940 setDragCursor(getApp()->getDefaultCursor(DEF_DNDSTOP_CURSOR));
941 break;
942 }
943 }
944 return 1;
945 }
946
947
948 // End drag operation
onEndDrag(FXObject * sender,FXSelector sel,void * ptr)949 long FXFileList::onEndDrag(FXObject* sender,FXSelector sel,void* ptr){
950 if(!FXIconList::onEndDrag(sender,sel,ptr)){
951 endDrag((didAccept()!=DRAG_REJECT));
952 setDragCursor(getDefaultCursor());
953 dragfiles=FXString::null;
954 }
955 return 1;
956 }
957
958 /*******************************************************************************/
959
960 // Cycle through items that represent images
onPreviewChore(FXObject *,FXSelector,void * ptr)961 long FXFileList::onPreviewChore(FXObject*,FXSelector,void* ptr){
962 FXint index=(FXint)(FXival)ptr;
963 if(showImages() && iconloader && index<getNumItems()){
964 FXIcon *icon=iconloader->loadScaledIconFile(getApp(),getItemPathname(index),imagesize);;
965 if(icon){
966 icon->create();
967 setItemBigIcon(index,icon,true);
968 setItemMiniIcon(index,icon,false);
969 }
970 if(++index<getNumItems()){
971 getApp()->addChore(this,ID_PREVIEWCHORE,(void*)(FXival)index);
972 }
973 }
974 return 1;
975 }
976
977 /*******************************************************************************/
978
979 // Set value from a message
onCmdSetValue(FXObject *,FXSelector,void * ptr)980 long FXFileList::onCmdSetValue(FXObject*,FXSelector,void* ptr){
981 setCurrentFile((const FXchar*)ptr,true);
982 return 1;
983 }
984
985
986 // Set current directory from dir part of filename
onCmdSetStringValue(FXObject *,FXSelector,void * ptr)987 long FXFileList::onCmdSetStringValue(FXObject*,FXSelector,void* ptr){
988 setCurrentFile(*((FXString*)ptr),true);
989 return 1;
990 }
991
992
993 // Get current file name (NULL if no current file)
onCmdGetStringValue(FXObject *,FXSelector,void * ptr)994 long FXFileList::onCmdGetStringValue(FXObject*,FXSelector,void* ptr){
995 *((FXString*)ptr)=getCurrentFile();
996 return 1;
997 }
998
999
1000 // Toggle hidden files display
onCmdToggleHidden(FXObject *,FXSelector,void *)1001 long FXFileList::onCmdToggleHidden(FXObject*,FXSelector,void*){
1002 showHiddenFiles(!showHiddenFiles(),true);
1003 return 1;
1004 }
1005
1006
1007 // Update toggle hidden files widget
onUpdToggleHidden(FXObject * sender,FXSelector,void *)1008 long FXFileList::onUpdToggleHidden(FXObject* sender,FXSelector,void*){
1009 sender->handle(this,showHiddenFiles()?FXSEL(SEL_COMMAND,ID_CHECK):FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
1010 return 1;
1011 }
1012
1013
1014 // Show hidden files
onCmdShowHidden(FXObject *,FXSelector,void *)1015 long FXFileList::onCmdShowHidden(FXObject*,FXSelector,void*){
1016 showHiddenFiles(true,true);
1017 return 1;
1018 }
1019
1020
1021 // Update show hidden files widget
onUpdShowHidden(FXObject * sender,FXSelector,void *)1022 long FXFileList::onUpdShowHidden(FXObject* sender,FXSelector,void*){
1023 sender->handle(this,showHiddenFiles()?FXSEL(SEL_COMMAND,ID_CHECK):FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
1024 return 1;
1025 }
1026
1027
1028 // Hide hidden files
onCmdHideHidden(FXObject *,FXSelector,void *)1029 long FXFileList::onCmdHideHidden(FXObject*,FXSelector,void*){
1030 showHiddenFiles(false,true);
1031 return 1;
1032 }
1033
1034
1035 // Update hide hidden files widget
onUpdHideHidden(FXObject * sender,FXSelector,void *)1036 long FXFileList::onUpdHideHidden(FXObject* sender,FXSelector,void*){
1037 sender->handle(this,showHiddenFiles()?FXSEL(SEL_COMMAND,ID_UNCHECK):FXSEL(SEL_COMMAND,ID_CHECK),NULL);
1038 return 1;
1039 }
1040
1041
1042 // Toggle image preview
onCmdToggleImages(FXObject *,FXSelector,void *)1043 long FXFileList::onCmdToggleImages(FXObject*,FXSelector,void*){
1044 showImages(!showImages(),true);
1045 return 1;
1046 }
1047
1048
1049 // Update image preview
onUpdToggleImages(FXObject * sender,FXSelector,void *)1050 long FXFileList::onUpdToggleImages(FXObject* sender,FXSelector,void*){
1051 sender->handle(this,showImages()?FXSEL(SEL_COMMAND,ID_CHECK):FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
1052 return 1;
1053 }
1054
1055
1056 // Move up one level
onCmdDirectoryUp(FXObject *,FXSelector,void *)1057 long FXFileList::onCmdDirectoryUp(FXObject*,FXSelector,void*){
1058 setDirectory(FXPath::upLevel(directory),true);
1059 return 1;
1060 }
1061
1062
1063 // Determine if we can still go up more
onUpdDirectoryUp(FXObject * sender,FXSelector,void *)1064 long FXFileList::onUpdDirectoryUp(FXObject* sender,FXSelector,void*){
1065 sender->handle(this,FXPath::isTopDirectory(directory)?FXSEL(SEL_COMMAND,ID_DISABLE):FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
1066 return 1;
1067 }
1068
1069
1070 // Change pattern
onCmdSetPattern(FXObject *,FXSelector,void * ptr)1071 long FXFileList::onCmdSetPattern(FXObject*,FXSelector,void* ptr){
1072 setPattern((const char*)ptr,true);
1073 return 1;
1074 }
1075
1076
1077 // Update pattern
onUpdSetPattern(FXObject * sender,FXSelector,void *)1078 long FXFileList::onUpdSetPattern(FXObject* sender,FXSelector,void*){
1079 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETVALUE),(void*)pattern.text());
1080 return 1;
1081 }
1082
1083
1084 // Change directory
onCmdSetDirectory(FXObject *,FXSelector,void * ptr)1085 long FXFileList::onCmdSetDirectory(FXObject*,FXSelector,void* ptr){
1086 setDirectory((const char*)ptr,true);
1087 return 1;
1088 }
1089
1090
1091 // Update directory
onUpdSetDirectory(FXObject * sender,FXSelector,void *)1092 long FXFileList::onUpdSetDirectory(FXObject* sender,FXSelector,void*){
1093 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETVALUE),(void*)directory.text());
1094 return 1;
1095 }
1096
1097
1098 // Sort by name
onCmdSortByName(FXObject *,FXSelector,void *)1099 long FXFileList::onCmdSortByName(FXObject*,FXSelector,void*){
1100 #ifdef WIN32
1101 if(getSortFunc()==ascending) setSortFunc(descending);
1102 else if(getSortFunc()==ascendingCase) setSortFunc(descendingCase);
1103 else if(getSortFunc()==descending) setSortFunc(ascending);
1104 else setSortFunc(ascendingCase);
1105 #else
1106 if(getSortFunc()==ascending) setSortFunc(descending);
1107 else if(getSortFunc()==ascendingCase) setSortFunc(descendingCase);
1108 else if(getSortFunc()==descending) setSortFunc(ascending);
1109 else setSortFunc(ascending);
1110 #endif
1111 sortItems();
1112 return 1;
1113 }
1114
1115
1116 // Update sender
onUpdSortByName(FXObject * sender,FXSelector,void *)1117 long FXFileList::onUpdSortByName(FXObject* sender,FXSelector,void*){
1118 sender->handle(this,(getSortFunc()==ascending || getSortFunc()==descending || getSortFunc()==ascendingCase || getSortFunc()==descendingCase) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
1119 return 1;
1120 }
1121
1122
1123 // Sort by type
onCmdSortByType(FXObject *,FXSelector,void *)1124 long FXFileList::onCmdSortByType(FXObject*,FXSelector,void*){
1125 setSortFunc((getSortFunc()==ascendingType) ? descendingType : ascendingType);
1126 sortItems();
1127 return 1;
1128 }
1129
1130
1131 // Update sender
onUpdSortByType(FXObject * sender,FXSelector,void *)1132 long FXFileList::onUpdSortByType(FXObject* sender,FXSelector,void*){
1133 sender->handle(this,(getSortFunc()==ascendingType || getSortFunc()==descendingType) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
1134 return 1;
1135 }
1136
1137
1138 // Sort by size
onCmdSortBySize(FXObject *,FXSelector,void *)1139 long FXFileList::onCmdSortBySize(FXObject*,FXSelector,void*){
1140 setSortFunc((getSortFunc()==ascendingSize) ? descendingSize : ascendingSize);
1141 sortItems();
1142 return 1;
1143 }
1144
1145
1146 // Update sender
onUpdSortBySize(FXObject * sender,FXSelector,void *)1147 long FXFileList::onUpdSortBySize(FXObject* sender,FXSelector,void*){
1148 sender->handle(this,(getSortFunc()==ascendingSize || getSortFunc()==descendingSize) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
1149 return 1;
1150 }
1151
1152
1153 // Sort by time
onCmdSortByTime(FXObject *,FXSelector,void *)1154 long FXFileList::onCmdSortByTime(FXObject*,FXSelector,void*){
1155 setSortFunc((getSortFunc()==ascendingTime) ? descendingTime : ascendingTime);
1156 sortItems();
1157 return 1;
1158 }
1159
1160
1161 // Update sender
onUpdSortByTime(FXObject * sender,FXSelector,void *)1162 long FXFileList::onUpdSortByTime(FXObject* sender,FXSelector,void*){
1163 sender->handle(this,(getSortFunc()==ascendingTime || getSortFunc()==descendingTime) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
1164 return 1;
1165 }
1166
1167
1168 // Sort by user
onCmdSortByUser(FXObject *,FXSelector,void *)1169 long FXFileList::onCmdSortByUser(FXObject*,FXSelector,void*){
1170 setSortFunc((getSortFunc()==ascendingUser) ? descendingUser : ascendingUser);
1171 sortItems();
1172 return 1;
1173 }
1174
1175
1176 // Update sender
onUpdSortByUser(FXObject * sender,FXSelector,void *)1177 long FXFileList::onUpdSortByUser(FXObject* sender,FXSelector,void*){
1178 sender->handle(this,(getSortFunc()==ascendingUser || getSortFunc()==descendingUser) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
1179 return 1;
1180 }
1181
1182
1183 // Sort by group
onCmdSortByGroup(FXObject *,FXSelector,void *)1184 long FXFileList::onCmdSortByGroup(FXObject*,FXSelector,void*){
1185 setSortFunc((getSortFunc()==ascendingGroup) ? descendingGroup : ascendingGroup);
1186 sortItems();
1187 return 1;
1188 }
1189
1190
1191 // Update sender
onUpdSortByGroup(FXObject * sender,FXSelector,void *)1192 long FXFileList::onUpdSortByGroup(FXObject* sender,FXSelector,void*){
1193 sender->handle(this,(getSortFunc()==ascendingGroup || getSortFunc()==descendingGroup) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
1194 return 1;
1195 }
1196
1197
1198 // Reverse sort order
onCmdSortReverse(FXObject *,FXSelector,void *)1199 long FXFileList::onCmdSortReverse(FXObject*,FXSelector,void*){
1200 if(getSortFunc()==ascending) setSortFunc(descending);
1201 else if(getSortFunc()==descending) setSortFunc(ascending);
1202 else if(getSortFunc()==ascendingCase) setSortFunc(descendingCase);
1203 else if(getSortFunc()==descendingCase) setSortFunc(ascendingCase);
1204 else if(getSortFunc()==ascendingType) setSortFunc(descendingType);
1205 else if(getSortFunc()==descendingType) setSortFunc(ascendingType);
1206 else if(getSortFunc()==ascendingSize) setSortFunc(descendingSize);
1207 else if(getSortFunc()==descendingSize) setSortFunc(ascendingSize);
1208 else if(getSortFunc()==ascendingTime) setSortFunc(descendingTime);
1209 else if(getSortFunc()==descendingTime) setSortFunc(ascendingTime);
1210 else if(getSortFunc()==ascendingUser) setSortFunc(descendingUser);
1211 else if(getSortFunc()==descendingUser) setSortFunc(ascendingUser);
1212 else if(getSortFunc()==ascendingGroup) setSortFunc(descendingGroup);
1213 else if(getSortFunc()==descendingGroup) setSortFunc(ascendingGroup);
1214 sortItems();
1215 return 1;
1216 }
1217
1218
1219 // Update sender
onUpdSortReverse(FXObject * sender,FXSelector,void *)1220 long FXFileList::onUpdSortReverse(FXObject* sender,FXSelector,void*){
1221 FXSelector selector=FXSEL(SEL_COMMAND,ID_UNCHECK);
1222 if(getSortFunc()==descending) selector=FXSEL(SEL_COMMAND,ID_CHECK);
1223 else if(getSortFunc()==descendingCase) selector=FXSEL(SEL_COMMAND,ID_CHECK);
1224 else if(getSortFunc()==descendingType) selector=FXSEL(SEL_COMMAND,ID_CHECK);
1225 else if(getSortFunc()==descendingSize) selector=FXSEL(SEL_COMMAND,ID_CHECK);
1226 else if(getSortFunc()==descendingTime) selector=FXSEL(SEL_COMMAND,ID_CHECK);
1227 else if(getSortFunc()==descendingUser) selector=FXSEL(SEL_COMMAND,ID_CHECK);
1228 else if(getSortFunc()==descendingGroup) selector=FXSEL(SEL_COMMAND,ID_CHECK);
1229 sender->handle(this,selector,NULL);
1230 return 1;
1231 }
1232
1233
1234 // Toggle case sensitivity
onCmdSortCase(FXObject *,FXSelector,void *)1235 long FXFileList::onCmdSortCase(FXObject*,FXSelector,void*){
1236 if(getSortFunc()==ascending) setSortFunc(ascendingCase);
1237 else if(getSortFunc()==ascendingCase) setSortFunc(ascending);
1238 else if(getSortFunc()==descending) setSortFunc(descendingCase);
1239 else if(getSortFunc()==descendingCase) setSortFunc(descending);
1240 sortItems();
1241 return 1;
1242 }
1243
1244
1245 // Check if case sensitive
onUpdSortCase(FXObject * sender,FXSelector,void *)1246 long FXFileList::onUpdSortCase(FXObject* sender,FXSelector,void*){
1247 sender->handle(this,(getSortFunc()==ascendingCase || getSortFunc()==descendingCase) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
1248 sender->handle(this,(getSortFunc()==ascendingCase || getSortFunc()==ascending || getSortFunc()==descendingCase || getSortFunc()==descending) ? FXSEL(SEL_COMMAND,ID_ENABLE) : FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
1249 return 1;
1250 }
1251
1252
1253 // Clicked header button
onCmdHeader(FXObject *,FXSelector,void * ptr)1254 long FXFileList::onCmdHeader(FXObject*,FXSelector,void* ptr){
1255 if(((FXuint)(FXuval)ptr)<6) handle(this,FXSEL(SEL_COMMAND,(ID_SORT_BY_NAME+(FXuint)(FXuval)ptr)),NULL);
1256 return 1;
1257 }
1258
1259
1260 // Clicked header button
onUpdHeader(FXObject *,FXSelector,void *)1261 long FXFileList::onUpdHeader(FXObject*,FXSelector,void*){
1262 header->setArrowDir(0,(getSortFunc()==ascending || getSortFunc()==ascendingCase) ? FXHeaderItem::ARROW_DOWN : (getSortFunc()==descending || getSortFunc()==descendingCase) ? FXHeaderItem::ARROW_UP : FXHeaderItem::ARROW_NONE); // Name
1263 header->setArrowDir(1,(getSortFunc()==ascendingType) ? FXHeaderItem::ARROW_DOWN : (getSortFunc()==descendingType) ? FXHeaderItem::ARROW_UP : FXHeaderItem::ARROW_NONE); // Type
1264 header->setArrowDir(2,(getSortFunc()==ascendingSize) ? FXHeaderItem::ARROW_DOWN : (getSortFunc()==descendingSize) ? FXHeaderItem::ARROW_UP : FXHeaderItem::ARROW_NONE); // Size
1265 header->setArrowDir(3,(getSortFunc()==ascendingTime) ? FXHeaderItem::ARROW_DOWN : (getSortFunc()==descendingTime) ? FXHeaderItem::ARROW_UP : FXHeaderItem::ARROW_NONE); // Date
1266 header->setArrowDir(4,(getSortFunc()==ascendingUser) ? FXHeaderItem::ARROW_DOWN : (getSortFunc()==descendingUser) ? FXHeaderItem::ARROW_UP : FXHeaderItem::ARROW_NONE); // User
1267 header->setArrowDir(5,(getSortFunc()==ascendingGroup) ? FXHeaderItem::ARROW_DOWN : (getSortFunc()==descendingGroup)? FXHeaderItem::ARROW_UP : FXHeaderItem::ARROW_NONE); // Group
1268 return 1;
1269 }
1270
1271 /*******************************************************************************/
1272
1273 // Periodically check to see if directory was changed, and update the list if it was.
onRefreshTimer(FXObject *,FXSelector,void *)1274 long FXFileList::onRefreshTimer(FXObject*,FXSelector,void*){
1275 if(flags&FLAG_UPDATE){
1276 counter+=1;
1277 if(!listItems((counter==REFRESHCOUNT),true)){
1278 setDirectory(FXPath::validPath(directory),true);
1279 }
1280 }
1281 getApp()->addTimeout(this,ID_REFRESHTIMER,REFRESHINTERVAL);
1282 return 0;
1283 }
1284
1285
1286 // Force an immediate update of the list
onCmdRefresh(FXObject *,FXSelector,void *)1287 long FXFileList::onCmdRefresh(FXObject*,FXSelector,void*){
1288 listItems(true,true);
1289 return 1;
1290 }
1291
1292
1293 // Compare till '\t' or '\0'
fileequal(const FXchar * p1,const FXchar * p2)1294 static FXbool fileequal(const FXchar* p1,const FXchar* p2){
1295 FXint c1,c2;
1296 do{
1297 c1=*p1++;
1298 c2=*p2++;
1299 }
1300 while(c1==c2 && c1!='\0' && c1!='\t');
1301 return (c1=='\0' || c1=='\t') && (c2=='\0' || c2=='\t');
1302 }
1303
1304
1305 // List the items in the directory.
1306 // Regenerate the list if an update is forced or the directory timestamp was changed.
1307 // Add, remove, or update items as needed, generating the proper callbacks.
1308 // In addition, re-sort the items using current sort-function.
1309 // Return false if the directory can not be accessed, true otherwise.
listItems(FXbool force,FXbool notify)1310 FXbool FXFileList::listItems(FXbool force,FXbool notify){
1311 FXStat info;
1312
1313 FXTRACE((100,"%s::listItems(%d,%d)\n",getClassName(),force,notify));
1314
1315 // See if directory still there
1316 if(FXStat::statFile(directory,info)){
1317
1318 // Last modified time of current directory
1319 FXTime time=info.modified();
1320
1321 // Regenerate list if update forced or modified time changed
1322 if(force || time!=timestamp){
1323 FXFileItem *oldlist=list; // Old insert-order list
1324 FXFileItem *newlist=NULL; // New insert-order list
1325 FXFileItem **po=&oldlist; // Head of old list
1326 FXFileItem **pn=&newlist; // Head of new list
1327 FXFileItem *olditem;
1328 FXFileItem *newitem;
1329 FXFileItem *link;
1330 FXString pathname;
1331 FXString extension;
1332 FXString label;
1333 FXString name;
1334 FXString grpid;
1335 FXString usrid;
1336 FXString attrs;
1337 FXString modtm;
1338 FXString lnknm;
1339 FXuint mode;
1340 FXbool istop;
1341 FXDir dir;
1342
1343 // Get directory stream pointer
1344 if(dir.open(directory)){
1345
1346 // Are we at the top directory?
1347 istop=FXPath::isTopDirectory(directory);
1348
1349 // Loop over directory entries
1350 while(dir.next(name)){
1351
1352 // Suppress '.' if not showing navigational items or not at top directory
1353 if(name[0]=='.'){
1354 if(name[1]=='\0'){
1355 if(!istop || (options&FILELIST_NO_PARENT)) continue;
1356 }
1357 else if(name[1]=='.' && name[2]=='\0'){
1358 if(istop || (options&FILELIST_NO_PARENT)) continue;
1359 }
1360 else{
1361 if(!(options&FILELIST_SHOWHIDDEN)) continue;
1362 }
1363 }
1364
1365 // Build full pathname
1366 pathname=directory;
1367 if(!ISPATHSEP(pathname.tail())) pathname+=PATHSEPSTRING;
1368 pathname+=name;
1369
1370 #ifdef WIN32
1371
1372 // Get file/link info
1373 if(!FXStat::statFile(pathname,info)) continue;
1374
1375 mode=info.mode();
1376
1377 // Suppress hidden files or directories
1378 if((mode&FXIO::Hidden) && !(options&FILELIST_SHOWHIDDEN)) continue;
1379 #else
1380
1381 // Get file/link info
1382 if(!FXStat::statLink(pathname,info)) continue;
1383
1384 mode=info.mode();
1385
1386 // If its a link, get file mode from target
1387 if(info.isLink()){
1388 mode=FXStat::mode(pathname) | FXIO::SymLink;
1389 }
1390
1391 #endif
1392
1393 // Skip item if it is a directory and we want only files, if it is a file and we want only directories,
1394 // or if it is a file and it fails to match the wildcard pattern.
1395 if(mode&FXIO::Directory){
1396 if(options&FILELIST_SHOWFILES) continue;
1397 }
1398 else{
1399 if(options&FILELIST_SHOWDIRS) continue;
1400 if(!FXPath::match(name,pattern,matchmode)) continue;
1401 }
1402
1403 // Search for item in old list, unlink from old if found
1404 for(FXFileItem** pp=po; (olditem=*pp)!=NULL; pp=&olditem->link){
1405 if(fileequal(olditem->label.text(),name.text())){
1406 *pp=olditem->link; olditem->link=NULL;
1407 break;
1408 }
1409 }
1410
1411 // Use a new item if forced, if there was no old item, or if the item information was changed
1412 if(force || !olditem || olditem->getDate()!=info.modified() || olditem->getSize()!=info.size() || olditem->getMode()!=mode){
1413
1414 // Make new item
1415 newitem=(FXFileItem*)createItem(FXString::null,NULL,NULL,NULL);
1416
1417 // Obtain user name
1418 usrid=FXSystem::userName(info.user());
1419
1420 // Obtain group name
1421 grpid=FXSystem::groupName(info.group());
1422
1423 // Permissions
1424 attrs=FXSystem::modeString(mode);
1425
1426 // Mod time
1427 modtm=FXSystem::localTime(info.modified(),timeformat.text());
1428
1429 // Link name, if any
1430 lnknm=FXString::null;
1431 if(info.isLink()) lnknm=FXFile::symlink(pathname);
1432
1433 // Update item information
1434 newitem->setDraggable(draggable);
1435 newitem->setSize(info.size());
1436 newitem->setDate(info.modified());
1437 newitem->setMode(mode);
1438 newitem->setAssoc(NULL);
1439
1440 // Determine icons and type
1441 if(newitem->isDirectory()){
1442 extension=tr("Folder");
1443 newitem->setBigIcon(big_folder);
1444 newitem->setMiniIcon(mini_folder);
1445 if(associations) newitem->setAssoc(associations->findDirBinding(pathname));
1446 }
1447 else if(newitem->isExecutable()){
1448 extension=tr("Application");
1449 newitem->setBigIcon(big_app);
1450 newitem->setMiniIcon(mini_app);
1451 if(associations) newitem->setAssoc(associations->findExecBinding(pathname));
1452 }
1453 else{
1454 extension=tr("Document");
1455 newitem->setBigIcon(big_doc);
1456 newitem->setMiniIcon(mini_doc);
1457 if(associations) newitem->setAssoc(associations->findFileBinding(pathname));
1458 }
1459
1460 // If association is found, use it
1461 if(newitem->getAssoc()){
1462 extension=newitem->getAssoc()->extension;
1463 if(newitem->getAssoc()->bigicon) newitem->setBigIcon(newitem->getAssoc()->bigicon);
1464 if(newitem->getAssoc()->miniicon) newitem->setMiniIcon(newitem->getAssoc()->miniicon);
1465 }
1466
1467 // Update item information
1468 label.format("%s\t%s\t%lld\t%s\t%s\t%s\t%s\t%s",name.text(),extension.text(),newitem->size,modtm.text(),usrid.text(),grpid.text(),attrs.text(),lnknm.text());
1469
1470 // New label
1471 newitem->setText(label);
1472
1473 // Create item
1474 if(id()) newitem->create();
1475
1476 // Replace or add item
1477 if(olditem){
1478 setItem(items.find(olditem),newitem,notify);
1479 }
1480 else{
1481 appendItem(newitem,notify);
1482 }
1483 *pn=newitem; pn=&newitem->link;
1484 }
1485
1486 // Keep old item if nothing changed
1487 else{
1488 *pn=olditem; pn=&olditem->link;
1489 }
1490 }
1491
1492 // Show thumbnails
1493 if(showImages()){
1494 getApp()->addChore(this,ID_PREVIEWCHORE,(void*)(FXival)0);
1495 }
1496
1497 // Close directory
1498 dir.close();
1499 }
1500
1501 // Wipe items remaining in list:- they have disappeared!!
1502 for(olditem=oldlist; olditem; olditem=link){
1503 link=olditem->link;
1504 removeItem(items.find(olditem),notify);
1505 }
1506
1507 // Remember new list
1508 list=newlist;
1509
1510 // Update sort order
1511 sortItems();
1512
1513 // Update timestamp
1514 timestamp=time;
1515
1516 // Reset counter
1517 counter=0;
1518 }
1519 return true;
1520 }
1521 return false;
1522 }
1523
1524 /*******************************************************************************/
1525
1526 // Set current file; return true if success
setCurrentFile(const FXString & file,FXbool notify)1527 FXbool FXFileList::setCurrentFile(const FXString& file,FXbool notify){
1528 FXTRACE((100,"%s::setCurrentFile(%s)\n",getClassName(),file.text()));
1529 if(setDirectory(FXPath::directory(file),notify)){
1530 FXint index=findItem(FXPath::name(file));
1531 if(0<=index){
1532 makeItemVisible(index);
1533 setAnchorItem(index);
1534 setCurrentItem(index,notify);
1535 selectItem(index,notify);
1536 return true;
1537 }
1538 }
1539 return false;
1540 }
1541
1542
1543 // Get pathname to current file, if any
getCurrentFile() const1544 FXString FXFileList::getCurrentFile() const {
1545 if(0<=getCurrentItem()){
1546 return getItemPathname(getCurrentItem());
1547 }
1548 return FXString::null;
1549 }
1550
1551
1552 // Set current directory; return true if success
setDirectory(const FXString & pathname,FXbool notify)1553 FXbool FXFileList::setDirectory(const FXString& pathname,FXbool notify){
1554 FXTRACE((100,"%s::setDirectory(%s)\n",getClassName(),pathname.text()));
1555 FXString path(FXPath::absolute(directory,pathname));
1556 if(FXStat::isDirectory(path)){
1557 if(directory==path) return true;
1558 clearItems(notify);
1559 directory=path;
1560 list=NULL;
1561 if(listItems(true,notify)){
1562 if(getNumItems()){
1563 makeItemVisible(0);
1564 setAnchorItem(0);
1565 setCurrentItem(0,notify);
1566 }
1567 return true;
1568 }
1569 }
1570 return false;
1571 }
1572
1573 /*******************************************************************************/
1574
1575 // Get file name from item
getItemFilename(FXint index) const1576 FXString FXFileList::getItemFilename(FXint index) const {
1577 if(index<0 || getNumItems()<=index){ fxerror("%s::getItemFilename: index out of range.\n",getClassName()); }
1578 return items[index]->label.section('\t',0);
1579 }
1580
1581
1582 // Get full pathname to item
getItemPathname(FXint index) const1583 FXString FXFileList::getItemPathname(FXint index) const {
1584 if(index<0 || getNumItems()<=index){ fxerror("%s::getItemPathname: index out of range.\n",getClassName()); }
1585 return FXPath::absolute(directory,items[index]->label.section('\t',0));
1586 }
1587
1588
1589 // Is file
isItemFile(FXint index) const1590 FXbool FXFileList::isItemFile(FXint index) const {
1591 if(index<0 || getNumItems()<=index){ fxerror("%s::isItemFile: index out of range.\n",getClassName()); }
1592 return ((FXFileItem*)items[index])->isFile();
1593 }
1594
1595
1596 // Is directory
isItemDirectory(FXint index) const1597 FXbool FXFileList::isItemDirectory(FXint index) const {
1598 if(index<0 || getNumItems()<=index){ fxerror("%s::isItemDirectory: index out of range.\n",getClassName()); }
1599 return ((FXFileItem*)items[index])->isDirectory();
1600 }
1601
1602
1603 // Is executable
isItemExecutable(FXint index) const1604 FXbool FXFileList::isItemExecutable(FXint index) const {
1605 if(index<0 || getNumItems()<=index){ fxerror("%s::isItemExecutable: index out of range.\n",getClassName()); }
1606 return ((FXFileItem*)items[index])->isExecutable();
1607 }
1608
1609
1610 // Return true if this is a symbolic link item
isItemSymlink(FXint index) const1611 FXbool FXFileList::isItemSymlink(FXint index) const {
1612 if(index<0 || getNumItems()<=index){ fxerror("%s::isItemSymlink: index out of range.\n",getClassName()); }
1613 return ((FXFileItem*)items[index])->isSymlink();
1614 }
1615
1616
1617 // Return true if item is navigational item like '.' or '..'
isItemNavigational(FXint index) const1618 FXbool FXFileList::isItemNavigational(FXint index) const {
1619 if(index<0 || getNumItems()<=index){ fxerror("%s::isItemNavigational: index out of range.\n",getClassName()); }
1620 return ((FXFileItem*)items[index])->isNavigational();
1621 }
1622
1623
1624 // Get associations (if any) from the file
getItemAssoc(FXint index) const1625 FXFileAssoc* FXFileList::getItemAssoc(FXint index) const {
1626 if(index<0 || getNumItems()<=index){ fxerror("%s::getItemAssoc: index out of range.\n",getClassName()); }
1627 return ((FXFileItem*)items[index])->getAssoc();
1628 }
1629
1630
1631 // Return the file size for this item
getItemSize(FXint index) const1632 FXlong FXFileList::getItemSize(FXint index) const {
1633 if(index<0 || getNumItems()<=index){ fxerror("%s::getItemSize: index out of range.\n",getClassName()); }
1634 return ((FXFileItem*)items[index])->getSize();
1635 }
1636
1637
1638 // Return the date for this item, in nanoseconds
getItemDate(FXint index) const1639 FXTime FXFileList::getItemDate(FXint index) const {
1640 if(index<0 || getNumItems()<=index){ fxerror("%s::getItemDate: index out of range.\n",getClassName()); }
1641 return ((FXFileItem*)items[index])->getDate();
1642 }
1643
1644
1645 // Return the mode bits for this item
getItemMode(FXint index) const1646 FXuint FXFileList::getItemMode(FXint index) const {
1647 if(index<0 || getNumItems()<=index){ fxerror("%s::getItemMode: index out of range.\n",getClassName()); }
1648 return ((FXFileItem*)items[index])->getMode();
1649 }
1650
1651 /*******************************************************************************/
1652
1653 // Set the pattern to filter
setPattern(const FXString & ptrn,FXbool notify)1654 void FXFileList::setPattern(const FXString& ptrn,FXbool notify){
1655 if(!ptrn.empty() && pattern!=ptrn){
1656 pattern=ptrn;
1657 listItems(true,notify);
1658 }
1659 }
1660
1661 // Change file match mode
setMatchMode(FXuint mode,FXbool notify)1662 void FXFileList::setMatchMode(FXuint mode,FXbool notify){
1663 if(matchmode!=mode){
1664 matchmode=mode;
1665 listItems(true,notify);
1666 }
1667 }
1668
1669
1670 // Change show hidden files mode
showHiddenFiles(FXbool flag,FXbool notify)1671 void FXFileList::showHiddenFiles(FXbool flag,FXbool notify){
1672 FXuint opts=((-(FXint)flag^options)&FILELIST_SHOWHIDDEN)^options;
1673 if(opts!=options){
1674 options=opts;
1675 listItems(true,notify);
1676 }
1677 }
1678
1679
1680 // Return true if showing hidden files
showHiddenFiles() const1681 FXbool FXFileList::showHiddenFiles() const {
1682 return (options&FILELIST_SHOWHIDDEN)!=0;
1683 }
1684
1685
1686 // Change show directories only mode
showOnlyDirectories(FXbool flag,FXbool notify)1687 void FXFileList::showOnlyDirectories(FXbool flag,FXbool notify){
1688 FXuint opts=(((0-flag)^options)&FILELIST_SHOWDIRS)^options;
1689 if(opts!=options){
1690 options=opts;
1691 listItems(true,notify);
1692 }
1693 }
1694
1695
1696 // Return true if showing directories only
showOnlyDirectories() const1697 FXbool FXFileList::showOnlyDirectories() const {
1698 return (options&FILELIST_SHOWDIRS)!=0;
1699 }
1700
1701
1702 // Show files only
showOnlyFiles(FXbool flag,FXbool notify)1703 void FXFileList::showOnlyFiles(FXbool flag,FXbool notify){
1704 FXuint opts=(((0-flag)^options)&FILELIST_SHOWFILES)^options;
1705 if(opts!=options){
1706 options=opts;
1707 listItems(true,notify);
1708 }
1709 }
1710
1711
1712 // Return true if showing files only
showOnlyFiles() const1713 FXbool FXFileList::showOnlyFiles() const {
1714 return (options&FILELIST_SHOWFILES)!=0;
1715 }
1716
1717
1718 // Show parent directories
showParents(FXbool flag,FXbool notify)1719 void FXFileList::showParents(FXbool flag,FXbool notify){
1720 FXuint opts=(((flag-1)^options)&FILELIST_NO_PARENT)^options;
1721 if(opts!=options){
1722 options=opts;
1723 listItems(true,notify);
1724 }
1725 }
1726
1727
1728 // Return true if showing parent directories
showParents() const1729 FXbool FXFileList::showParents() const {
1730 return (options&FILELIST_NO_PARENT)==0;
1731 }
1732
1733
1734 // Change show image display mode
showImages(FXbool flag,FXbool notify)1735 void FXFileList::showImages(FXbool flag,FXbool notify){
1736 FXuint opts=(((0-flag)^options)&FILELIST_SHOWIMAGES)^options;
1737 if(opts!=options){
1738 options=opts;
1739 listItems(true,notify);
1740 }
1741 }
1742
1743
1744 // Return true if displaying image
showImages() const1745 FXbool FXFileList::showImages() const {
1746 return (options&FILELIST_SHOWIMAGES)!=0;
1747 }
1748
1749
1750 // Change images preview size
setImageSize(FXint size,FXbool notify)1751 void FXFileList::setImageSize(FXint size,FXbool notify){
1752 if(size!=imagesize){
1753 imagesize=size;
1754 listItems(true,notify);
1755 }
1756 }
1757
1758
1759 // Change file associations; delete the old one unless it was shared
setAssociations(FXFileAssociations * assocs,FXbool owned,FXbool notify)1760 void FXFileList::setAssociations(FXFileAssociations* assocs,FXbool owned,FXbool notify){
1761 FXuint opts=options;
1762 options^=((owned-1)^options)&FILELIST_NO_OWN_ASSOC;
1763 if(associations!=assocs){
1764 if(!(opts&FILELIST_NO_OWN_ASSOC)) delete associations;
1765 associations=assocs;
1766 listItems(true,notify);
1767 }
1768 }
1769
1770
1771 // Set draggable files
setDraggableFiles(FXbool flg,FXbool notify)1772 void FXFileList::setDraggableFiles(FXbool flg,FXbool notify){
1773 if(draggable!=flg){
1774 draggable=flg;
1775 listItems(true,notify);
1776 }
1777 }
1778
1779
1780 // Set file time format
setTimeFormat(const FXString & fmt,FXbool notify)1781 void FXFileList::setTimeFormat(const FXString& fmt,FXbool notify){
1782 if(timeformat!=fmt){
1783 timeformat=fmt;
1784 listItems(true,notify);
1785 }
1786 }
1787
1788 /*******************************************************************************/
1789
1790 // Save data
save(FXStream & store) const1791 void FXFileList::save(FXStream& store) const {
1792 FXIconList::save(store);
1793 store << associations;
1794 store << iconloader;
1795 store << big_folder;
1796 store << mini_folder;
1797 store << big_doc;
1798 store << mini_doc;
1799 store << big_app;
1800 store << mini_app;
1801 store << directory;
1802 store << pattern;
1803 store << timeformat;
1804 store << matchmode;
1805 store << imagesize;
1806 store << draggable;
1807 }
1808
1809
1810 // Load data
load(FXStream & store)1811 void FXFileList::load(FXStream& store){
1812 FXIconList::load(store);
1813 store >> associations;
1814 store >> iconloader;
1815 store >> big_folder;
1816 store >> mini_folder;
1817 store >> big_doc;
1818 store >> mini_doc;
1819 store >> big_app;
1820 store >> mini_app;
1821 store >> directory;
1822 store >> pattern;
1823 store >> timeformat;
1824 store >> matchmode;
1825 store >> imagesize;
1826 store >> draggable;
1827 }
1828
1829
1830 // Cleanup
~FXFileList()1831 FXFileList::~FXFileList(){
1832 getApp()->removeChore(this);
1833 getApp()->removeTimeout(this,ID_OPENTIMER);
1834 getApp()->removeTimeout(this,ID_REFRESHTIMER);
1835 if(!(options&FILELIST_NO_OWN_ASSOC)) delete associations;
1836 delete big_folder;
1837 delete mini_folder;
1838 delete big_doc;
1839 delete mini_doc;
1840 delete big_app;
1841 delete mini_app;
1842 associations=(FXFileAssociations*)-1L;
1843 iconloader=(FXIconSource*)-1L;
1844 list=(FXFileItem*)-1L;
1845 big_folder=(FXIcon*)-1L;
1846 mini_folder=(FXIcon*)-1L;
1847 big_doc=(FXIcon*)-1L;
1848 mini_doc=(FXIcon*)-1L;
1849 big_app=(FXIcon*)-1L;
1850 mini_app=(FXIcon*)-1L;
1851 }
1852
1853 }
1854