1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 #include "Fsb.h"
26 #include "FsbP.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <time.h>
33 #include <inttypes.h>
34 #include <errno.h>
35
36 #include <sys/stat.h>
37 #include <limits.h>
38 #include <dirent.h>
39 #include <fnmatch.h>
40
41 #include <Xm/XmAll.h>
42 #include <Xm/DropDown.h>
43
44 #include "pathbar.h"
45
46 #include "../common/utils.h"
47
48 #ifdef FSB_ENABLE_DETAIL
49 #include <XmL/Grid.h>
50 #endif
51
52 #define WIDGET_SPACING 5
53 #define WINDOW_SPACING 8
54
55 #define BUTTON_EXTRA_SPACE 4
56
57 #define DATE_FORMAT_SAME_YEAR "%b %d %H:%M"
58 #define DATE_FORMAT_OTHER_YEAR "%b %d %Y"
59
60 #define KB_SUFFIX "KiB"
61 #define MB_SUFFIX "MiB"
62 #define GB_SUFFIX "GiB"
63 #define TB_SUFFIX "TiB"
64
65 #define FSB_ERROR_TITLE "Error"
66 #define FSB_ERROR_CHAR "Character ''/'' is not allowed in file names"
67 #define FSB_ERROR_RENAME "Cannot rename file: %s"
68 #define FSB_ERROR_DELETE "Cannot delete file: %s"
69 #define FSB_ERROR_CREATE_FOLDER "Cannot create folder: %s"
70 #define FSB_ERROR_OPEN_DIR "Cannot open directory: %s"
71
72 #define FSB_DETAIL_HEADINGS "Name|Size|Last Modified"
73
74 static void fsb_class_init(
void);
75 static void fsb_class_part_init (WidgetClass wc);
76 static void fsb_init(Widget request, Widget neww, ArgList args, Cardinal *num_args);
77 static void fsb_resize(Widget widget);
78 static void fsb_realize(Widget widget, XtValueMask *mask, XSetWindowAttributes *attributes);
79 static void fsb_destroy(Widget widget);
80 static Boolean fsb_set_values(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args);
81 static Boolean fsb_acceptfocus(Widget widget, Time *time);
82
83 static void fsb_insert_child(Widget child);
84
85 static void fsb_mapcb(Widget widget, XtPointer u, XtPointer cb);
86
87 static int FSBGlobFilter(
const char *a,
const char *b);
88
89 static void FSBUpdateTitle(Widget w);
90
91 static void FocusInAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
92
93 static void ErrDialog(XnFileSelectionBox w,
const char *title,
const char *errmsg);
94
95 static void FSBRename(XnFileSelectionBox fsb,
const char *path);
96 static void FSBDelete(XnFileSelectionBox fsb,
const char *path);
97
98 static void FSBSelectItem(XnFileSelectionBox fsb,
const char *item);
99
100 static char* set_selected_path(XnFileSelectionBox data, XmString item);
101
102 static void FileContextMenuCB(Widget item, XtPointer index, XtPointer cd);
103
104 static Widget CreateContextMenu(XnFileSelectionBox fsb, Widget parent, XtCallbackProc callback);
105
106 static void FileListUpdate(Widget fsb, Widget view, FileElm *dirlist,
int dircount, FileElm *files,
int filecount,
const char *filter,
int maxnamelen,
void *userData);
107 static void FileListSelect(Widget fsb, Widget view,
const char *item);
108 static void FileListCleanup(Widget fsb, Widget view,
void *userData);
109 static void FileListDestroy(Widget fsb, Widget view,
void *userData);
110
111 static void FileListActivateCB(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb);
112 static void FileListSelectCB(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb);
113
114 static void FileListWidgetAdd(XnFileSelectionBox fsb, Widget w,
int showHidden,
const char *filter, FileElm *ls,
int count);
115
116 #ifdef FSB_ENABLE_DETAIL
117 static void FileListDetailUpdate(Widget fsb, Widget view, FileElm *dirlist,
int dircount, FileElm *files,
int filecount,
const char *filter,
int maxnamelen,
void *userData);
118 static void FileListDetailSelect(Widget fsb, Widget view,
const char *item);
119 static void FileListDetailCleanup(Widget fsb, Widget view,
void *userData);
120 static void FileListDetailDestroy(Widget fsb, Widget view,
void *userData);
121 static void FileListDetailAdjustColWidth(Widget grid);
122 static void FileListDetailAdd(XnFileSelectionBox fsb, Widget grid,
int showHidden,
const char *filter, FileElm *ls,
int count,
int maxWidth);
123 #endif
124
125 static void FSBNewFolder(Widget w, XnFileSelectionBox data, XtPointer u);
126
127 static void FSBHome(Widget w, XnFileSelectionBox data, XtPointer u);
128
129 static void FileSelectionCallback(XnFileSelectionBox fsb, XtCallbackList cb,
int reason,
const char *value);
130
131 static void CreateUI(XnFileSelectionBox w);
132 static FSBViewWidgets CreateView(XnFileSelectionBox w, FSBViewCreateProc createProc,
void *userData, Boolean useDirList);
133 static void AddViewMenuItem(XnFileSelectionBox w,
const char *name,
int viewIndex);
134 static void SelectView(XnFileSelectionBox f,
int view);
135
136 static char* FSBDialogTitle(Widget w);
137
138 static FSBViewWidgets CreateListView(Widget fsb, ArgList args,
int n,
void *userData);
139 static FSBViewWidgets CreateDetailView(Widget fsb, ArgList args,
int n,
void *userData);
140
141 static const char* GetHomeDir(
void);
142
143 static char* ConcatPath(
const char *parent,
const char *name);
144 static char* FileName(
char *path);
145 static char* ParentPath(
const char *path);
146
147
148 static int filedialog_update_dir(XnFileSelectionBox data,
const char *path);
149 static void filedialog_cleanup_filedata(XnFileSelectionBox data);
150
151
152 static XtResource resources[] = {
153 {XmNokCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), XtOffset(XnFileSelectionBox, fsb.okCallback), XmRCallback,
NULL},
154 {XmNcancelCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), XtOffset(XnFileSelectionBox, fsb.cancelCallback), XmRCallback,
NULL},
155 {XnNwidgetSpacing, XmCSpacing, XmRDimension,
sizeof(Dimension), XtOffset(XnFileSelectionBox, fsb.widgetSpacing), XmRImmediate, (XtPointer)
WIDGET_SPACING},
156 {XnNwindowSpacing, XmCSpacing, XmRDimension,
sizeof(Dimension), XtOffset(XnFileSelectionBox, fsb.windowSpacing), XmRImmediate, (XtPointer)
WINDOW_SPACING},
157 {XnNfsbType, XnCfsbType, XmRInt,
sizeof(
int), XtOffset(XnFileSelectionBox, fsb.type), XmRImmediate, (XtPointer)
FILEDIALOG_OPEN},
158 {XnNshowHidden, XnCshowHidden, XmRBoolean,
sizeof(Boolean), XtOffset(XnFileSelectionBox, fsb.showHidden), XmRImmediate, (XtPointer)False},
159 {XnNshowHiddenButton, XnCshowHiddenButton, XmRBoolean,
sizeof(Boolean), XtOffset(XnFileSelectionBox, fsb.showHiddenButton), XmRImmediate, (XtPointer)True},
160 {XnNshowViewMenu, XnCshowViewMenu, XmRBoolean,
sizeof(Boolean), XtOffset(XnFileSelectionBox, fsb.showViewMenu), XmRImmediate, (XtPointer)False},
161 {XnNselectedView, XnCselectedView, XmRInt,
sizeof(
int), XtOffset(XnFileSelectionBox, fsb.selectedview), XmRImmediate, (XtPointer)
0},
162
163 {XnNdirectory, XnCdirectory, XmRString,
sizeof(XmString), XtOffset(XnFileSelectionBox, fsb.currentPath), XmRString,
NULL},
164 {XnNselectedPath, XnCselectedPath, XmRString,
sizeof(XmString), XtOffset(XnFileSelectionBox, fsb.selectedPath), XmRString,
NULL},
165 {XnNhomePath, XnChomePath, XmRString,
sizeof(XmString), XtOffset(XnFileSelectionBox, fsb.homePath), XmRString,
NULL},
166
167 {XnNfilter,XnCfilter,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.filterStr), XmRString,
"*"},
168 {XnNfilterFunc,XnCfilterFunc,XmRFunction,
sizeof(FSBFilterFunc),XtOffset(XnFileSelectionBox, fsb.filterFunc), XmRFunction,
NULL},
169
170 {XnNlabelListView,XnClabelListView,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelListView), XmRString,
"List"},
171 {XnNlabelDetailView,XnClabelDetailView,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDetailView), XmRString,
"Detail"},
172 {XnNlabelOpenFileTitle,XnClabelOpenFileTitle,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelOpenFileTitle), XmRString,
"Open File"},
173 {XnNlabelSaveFileTitle,XnClabelSaveFileTitle,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelSaveFileTitle), XmRString,
"Save File"},
174 {XnNlabelDirUp,XnClabelDirUp,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDirUp), XmRString,
"Dir Up"},
175 {XnNlabelHome,XnClabelHome,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelHome), XmRString,
"Home"},
176 {XnNlabelNewFolder,XnClabelNewFolder,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelNewFolder), XmRString,
"New Folder"},
177 {XnNlabelFilterButton,XnClabelFilterButton,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelFilterButton), XmRString,
"Filter"},
178 {XnNlabelShowHiddenFiles,XnClabelShowHiddenFiles,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelShowHiddenFiles), XmRString,
"Show hiden files"},
179 {XnNlabelDirectories,XnClabelDirectories,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDirectories), XmRString,
"Directories"},
180 {XnNlabelFiles,XnClabelFiles,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelFiles), XmRString,
"Files"},
181 {XnNlabelRename,XnClabelRename,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelRename), XmRString,
"Rename"},
182 {XnNlabelDelete,XnClabelDelete,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDelete), XmRString,
"Delete"},
183 {XnNlabelOpen,XnClabelOpen,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelOpen), XmRString,
"Open"},
184 {XnNlabelSave,XnClabelSave,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelSave), XmRString,
"Save"},
185 {XnNlabelOk,XnClabelOk,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelOk), XmRString,
"OK"},
186 {XnNlabelCancel,XnClabelCancel,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelCancel), XmRString,
"Cancel"},
187 {XnNlabelHelp,XnClabelHelp,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelHelp), XmRString,
"Help"},
188 {XnNlabelFileName,XnClabelFileName,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelFileName), XmRString,
"New File Name"},
189 {XnNlabelDirectoryName,XnClabelDirectoryName,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDirectoryName), XmRString,
"Directory name:"},
190 {XnNlabelNewFileName,XnClabelNewFileName,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelNewFileName), XmRString,
"New file name:"},
191 {XnNlabelDeleteFile,XnClabelDeleteFile,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDeleteFile), XmRString,
"Delete file ''%s''?"},
192 {XnNdetailHeadings,XnCdetailHeadings,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.detailHeadings), XmRString,
FSB_DETAIL_HEADINGS},
193 {XnNdateFormatSameYear,XnCdateFormatSameYear,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.dateFormatSameYear), XmRString,
DATE_FORMAT_SAME_YEAR},
194 {XnNdateFormatOtherYear,XnNdateFormatOtherYear,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.dateFormatOtherYear), XmRString,
DATE_FORMAT_OTHER_YEAR},
195 {XnNsuffixBytes,XnCsuffixBytes,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixBytes), XmRString,
"bytes"},
196 {XnNsuffixKB,XnCsuffixKB,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixKB), XmRString,
KB_SUFFIX},
197 {XnNsuffixMB,XnCsuffixKB,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixMB), XmRString,
MB_SUFFIX},
198 {XnNsuffixGB,XnCsuffixKB,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixGB), XmRString,
GB_SUFFIX},
199 {XnNsuffixTB,XnCsuffixKB,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixTB), XmRString,
TB_SUFFIX},
200
201 {XnNerrorTitle,XnCerrorTitle,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorTitle), XmRString,
FSB_ERROR_TITLE},
202 {XnNerrorIllegalChar,XnCerrorIllegalChar,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorIllegalChar), XmRString,
FSB_ERROR_CHAR},
203 {XnNerrorRename,XnCerrorRename,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorRename), XmRString,
FSB_ERROR_RENAME},
204 {XnNerrorCreateFolder,XnCerrorCreateFolder,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorFolder), XmRString,
FSB_ERROR_CREATE_FOLDER},
205 {XnNerrorDelete,XnCerrorDelete,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorDelete), XmRString,
FSB_ERROR_DELETE},
206 {XnNerrorOpenDir,XnCerrorOpenDir,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorOpenDir), XmRString,
FSB_ERROR_OPEN_DIR}
207 };
208
209 static XtActionsRec actionslist[] = {
210 {
"focusIn", FocusInAP},
211 {
"NULL",
NULL}
212 };
213
214
215 static char defaultTranslations[] =
"<FocusIn>: focusIn()";
216
217 static XtResource constraints[] = {};
218
219 FSBClassRec fsbWidgetClassRec = {
220
221 {
222 (WidgetClass)&xmFormClassRec,
223 "XnFSB",
224 sizeof(FSBRec),
225 fsb_class_init,
226 fsb_class_part_init,
227 FALSE,
228 fsb_init,
229 NULL,
230 fsb_realize,
231 actionslist,
232 XtNumber(actionslist),
233 resources,
234 XtNumber(resources),
235 NULLQUARK,
236 True,
237 True,
238 True,
239 False,
240 fsb_destroy,
241 fsb_resize,
242 XtInheritExpose,
243 fsb_set_values,
244 NULL,
245 XtInheritSetValuesAlmost,
246 NULL,
247 fsb_acceptfocus,
248 XtVersion,
249 NULL,
250 defaultTranslations,
251 XtInheritQueryGeometry,
252 XtInheritDisplayAccelerator,
253 NULL,
254 },
255
256 {
257 XtInheritGeometryManager,
258 XtInheritChangeManaged,
259 fsb_insert_child,
260 XtInheritDeleteChild,
261 NULL,
262 },
263
264 {
265 constraints,
266 XtNumber(constraints),
267 sizeof(XmFormConstraintRec),
268 NULL,
269 NULL,
270 NULL,
271 NULL,
272 },
273
274 {
275 XtInheritTranslations,
276 NULL,
277 0,
278 NULL,
279 0,
280 XmInheritParentProcess,
281 NULL
282 },
283
284 {
285 FALSE,
286 NULL,
287 XmInheritFocusMovedProc,
288 NULL
289 },
290
291 {
292 NULL
293 },
294
295 {
296 0
297 }
298 };
299
300 WidgetClass xnFsbWidgetClass = (WidgetClass)&fsbWidgetClassRec;
301
302
303 static void fsb_class_init(
void) {
304
305 }
306
307 static void fsb_class_part_init (WidgetClass wc) {
308 FSBClassRec *fsbClass = (FSBClassRec*)wc;
309 XmFormClassRec *formClass = (XmFormClassRec*)xmFormWidgetClass;
310
311 fsbClass->constraint_class.initialize = formClass->constraint_class.initialize;
312 fsbClass->constraint_class.set_values = formClass->constraint_class.set_values;
313 }
314
315
316 #define STRDUP_RES(a)
if(a) a = strdup(a)
317 #define XMS_STRDUP_RES(a)
if(a) a = XmStringCopy(a)
318
319 static void fsb_init(Widget request, Widget neww, ArgList args, Cardinal *num_args) {
320 XnFileSelectionBox fsb = (XnFileSelectionBox)neww;
321 (xmFormClassRec.core_class.initialize)(request, neww, args, num_args);
322
323 fsb->fsb.disable_set_values =
0;
324
325 STRDUP_RES(fsb->fsb.homePath);
326 STRDUP_RES(fsb->fsb.selectedPath);
327 STRDUP_RES(fsb->fsb.currentPath);
328 STRDUP_RES(fsb->fsb.filterStr);
329 STRDUP_RES(fsb->fsb.labelListView);
330 STRDUP_RES(fsb->fsb.labelDetailView);
331 STRDUP_RES(fsb->fsb.labelOpenFileTitle);
332 STRDUP_RES(fsb->fsb.labelSaveFileTitle);
333 XMS_STRDUP_RES(fsb->fsb.labelDirUp);
334 XMS_STRDUP_RES(fsb->fsb.labelHome);
335 XMS_STRDUP_RES(fsb->fsb.labelNewFolder);
336 XMS_STRDUP_RES(fsb->fsb.labelFilterButton);
337 XMS_STRDUP_RES(fsb->fsb.labelShowHiddenFiles);
338 XMS_STRDUP_RES(fsb->fsb.labelDirectories);
339 XMS_STRDUP_RES(fsb->fsb.labelFiles);
340 XMS_STRDUP_RES(fsb->fsb.labelRename);
341 XMS_STRDUP_RES(fsb->fsb.labelDelete);
342 XMS_STRDUP_RES(fsb->fsb.labelOpen);
343 XMS_STRDUP_RES(fsb->fsb.labelSave);
344 XMS_STRDUP_RES(fsb->fsb.labelCancel);
345 XMS_STRDUP_RES(fsb->fsb.labelHelp);
346 XMS_STRDUP_RES(fsb->fsb.labelFileName);
347 XMS_STRDUP_RES(fsb->fsb.labelDirectoryName);
348 XMS_STRDUP_RES(fsb->fsb.labelNewFileName);
349 STRDUP_RES(fsb->fsb.labelDeleteFile);
350 STRDUP_RES(fsb->fsb.detailHeadings);
351 STRDUP_RES(fsb->fsb.dateFormatSameYear);
352 STRDUP_RES(fsb->fsb.dateFormatOtherYear);
353 STRDUP_RES(fsb->fsb.suffixBytes);
354 STRDUP_RES(fsb->fsb.suffixKB);
355 STRDUP_RES(fsb->fsb.suffixMB);
356 STRDUP_RES(fsb->fsb.suffixGB);
357 STRDUP_RES(fsb->fsb.suffixTB);
358 STRDUP_RES(fsb->fsb.errorTitle);
359 STRDUP_RES(fsb->fsb.errorIllegalChar);
360 STRDUP_RES(fsb->fsb.errorRename);
361 STRDUP_RES(fsb->fsb.errorFolder);
362 STRDUP_RES(fsb->fsb.errorDelete);
363 STRDUP_RES(fsb->fsb.errorOpenDir);
364
365 CreateUI((XnFileSelectionBox)fsb);
366
367 XtAddCallback(neww, XmNmapCallback, fsb_mapcb,
NULL);
368 }
369
370 #define STR_FREE(a)
if(a) free(a)
371 #define XMSTR_FREE(a)
if(a) XmStringFree(a)
372
373 static void fsb_destroy(Widget widget) {
374 XnFileSelectionBox w = (XnFileSelectionBox)widget;
375
376
377 for(
int i=
0;i<w->fsb.numviews;i++) {
378 FSBView v = w->fsb.view[i];
379 v.destroy(widget, v.widget, v.userData);
380 }
381
382 STR_FREE(w->fsb.homePath);
383
384
385 filedialog_cleanup_filedata(w);
386 STR_FREE(w->fsb.currentPath);
387 STR_FREE(w->fsb.selectedPath);
388 STR_FREE(w->fsb.filterStr);
389
390 PathBarDestroy(w->fsb.pathBar);
391
392
393 STR_FREE(w->fsb.labelListView);
394 STR_FREE(w->fsb.labelDetailView);
395 STR_FREE(w->fsb.labelOpenFileTitle);
396 STR_FREE(w->fsb.labelSaveFileTitle);
397
398 XMSTR_FREE(w->fsb.labelDirUp);
399 XMSTR_FREE(w->fsb.labelHome);
400 XMSTR_FREE(w->fsb.labelNewFolder);
401 XMSTR_FREE(w->fsb.labelFilterButton);
402 XMSTR_FREE(w->fsb.labelShowHiddenFiles);
403 XMSTR_FREE(w->fsb.labelDirectories);
404 XMSTR_FREE(w->fsb.labelFiles);
405 XMSTR_FREE(w->fsb.labelRename);
406 XMSTR_FREE(w->fsb.labelDelete);
407 XMSTR_FREE(w->fsb.labelOpen);
408 XMSTR_FREE(w->fsb.labelSave);
409 XMSTR_FREE(w->fsb.labelCancel);
410 XMSTR_FREE(w->fsb.labelHelp);
411 XMSTR_FREE(w->fsb.labelFileName);
412 XMSTR_FREE(w->fsb.labelDirectoryName);
413 XMSTR_FREE(w->fsb.labelNewFileName);
414 STR_FREE(w->fsb.labelDeleteFile);
415 STR_FREE(w->fsb.detailHeadings);
416
417 STR_FREE(w->fsb.dateFormatSameYear);
418 STR_FREE(w->fsb.dateFormatOtherYear);
419 STR_FREE(w->fsb.suffixBytes);
420 STR_FREE(w->fsb.suffixKB);
421 STR_FREE(w->fsb.suffixMB);
422 STR_FREE(w->fsb.suffixGB);
423 STR_FREE(w->fsb.suffixTB);
424
425 STR_FREE(w->fsb.errorTitle);
426 STR_FREE(w->fsb.errorIllegalChar);
427 STR_FREE(w->fsb.errorRename);
428 STR_FREE(w->fsb.errorFolder);
429 STR_FREE(w->fsb.errorDelete);
430 STR_FREE(w->fsb.errorOpenDir);
431 }
432
433 static void fsb_resize(Widget widget) {
434 XnFileSelectionBox w = (XnFileSelectionBox)widget;
435 (xmFormClassRec.core_class.resize)(widget);
436
437 #ifdef FSB_ENABLE_DETAIL
438 if(w->fsb.view[w->fsb.selectedview].update == FileListDetailUpdate) {
439 FileListDetailAdjustColWidth(w->fsb.grid);
440 }
441 #endif
442 }
443
444 static void fsb_realize(Widget widget, XtValueMask *mask, XSetWindowAttributes *attributes) {
445 XnFileSelectionBox w = (XnFileSelectionBox)widget;
446 (xmFormClassRec.core_class.realize)(widget, mask, attributes);
447
448 FSBView view = w->fsb.view[w->fsb.selectedview];
449 XmProcessTraversal(view.focus, XmTRAVERSE_CURRENT);
450
451 #ifdef FSB_ENABLE_DETAIL
452 if(w->fsb.view[w->fsb.selectedview].update == FileListDetailUpdate) {
453 FileListDetailAdjustColWidth(w->fsb.grid);
454 }
455 #endif
456 }
457
458 static void FSBUpdateTitle(Widget w) {
459 if(XtParent(w)->core.widget_class == xmDialogShellWidgetClass) {
460 char *title = FSBDialogTitle(w);
461 XtVaSetValues(XtParent(w), XmNtitle, title,
NULL);
462 }
463 }
464
465 static Boolean fsb_set_values(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) {
466 Boolean r = False;
467
468 XnFileSelectionBox o = (XnFileSelectionBox)old;
469 XnFileSelectionBox n = (XnFileSelectionBox)neww;
470
471 int setOkBtnLabel =
0;
472 int ismanaged = XtIsManaged(neww);
473 Dimension width, height;
474 if(!ismanaged) {
475 width = n->core.width;
476 height = n->core.height;
477 if(n->fsb.pathBar) {
478 n->fsb.pathBar->disableResize = True;
479 }
480 }
481
482 if(o->fsb.selectedview != n->fsb.selectedview) {
483 int selectedview = n->fsb.selectedview;
484 n->fsb.selectedview = o->fsb.selectedview;
485 SelectView(n, selectedview);
486 }
487
488 char *updateDir =
NULL;
489 int selectItem =
0;
490 if(o->fsb.selectedPath != n->fsb.selectedPath) {
491 STR_FREE(o->fsb.selectedPath);
492 STRDUP_RES(n->fsb.selectedPath);
493 XmTextFieldSetString(n->fsb.name, FileName(n->fsb.selectedPath));
494
495 updateDir = ParentPath(n->fsb.selectedPath);
496 selectItem =
1;
497 }
498 if(o->fsb.currentPath != n->fsb.currentPath) {
499 STR_FREE(o->fsb.currentPath);
500 updateDir = strdup(n->fsb.currentPath);
501 n->fsb.currentPath =
NULL;
502 }
503
504 if(o->fsb.filterStr != n->fsb.filterStr) {
505 STR_FREE(o->fsb.filterStr);
506 STRDUP_RES(n->fsb.filterStr);
507 XmTextFieldSetString(XmDropDownGetText(n->fsb.filter), n->fsb.filterStr);
508 if(!updateDir) {
509 filedialog_update_dir(n,
NULL);
510 }
511 }
512
513 if(updateDir) {
514 filedialog_update_dir(n, updateDir);
515 PathBarSetPath(n->fsb.pathBar, updateDir);
516 free(updateDir);
517 }
518
519 if(o->fsb.type != n->fsb.type) {
520 if(n->fsb.type ==
FILEDIALOG_OPEN) {
521 XtVaSetValues(n->fsb.workarea, XmNbottomWidget, n->fsb.separator,
NULL);
522 XtUnmanageChild(n->fsb.name);
523 XtUnmanageChild(n->fsb.nameLabel);
524 }
else {
525 XtManageChild(n->fsb.name);
526 XtManageChild(n->fsb.nameLabel);
527 XtVaSetValues(n->fsb.workarea, XmNbottomWidget, n->fsb.nameLabel,
NULL);
528 }
529 FSBUpdateTitle(neww);
530 setOkBtnLabel =
1;
531 }
532
533
534 int updateTitle =
0;
535 if(o->fsb.labelListView != n->fsb.labelListView) {
536 STR_FREE(o->fsb.labelListView);
537 STRDUP_RES(n->fsb.labelListView);
538 XmString label = XmStringCreateLocalized(n->fsb.labelListView);
539 XtVaSetValues(n->fsb.viewSelectorList, XmNlabelString, label,
NULL);
540 XmStringFree(label);
541 }
542 if(o->fsb.labelDetailView != n->fsb.labelDetailView) {
543 STR_FREE(o->fsb.labelDetailView);
544 STRDUP_RES(n->fsb.labelDetailView);
545 XmString label = XmStringCreateLocalized(n->fsb.labelDetailView);
546 XtVaSetValues(n->fsb.viewSelectorDetail, XmNlabelString, label,
NULL);
547 if(n->fsb.detailToggleButton) {
548 XtVaSetValues(n->fsb.detailToggleButton, XmNlabelString, label,
NULL);
549 }
550 XmStringFree(label);
551 }
552 if(o->fsb.labelOpenFileTitle != n->fsb.labelOpenFileTitle) {
553 STR_FREE(o->fsb.labelOpenFileTitle);
554 STRDUP_RES(n->fsb.labelOpenFileTitle);
555 updateTitle =
1;
556 }
557 if(o->fsb.labelSaveFileTitle != n->fsb.labelSaveFileTitle) {
558 STR_FREE(o->fsb.labelSaveFileTitle);
559 STRDUP_RES(n->fsb.labelSaveFileTitle);
560 updateTitle =
1;
561 }
562
563 if(o->fsb.labelDirUp != n->fsb.labelDirUp) {
564 XMSTR_FREE(o->fsb.labelDirUp);
565 XMS_STRDUP_RES(n->fsb.labelDirUp);
566 XtVaSetValues(n->fsb.dirUp, XmNlabelString, n->fsb.labelDirUp,
NULL);
567 }
568 if(o->fsb.labelHome != n->fsb.labelHome) {
569 XMSTR_FREE(o->fsb.labelHome);
570 XMS_STRDUP_RES(n->fsb.labelHome);
571 XtVaSetValues(n->fsb.dirUp, XmNlabelString, n->fsb.labelHome,
NULL);
572 }
573 if(o->fsb.labelNewFolder != n->fsb.labelNewFolder) {
574 XMSTR_FREE(o->fsb.labelNewFolder);
575 XMS_STRDUP_RES(n->fsb.labelNewFolder);
576 XtVaSetValues(n->fsb.newFolder, XmNlabelString, n->fsb.labelNewFolder,
NULL);
577 }
578 if(o->fsb.labelFilterButton != n->fsb.labelFilterButton) {
579 XMSTR_FREE(o->fsb.labelFilterButton);
580 XMS_STRDUP_RES(n->fsb.labelFilterButton);
581 XtVaSetValues(n->fsb.filterButton, XmNlabelString, n->fsb.labelFilterButton,
NULL);
582 }
583 if(o->fsb.labelShowHiddenFiles != n->fsb.labelShowHiddenFiles) {
584 XMSTR_FREE(o->fsb.labelShowHiddenFiles);
585 XMS_STRDUP_RES(n->fsb.labelShowHiddenFiles);
586 XtVaSetValues(n->fsb.showHiddenButtonW, XmNlabelString, n->fsb.labelShowHiddenFiles,
NULL);
587 }
588 if(o->fsb.labelDirectories != n->fsb.labelDirectories) {
589 XMSTR_FREE(o->fsb.labelDirectories);
590 XMS_STRDUP_RES(n->fsb.labelDirectories);
591 XtVaSetValues(n->fsb.lsDirLabel, XmNlabelString, n->fsb.labelDirectories,
NULL);
592 }
593 if(o->fsb.labelFiles != n->fsb.labelFiles) {
594 XMSTR_FREE(o->fsb.labelFiles);
595 XMS_STRDUP_RES(n->fsb.labelFiles);
596 XtVaSetValues(n->fsb.lsFileLabel, XmNlabelString, n->fsb.labelFiles,
NULL);
597 }
598 int recreateContextMenu =
0;
599 if(o->fsb.labelRename != n->fsb.labelRename) {
600 XMSTR_FREE(o->fsb.labelRename);
601 XMS_STRDUP_RES(n->fsb.labelRename);
602 recreateContextMenu =
1;
603 }
604 if(o->fsb.labelDelete != n->fsb.labelDelete) {
605 XMSTR_FREE(o->fsb.labelDelete);
606 XMS_STRDUP_RES(n->fsb.labelDelete);
607 recreateContextMenu =
1;
608 }
609
610 if(o->fsb.labelOpen != n->fsb.labelOpen) {
611 XMSTR_FREE(o->fsb.labelOpen);
612 XMS_STRDUP_RES(n->fsb.labelOpen);
613 setOkBtnLabel =
1;
614 }
615 if(o->fsb.labelSave != n->fsb.labelSave) {
616 XMSTR_FREE(o->fsb.labelSave);
617 XMS_STRDUP_RES(n->fsb.labelSave);
618 setOkBtnLabel =
1;
619 }
620 if(o->fsb.labelCancel != n->fsb.labelCancel) {
621 XMSTR_FREE(o->fsb.labelCancel);
622 XMS_STRDUP_RES(n->fsb.labelCancel);
623 XtVaSetValues(n->fsb.cancelBtn, XmNlabelString, n->fsb.labelCancel,
NULL);
624 }
625 if(o->fsb.labelHelp != n->fsb.labelHelp) {
626 XMSTR_FREE(o->fsb.labelHelp);
627 XMS_STRDUP_RES(n->fsb.labelHelp);
628 XtVaSetValues(n->fsb.helpBtn, XmNlabelString, n->fsb.labelHelp,
NULL);
629 }
630 if(o->fsb.labelFileName != n->fsb.labelFileName) {
631 XMSTR_FREE(o->fsb.labelFileName);
632 XMS_STRDUP_RES(n->fsb.labelFileName);
633 XtVaSetValues(n->fsb.nameLabel, XmNlabelString, n->fsb.labelFileName,
NULL);
634 }
635 if(o->fsb.labelDirectoryName != n->fsb.labelDirectoryName) {
636 XMSTR_FREE(o->fsb.labelDirectoryName);
637 XMS_STRDUP_RES(n->fsb.labelDirectoryName);
638 }
639 if(o->fsb.labelNewFileName != n->fsb.labelNewFileName) {
640 XMSTR_FREE(o->fsb.labelNewFileName);
641 XMS_STRDUP_RES(n->fsb.labelNewFileName);
642 }
643
644 if(o->fsb.labelDeleteFile != n->fsb.labelDeleteFile) {
645 STR_FREE(o->fsb.labelDeleteFile);
646 STRDUP_RES(n->fsb.labelDeleteFile);
647 }
648 #ifdef FSB_ENABLE_DETAIL
649 if(o->fsb.detailHeadings != n->fsb.detailHeadings) {
650 STR_FREE(o->fsb.detailHeadings);
651 STRDUP_RES(n->fsb.detailHeadings);
652 XtVaSetValues(n->fsb.grid, XmNsimpleHeadings, n->fsb.detailHeadings,
NULL);
653 }
654 #endif
655 if(o->fsb.dateFormatSameYear != n->fsb.dateFormatSameYear) {
656 STR_FREE(o->fsb.dateFormatSameYear);
657 STRDUP_RES(n->fsb.dateFormatSameYear);
658 }
659 if(o->fsb.dateFormatOtherYear != n->fsb.dateFormatOtherYear) {
660 STR_FREE(o->fsb.dateFormatOtherYear);
661 STRDUP_RES(n->fsb.dateFormatOtherYear);
662 }
663 if(o->fsb.suffixBytes != n->fsb.suffixBytes) {
664 STR_FREE(o->fsb.suffixBytes);
665 STRDUP_RES(n->fsb.suffixBytes);
666 }
667 if(o->fsb.suffixMB != n->fsb.suffixMB) {
668 STR_FREE(o->fsb.suffixMB);
669 STRDUP_RES(n->fsb.suffixMB);
670 }
671 if(o->fsb.suffixGB != n->fsb.suffixGB) {
672 STR_FREE(o->fsb.suffixGB);
673 STRDUP_RES(n->fsb.suffixGB);
674 }
675 if(o->fsb.suffixTB != n->fsb.suffixTB) {
676 STR_FREE(o->fsb.suffixTB);
677 STRDUP_RES(n->fsb.suffixTB);
678 }
679 if(o->fsb.errorTitle != n->fsb.errorTitle) {
680 STR_FREE(o->fsb.errorTitle);
681 STRDUP_RES(n->fsb.errorTitle);
682 }
683 if(o->fsb.errorIllegalChar != n->fsb.errorIllegalChar) {
684 STR_FREE(o->fsb.errorIllegalChar);
685 STRDUP_RES(n->fsb.errorIllegalChar);
686 }
687 if(o->fsb.errorRename != n->fsb.errorRename) {
688 STR_FREE(o->fsb.errorRename);
689 STRDUP_RES(n->fsb.errorRename);
690 }
691 if(o->fsb.errorFolder != n->fsb.errorFolder) {
692 STR_FREE(o->fsb.errorFolder);
693 STRDUP_RES(n->fsb.errorFolder);
694 }
695 if(o->fsb.errorDelete != n->fsb.errorDelete) {
696 STR_FREE(o->fsb.errorDelete);
697 STRDUP_RES(n->fsb.errorDelete);
698 }
699 if(o->fsb.errorOpenDir != n->fsb.errorOpenDir) {
700 STR_FREE(o->fsb.errorOpenDir);
701 STRDUP_RES(n->fsb.errorOpenDir);
702 }
703
704 if(updateTitle) {
705 FSBUpdateTitle(neww);
706 }
707 if(recreateContextMenu) {
708 XtDestroyWidget(n->fsb.listContextMenu);
709 XtDestroyWidget(n->fsb.gridContextMenu);
710 n->fsb.listContextMenu = CreateContextMenu(n, n->fsb.filelist, FileContextMenuCB);
711 n->fsb.gridContextMenu = CreateContextMenu(n, n->fsb.grid, FileContextMenuCB);
712 }
713 if(setOkBtnLabel) {
714 XtVaSetValues(n->fsb.okBtn, XmNlabelString, n->fsb.type ==
FILEDIALOG_OPEN ? n->fsb.labelOpen : n->fsb.labelSave,
NULL);
715 }
716
717 if(!ismanaged && !n->fsb.disable_set_values) {
718 n->fsb.disable_set_values =
1;
719 XtVaSetValues(neww, XmNwidth, width, XmNheight, height,
NULL);
720 n->fsb.disable_set_values =
0;
721
722 if(n->fsb.pathBar)
723 n->fsb.pathBar->disableResize = False;
724 }
725
726 if(selectItem) {
727 if(ismanaged) {
728 FSBSelectItem(n, FileName(n->fsb.selectedPath));
729 }
730 }
731
732 Boolean fr = (xmFormClassRec.core_class.set_values)(old, request, neww, args, num_args);
733 return fr ? fr : r;
734 }
735
736 static void fsb_insert_child(Widget child) {
737 XnFileSelectionBox p = (XnFileSelectionBox)XtParent(child);
738 (xmFormClassRec.composite_class.insert_child)(child);
739
740 if(!p->fsb.gui_created) {
741 return;
742 }
743
744
745 XtVaSetValues(child,
746 XmNbottomAttachment, XmATTACH_WIDGET,
747 XmNbottomWidget, p->fsb.bottom_widget,
748 XmNbottomOffset, p->fsb.widgetSpacing,
749 XmNleftAttachment, XmATTACH_FORM,
750 XmNleftOffset, p->fsb.windowSpacing,
751 XmNrightAttachment, XmATTACH_FORM,
752 XmNrightAttachment, XmATTACH_FORM,
753 XmNrightOffset, p->fsb.windowSpacing,
754 NULL);
755
756
757 XtVaSetValues(p->fsb.listform,
758 XmNbottomWidget, child,
759 XmNbottomOffset,
0,
760 NULL);
761
762 p->fsb.workarea = child;
763 }
764
765 Boolean fsb_acceptfocus(Widget widget, Time *time) {
766 return 0;
767 }
768
769 static void fsb_mapcb(Widget widget, XtPointer u, XtPointer cb) {
770 XnFileSelectionBox w = (XnFileSelectionBox)widget;
771 pathbar_resize(w->fsb.pathBar->widget, w->fsb.pathBar,
NULL);
772
773 if(w->fsb.type ==
FILEDIALOG_OPEN) {
774 FSBView view = w->fsb.view[w->fsb.selectedview];
775 XmProcessTraversal(view.focus, XmTRAVERSE_CURRENT);
776 }
else {
777 XmProcessTraversal(w->fsb.name, XmTRAVERSE_CURRENT);
778 }
779
780
781 if(w->fsb.selectedPath) {
782 FSBSelectItem(w, FileName(w->fsb.selectedPath));
783 }
784 }
785
786 static void FocusInAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) {
787
788 }
789
790 static int apply_filter(XnFileSelectionBox w,
const char *pattern,
const char *string) {
791 if(!pattern)
return 0;
792
793 FSBFilterFunc func = w->fsb.filterFunc ? w->fsb.filterFunc : FSBGlobFilter;
794 return func(pattern, string);
795 }
796
797 static int FSBGlobFilter(
const char *a,
const char *b) {
798 return fnmatch(a, b,
0);
799 }
800
801
802 static void errCB(Widget w, XtPointer d, XtPointer cbs) {
803 XtDestroyWidget(w);
804 }
805
806 static void ErrDialog(XnFileSelectionBox w,
const char *title,
const char *errmsg) {
807 Arg args[
16];
808 int n =
0;
809
810 XmString titleStr = XmStringCreateLocalized((
char*)title);
811 XmString msg = XmStringCreateLocalized((
char*)errmsg);
812
813 XtSetArg(args[n], XmNdialogTitle, titleStr); n++;
814 XtSetArg(args[n], XmNselectionLabelString, msg); n++;
815 XtSetArg(args[n], XmNokLabelString, w->fsb.labelOk); n++;
816 XtSetArg(args[n], XmNcancelLabelString, w->fsb.labelCancel); n++;
817
818 Widget dialog = XmCreatePromptDialog ((Widget)w,
"NewFolderPrompt", args, n);
819
820 Widget help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
821 XtUnmanageChild(help);
822 Widget cancel = XmSelectionBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON);
823 XtUnmanageChild(cancel);
824 Widget text = XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT);
825 XtUnmanageChild(text);
826
827 XtAddCallback(dialog, XmNokCallback, errCB,
NULL);
828
829 XtManageChild(dialog);
830
831 XmStringFree(titleStr);
832 XmStringFree(msg);
833 }
834
835 static void rename_file_cb(Widget w,
const char *path, XmSelectionBoxCallbackStruct *cb) {
836 XnFileSelectionBox fsb =
NULL;
837 XtVaGetValues(w, XmNuserData, &fsb,
NULL);
838
839 char *fileName =
NULL;
840 XmStringGetLtoR(cb->value, XmSTRING_DEFAULT_CHARSET, &fileName);
841
842
843 if(strchr(fileName,
'/')) {
844 ErrDialog(fsb, fsb->fsb.errorTitle, fsb->fsb.errorIllegalChar);
845 XtFree(fileName);
846 return;
847 }
848
849 char *parentPath = ParentPath(path);
850 char *newPath = ConcatPath(parentPath, fileName);
851
852 if(rename(path, newPath)) {
853 char errmsg[
256];
854 snprintf(errmsg,
256, fsb->fsb.errorRename, strerror(errno));
855 ErrDialog(fsb, fsb->fsb.errorTitle, errmsg);
856 }
else {
857 filedialog_update_dir(fsb, parentPath);
858 }
859
860 free(parentPath);
861 free(newPath);
862 XtFree(fileName);
863 XtDestroyWidget(XtParent(w));
864 }
865
866 static void selectionbox_cancel(Widget w, XtPointer data, XtPointer d) {
867 XtDestroyWidget(XtParent(w));
868 }
869
870 static void FSBRename(XnFileSelectionBox fsb,
const char *path) {
871 Arg args[
16];
872 int n =
0;
873 Widget w = (Widget)fsb;
874
875 char *name = FileName((
char*)path);
876
877 XmString filename = XmStringCreateLocalized(name);
878 XtSetArg(args[n], XmNselectionLabelString,fsb->fsb.labelNewFileName); n++;
879 XtSetArg(args[n], XmNtextString, filename); n++;
880 XtSetArg(args[n], XmNuserData, fsb); n++;
881 XtSetArg(args[n], XmNdialogTitle, fsb->fsb.labelRename); n++;
882 XtSetArg(args[n], XmNokLabelString, fsb->fsb.labelOk); n++;
883 XtSetArg(args[n], XmNcancelLabelString, fsb->fsb.labelCancel); n++;
884 Widget dialog = XmCreatePromptDialog (w,
"RenameFilePrompt", args, n);
885
886 Widget help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
887 XtUnmanageChild(help);
888
889 XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)rename_file_cb, (
char*)path);
890 XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)selectionbox_cancel,
NULL);
891
892 XmStringFree(filename);
893 XtManageChild(dialog);
894 }
895
896 static void delete_file_cb(Widget w,
const char *path, XmSelectionBoxCallbackStruct *cb) {
897 XnFileSelectionBox fsb =
NULL;
898 XtVaGetValues(w, XmNuserData, &fsb,
NULL);
899
900 if(unlink(path)) {
901 char errmsg[
256];
902 snprintf(errmsg,
256, fsb->fsb.errorDelete, strerror(errno));
903 ErrDialog(fsb, fsb->fsb.errorTitle, errmsg);
904 }
else {
905 char *parentPath = ParentPath(path);
906 filedialog_update_dir(fsb, parentPath);
907 free(parentPath);
908 }
909
910 XtDestroyWidget(XtParent(w));
911 }
912
913 static void FSBDelete(XnFileSelectionBox fsb,
const char *path) {
914 Arg args[
16];
915 int n =
0;
916 Widget w = (Widget)fsb;
917
918 char *name = FileName((
char*)path);
919 size_t len = strlen(name);
920 size_t msglen = len + strlen(fsb->fsb.labelDeleteFile) +
4;
921 char *msg = malloc(msglen);
922 snprintf(msg, msglen, fsb->fsb.labelDeleteFile, name);
923
924 XmString prompt = XmStringCreateLocalized(msg);
925 XtSetArg(args[n], XmNselectionLabelString, prompt); n++;
926 XtSetArg(args[n], XmNuserData, fsb); n++;
927 XtSetArg(args[n], XmNdialogTitle, fsb->fsb.labelDelete); n++;
928 XtSetArg(args[n], XmNokLabelString, fsb->fsb.labelOk); n++;
929 XtSetArg(args[n], XmNcancelLabelString, fsb->fsb.labelCancel); n++;
930 Widget dialog = XmCreatePromptDialog (w,
"DeleteFilePrompt", args, n);
931
932 Widget help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
933 XtUnmanageChild(help);
934 Widget text = XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT);
935 XtUnmanageChild(text);
936
937 XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)delete_file_cb, (
char*)path);
938 XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)selectionbox_cancel,
NULL);
939
940 free(msg);
941 XmStringFree(prompt);
942 XtManageChild(dialog);
943 }
944
945 static void FSBSelectItem(XnFileSelectionBox fsb,
const char *item) {
946 FSBView view = fsb->fsb.view[fsb->fsb.selectedview];
947 if(view.select) {
948 view.select((Widget)fsb, view.widget, item);
949 }
950 }
951
952 static char* set_selected_path(XnFileSelectionBox data, XmString item)
953 {
954 char *name =
NULL;
955 XmStringGetLtoR(item, XmFONTLIST_DEFAULT_TAG, &name);
956 if(!name) {
957 return NULL;
958 }
959 char *path = ConcatPath(data->fsb.currentPath, name);
960 XtFree(name);
961
962 if(data->fsb.selectedPath) {
963 free(data->fsb.selectedPath);
964 }
965 data->fsb.selectedPath = path;
966
967 return path;
968 }
969
970
971
972 static void FileContextMenuCB(Widget item, XtPointer index, XtPointer cd) {
973 intptr_t i = (
intptr_t)index;
974 Widget parent = XtParent(item);
975 XnFileSelectionBox fsb =
NULL;
976 XtVaGetValues(parent, XmNuserData, &fsb,
NULL);
977
978 const char *path = fsb->fsb.selectedPath;
979 if(path) {
980 if(i ==
0) {
981 FSBRename(fsb, path);
982 }
else if(i ==
1) {
983 FSBDelete(fsb, path);
984 }
985 }
986 }
987
988 static Widget CreateContextMenu(XnFileSelectionBox fsb, Widget parent, XtCallbackProc callback) {
989 return XmVaCreateSimplePopupMenu(
990 parent,
"popup", callback, XmNpopupEnabled, XmPOPUP_AUTOMATIC,
991 XmNuserData, fsb,
992 XmVaPUSHBUTTON, fsb->fsb.labelRename,
'R',
NULL,
NULL,
993 XmVaPUSHBUTTON, fsb->fsb.labelDelete,
'D',
NULL,
NULL,
994 NULL);
995 }
996
997
998 static void FileListUpdate(Widget fsb, Widget view, FileElm *dirs,
int dircount, FileElm *files,
int filecount,
const char *filter,
int maxnamelen,
void *userData) {
999 XnFileSelectionBox data = userData;
1000 FileListWidgetAdd(data, data->fsb.filelist, data->fsb.showHidden, filter, files, filecount);
1001 }
1002
1003 static void FileListSelect(Widget fsb, Widget view,
const char *item) {
1004 XnFileSelectionBox w = (XnFileSelectionBox)fsb;
1005
1006 int numItems =
0;
1007 XmStringTable items =
NULL;
1008 XtVaGetValues(w->fsb.filelist, XmNitemCount, &numItems, XmNitems, &items,
NULL);
1009
1010 for(
int i=
0;i<numItems;i++) {
1011 char *str =
NULL;
1012 XmStringGetLtoR(items[i], XmFONTLIST_DEFAULT_TAG, &str);
1013 if(!strcmp(str, item)) {
1014 XmListSelectPos(w->fsb.filelist, i
+1, False);
1015 break;
1016 }
1017 XtFree(str);
1018 }
1019 }
1020
1021 static void FileListCleanup(Widget fsb, Widget view,
void *userData) {
1022 XnFileSelectionBox data = userData;
1023 XmListDeleteAllItems(data->fsb.filelist);
1024 }
1025
1026 static void FileListDestroy(Widget fsb, Widget view,
void *userData) {
1027
1028 }
1029
1030 static void FileListActivateCB(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb)
1031 {
1032 char *path = set_selected_path(data, cb->item);
1033 if(path) {
1034 data->fsb.end = True;
1035 data->fsb.status =
FILEDIALOG_OK;
1036 data->fsb.selIsDir = False;
1037 FileSelectionCallback(data, data->fsb.okCallback, XmCR_OK, data->fsb.selectedPath);
1038 }
1039 }
1040
1041 static void FileListSelectCB(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb)
1042 {
1043 if(data->fsb.type ==
FILEDIALOG_SAVE) {
1044 char *name =
NULL;
1045 XmStringGetLtoR(cb->item, XmFONTLIST_DEFAULT_TAG, &name);
1046 XmTextFieldSetString(data->fsb.name, name);
1047 XtFree(name);
1048 }
else {
1049 char *path = set_selected_path(data, cb->item);
1050 if(path) {
1051 data->fsb.selIsDir = False;
1052 }
1053 }
1054 }
1055
1056
1057 static void FileListWidgetAdd(XnFileSelectionBox fsb, Widget w,
int showHidden,
const char *filter, FileElm *ls,
int count)
1058 {
1059 if(count >
0) {
1060 XmStringTable items = calloc(count,
sizeof(XmString));
1061 int i =
0;
1062
1063 for(
int j=
0;j<count;j++) {
1064 FileElm *e = &ls[j];
1065
1066 char *name = FileName(e->path);
1067 if((!showHidden && name[
0] ==
'.') || apply_filter(fsb, filter, name)) {
1068 continue;
1069 }
1070
1071 items[i] = XmStringCreateLocalized(name);
1072 i++;
1073 }
1074 XmListAddItems(w, items, i,
0);
1075 for(i=
0;i<count;i++) {
1076 XmStringFree(items[i]);
1077 }
1078 free(items);
1079 }
1080 }
1081
1082 #ifdef FSB_ENABLE_DETAIL
1083 static void FileListDetailUpdate(Widget fsb, Widget view, FileElm *dirs,
int dircount, FileElm *files,
int filecount,
const char *filter,
int maxnamelen,
void *userData) {
1084 XnFileSelectionBox data = userData;
1085 FileListDetailAdd(data, data->fsb.grid, data->fsb.showHidden, filter, files, filecount, maxnamelen);
1086 }
1087 #endif
1088
1089
1090
1091
1092 static char* size_str(XnFileSelectionBox fsb, FileElm *f) {
1093 char *str = malloc(
16);
1094 uint64_t size = f->size;
1095
1096 if(f->isDirectory) {
1097 str[
0] =
'\0';
1098 }
else if(size <
0x400) {
1099 snprintf(str,
16,
"%d %s", (
int)size, fsb->fsb.suffixBytes);
1100 }
else if(size <
0x100000) {
1101 float s = (
float)size/
0x400;
1102 int diff = (s*
100 - (
int)s*
100);
1103 if(diff >
90) {
1104 diff =
0;
1105 s +=
0.10f;
1106 }
1107 if(size <
0x2800 && diff !=
0) {
1108
1109 snprintf(str,
16,
"%.1f %s", s, fsb->fsb.suffixKB);
1110 }
else {
1111 snprintf(str,
16,
"%.0f %s", s, fsb->fsb.suffixKB);
1112 }
1113 }
else if(size <
0x40000000) {
1114 float s = (
float)size/
0x100000;
1115 int diff = (s*
100 - (
int)s*
100);
1116 if(diff >
90) {
1117 diff =
0;
1118 s +=
0.10f;
1119 }
1120 if(size <
0xa00000 && diff !=
0) {
1121
1122 snprintf(str,
16,
"%.1f %s", s, fsb->fsb.suffixMB);
1123 }
else {
1124 snprintf(str,
16,
"%.0f %s", s, fsb->fsb.suffixMB);
1125 }
1126 }
else if(size <
0x1000000000ULL) {
1127 float s = (
float)size/
0x40000000;
1128 int diff = (s*
100 - (
int)s*
100);
1129 if(diff >
90) {
1130 diff =
0;
1131 s +=
0.10f;
1132 }
1133 if(size <
0x280000000 && diff !=
0) {
1134
1135 snprintf(str,
16,
"%.1f %s", s, fsb->fsb.suffixGB);
1136 }
else {
1137 snprintf(str,
16,
"%.0f %s", s, fsb->fsb.suffixGB);
1138 }
1139 }
else {
1140 size /=
1024;
1141 float s = (
float)size/
0x40000000;
1142 int diff = (s*
100 - (
int)s*
100);
1143 if(diff >
90) {
1144 diff =
0;
1145 s +=
0.10f;
1146 }
1147 if(size <
0x280000000 && diff !=
0) {
1148
1149 snprintf(str,
16,
"%.1f %s", s, fsb->fsb.suffixTB);
1150 }
else {
1151 snprintf(str,
16,
"%.0f %s", s, fsb->fsb.suffixTB);
1152 }
1153 }
1154 return str;
1155 }
1156
1157 static char* date_str(XnFileSelectionBox fsb,
time_t tm) {
1158 struct tm t;
1159 struct tm n;
1160 time_t now = time(
NULL);
1161
1162 localtime_r(&tm, &t);
1163 localtime_r(&now, &n);
1164
1165 char *str = malloc(
24);
1166 if(t.tm_year == n.tm_year) {
1167 strftime(str,
24, fsb->fsb.dateFormatSameYear, &t);
1168 }
else {
1169 strftime(str,
24, fsb->fsb.dateFormatOtherYear, &t);
1170 }
1171 return str;
1172 }
1173
1174 #ifdef FSB_ENABLE_DETAIL
1175 static void FileListDetailAdjustColWidth(Widget grid) {
1176 XmLGridColumn column0 = XmLGridGetColumn(grid, XmCONTENT,
0);
1177 XmLGridColumn column1 = XmLGridGetColumn(grid, XmCONTENT,
1);
1178 XmLGridColumn column2 = XmLGridGetColumn(grid, XmCONTENT,
2);
1179
1180 Dimension col0Width = XmLGridColumnWidthInPixels(column0);
1181 Dimension col1Width = XmLGridColumnWidthInPixels(column1);
1182 Dimension col2Width = XmLGridColumnWidthInPixels(column2);
1183
1184 Dimension totalWidth = col0Width + col1Width + col2Width;
1185
1186 Dimension gridWidth =
0;
1187 Dimension gridShadow =
0;
1188 XtVaGetValues(grid, XmNwidth, &gridWidth, XmNshadowThickness, &gridShadow,
NULL);
1189
1190 Dimension widthDiff = gridWidth - totalWidth - gridShadow - gridShadow;
1191
1192 if(gridWidth > totalWidth) {
1193 XtVaSetValues(grid,
1194 XmNcolumnRangeStart,
0,
1195 XmNcolumnRangeEnd,
0,
1196 XmNcolumnWidth, col0Width + widthDiff - XmLGridVSBWidth(grid) -
2,
1197 XmNcolumnSizePolicy, XmCONSTANT,
1198 NULL);
1199 }
1200 }
1201
1202 static void FileListDetailAdd(XnFileSelectionBox fsb, Widget grid,
int showHidden,
const char *filter, FileElm *ls,
int count,
int maxWidth)
1203 {
1204 XmLGridAddRows(grid, XmCONTENT,
1, count);
1205
1206 int row =
0;
1207 for(
int i=
0;i<count;i++) {
1208 FileElm *e = &ls[i];
1209
1210 char *name = FileName(e->path);
1211 if((!showHidden && name[
0] ==
'.') || (!e->isDirectory && apply_filter(fsb, filter, name))) {
1212 continue;
1213 }
1214
1215
1216 XmString str = XmStringCreateLocalized(name);
1217 XtVaSetValues(grid,
1218 XmNcolumn,
0,
1219 XmNrow, row,
1220 XmNcellString, str,
NULL);
1221 XmStringFree(str);
1222
1223 char *szbuf = size_str(fsb, e);
1224 str = XmStringCreateLocalized(szbuf);
1225 XtVaSetValues(grid,
1226 XmNcolumn,
1,
1227 XmNrow, row,
1228 XmNcellString, str,
NULL);
1229 free(szbuf);
1230 XmStringFree(str);
1231
1232 char *datebuf = date_str(fsb, e->lastModified);
1233 str = XmStringCreateLocalized(datebuf);
1234 XtVaSetValues(grid,
1235 XmNcolumn,
2,
1236 XmNrow, row,
1237 XmNcellString, str,
NULL);
1238 free(datebuf);
1239 XmStringFree(str);
1240
1241 XtVaSetValues(grid, XmNrow, row, XmNrowUserData, e,
NULL);
1242 row++;
1243 }
1244
1245
1246 if(count > row) {
1247 XmLGridDeleteRows(grid, XmCONTENT, row, count-row);
1248 }
1249
1250 if(maxWidth <
16) {
1251 maxWidth =
16;
1252 }
1253
1254 XtVaSetValues(grid,
1255 XmNcolumnRangeStart,
0,
1256 XmNcolumnRangeEnd,
0,
1257 XmNcolumnWidth, maxWidth,
1258 XmNcellAlignment, XmALIGNMENT_LEFT,
1259 XmNcolumnSizePolicy, XmVARIABLE,
1260 NULL);
1261 XtVaSetValues(grid,
1262 XmNcolumnRangeStart,
1,
1263 XmNcolumnRangeEnd,
1,
1264 XmNcolumnWidth,
9,
1265 XmNcellAlignment, XmALIGNMENT_LEFT,
1266 XmNcolumnSizePolicy, XmVARIABLE,
1267 NULL);
1268 XtVaSetValues(grid,
1269 XmNcolumnRangeStart,
2,
1270 XmNcolumnRangeEnd,
2,
1271 XmNcolumnWidth,
16,
1272 XmNcellAlignment, XmALIGNMENT_RIGHT,
1273 XmNcolumnSizePolicy, XmVARIABLE,
1274 NULL);
1275
1276 FileListDetailAdjustColWidth(grid);
1277 }
1278
1279 static void FileListDetailSelect(Widget fsb, Widget view,
const char *item) {
1280 XnFileSelectionBox w = (XnFileSelectionBox)fsb;
1281
1282 int numRows =
0;
1283 XtVaGetValues(w->fsb.grid, XmNrows, &numRows,
NULL);
1284
1285 XmLGridColumn col = XmLGridGetColumn(w->fsb.grid, XmCONTENT,
0);
1286 for(
int i=
0;i<numRows;i++) {
1287 XmLGridRow row = XmLGridGetRow(w->fsb.grid, XmCONTENT, i);
1288 FileElm *elm =
NULL;
1289 XtVaGetValues(w->fsb.grid, XmNrowPtr, row, XmNcolumnPtr, col, XmNrowUserData, &elm,
NULL);
1290 if(elm) {
1291 if(!strcmp(item, FileName(elm->path))) {
1292 XmLGridSelectRow(w->fsb.grid, i, False);
1293 XmLGridFocusAndShowRow(w->fsb.grid, i
+1);
1294 break;
1295 }
1296 }
1297 }
1298 }
1299
1300 static void FileListDetailCleanup(Widget fsb, Widget view,
void *userData) {
1301 XnFileSelectionBox data = userData;
1302
1303 Cardinal rows =
0;
1304 XtVaGetValues(data->fsb.grid, XmNrows, &rows,
NULL);
1305 XmLGridDeleteRows(data->fsb.grid, XmCONTENT,
0, rows);
1306 }
1307
1308 static void FileListDetailDestroy(Widget fsb, Widget view,
void *userData) {
1309
1310 }
1311 #endif
1312
1313 static void create_folder(Widget w, XnFileSelectionBox data, XmSelectionBoxCallbackStruct *cbs) {
1314 char *fileName =
NULL;
1315 XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &fileName);
1316
1317 char *newFolder = ConcatPath(data->fsb.currentPath ? data->fsb.currentPath :
"", fileName);
1318 if(mkdir(newFolder,
S_IRWXU |
S_IRGRP |
S_IXGRP |
S_IROTH |
S_IXOTH)) {
1319 char errmsg[
256];
1320 snprintf(errmsg,
256, data->fsb.errorFolder, strerror(errno));
1321 ErrDialog(data, data->fsb.errorTitle, errmsg);
1322 }
else {
1323 char *p = strdup(data->fsb.currentPath);
1324 filedialog_update_dir(data, p);
1325 free(p);
1326 }
1327 free(newFolder);
1328
1329 XtDestroyWidget(XtParent(w));
1330 }
1331
1332 static void new_folder_cancel(Widget w, XnFileSelectionBox data, XtPointer d) {
1333 XtDestroyWidget(XtParent(w));
1334 }
1335
1336 static void FSBNewFolder(Widget w, XnFileSelectionBox data, XtPointer u)
1337 {
1338 Arg args[
16];
1339 int n =
0;
1340
1341 XtSetArg(args[n], XmNdialogTitle, data->fsb.labelNewFolder); n++;
1342 XtSetArg (args[n], XmNselectionLabelString, data->fsb.labelDirectoryName); n++;
1343 XtSetArg(args[n], XmNokLabelString, data->fsb.labelOk); n++;
1344 XtSetArg(args[n], XmNcancelLabelString, data->fsb.labelCancel); n++;
1345 Widget dialog = XmCreatePromptDialog (w,
"NewFolderPrompt", args, n);
1346
1347 Widget help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
1348 XtUnmanageChild(help);
1349
1350 XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)create_folder, data);
1351 XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)new_folder_cancel, data);
1352
1353 XtManageChild(dialog);
1354
1355 }
1356
1357 static void FSBHome(Widget w, XnFileSelectionBox data, XtPointer u) {
1358 const char *homePath = data->fsb.homePath ? data->fsb.homePath : GetHomeDir();
1359 filedialog_update_dir(data, homePath);
1360 PathBarSetPath(data->fsb.pathBar, homePath);
1361 }
1362
1363
1364
1365
1366
1367
1368
1369
1370 static int file_cmp_field =
0;
1371
1372
1373
1374
1375 static int file_cmp_order =
1;
1376
1377 static int filecmp(
const void *f1,
const void *f2)
1378 {
1379 const FileElm *file1 = f1;
1380 const FileElm *file2 = f2;
1381 if(file1->isDirectory != file2->isDirectory) {
1382 return file1->isDirectory < file2->isDirectory;
1383 }
1384
1385 int cmp_field = file_cmp_field;
1386 int cmp_order = file_cmp_order;
1387 if(file1->isDirectory) {
1388 cmp_field =
0;
1389 cmp_order =
1;
1390 }
1391
1392 int ret =
0;
1393 switch(cmp_field) {
1394 case 0: {
1395 ret = strcmp(FileName(file1->path), FileName(file2->path));
1396 break;
1397 }
1398 case 1: {
1399 if(file1->size < file2->size) {
1400 ret =
-1;
1401 }
else if(file1->size == file2->size) {
1402 ret =
0;
1403 }
else {
1404 ret =
1;
1405 }
1406 break;
1407 }
1408 case 2: {
1409 if(file1->lastModified < file2->lastModified) {
1410 ret =
-1;
1411 }
else if(file1->lastModified == file2->lastModified) {
1412 ret =
0;
1413 }
else {
1414 ret =
1;
1415 }
1416 break;
1417 }
1418 }
1419
1420 return ret * cmp_order;
1421 }
1422
1423
1424 static void free_files(FileElm *ls,
int count)
1425 {
1426 for(
int i=
0;i<count;i++) {
1427 if(ls[i].path) {
1428 free(ls[i].path);
1429 }
1430 }
1431 free(ls);
1432 }
1433
1434 static void filedialog_cleanup_filedata(XnFileSelectionBox data)
1435 {
1436 free_files(data->fsb.dirs, data->fsb.dircount);
1437 free_files(data->fsb.files, data->fsb.filecount);
1438 data->fsb.dirs =
NULL;
1439 data->fsb.files =
NULL;
1440 data->fsb.dircount =
0;
1441 data->fsb.filecount =
0;
1442 data->fsb.maxnamelen =
0;
1443 }
1444
1445 #define FILE_ARRAY_SIZE 1024
1446
1447 static void file_array_add(FileElm **files,
int *alloc,
int *count, FileElm elm) {
1448 int c = *count;
1449 int a = *alloc;
1450 if(c >= a) {
1451 a *=
2;
1452 FileElm *newarray = realloc(*files,
sizeof(FileElm) * a);
1453
1454 *files = newarray;
1455 *alloc = a;
1456 }
1457
1458 (*files)[c] = elm;
1459 c++;
1460 *count = c;
1461 }
1462
1463 static int filedialog_update_dir(XnFileSelectionBox data,
const char *path)
1464 {
1465 DIR *dir =
NULL;
1466 if(path) {
1467
1468 dir = opendir(path);
1469 if(!dir) {
1470 char errmsg[
256];
1471 snprintf(errmsg,
256, data->fsb.errorOpenDir, strerror(errno));
1472
1473 ErrDialog(data, data->fsb.errorTitle, errmsg);
1474 return 1;
1475 }
1476 }
1477
1478 FSBView view = data->fsb.view[data->fsb.selectedview];
1479 view.cleanup((Widget)data, view.widget, view.userData);
1480
1481 if(view.useDirList) {
1482 XmListDeleteAllItems(data->fsb.dirlist);
1483 }
1484
1485
1486 if(path) {
1487 int dircount =
0;
1488 int filecount =
0;
1489 size_t maxNameLen =
0;
1490
1491 FileElm *dirs = calloc(
sizeof(FileElm),
FILE_ARRAY_SIZE);
1492 FileElm *files = calloc(
sizeof(FileElm),
FILE_ARRAY_SIZE);
1493 int dirs_alloc =
FILE_ARRAY_SIZE;
1494 int files_alloc =
FILE_ARRAY_SIZE;
1495
1496 filedialog_cleanup_filedata(data);
1497
1498
1499 XmTextFieldSetString(data->fsb.path, (
char*)path);
1500 char *oldPath = data->fsb.currentPath;
1501 data->fsb.currentPath = strdup(path);
1502 if(oldPath) {
1503 free(oldPath);
1504 }
1505 path = data->fsb.currentPath;
1506
1507 struct dirent *ent;
1508 while((ent = readdir(dir)) !=
NULL) {
1509 if(!strcmp(ent->d_name,
".") || !strcmp(ent->d_name,
"..")) {
1510 continue;
1511 }
1512
1513 char *entpath = ConcatPath(path, ent->d_name);
1514
1515 struct stat s;
1516 if(stat(entpath, &s)) {
1517 free(entpath);
1518 continue;
1519 }
1520
1521 FileElm new_entry;
1522 new_entry.path = entpath;
1523 new_entry.isDirectory =
S_ISDIR(s.st_mode);
1524 new_entry.size = (
uint64_t)s.st_size;
1525 new_entry.lastModified = s.st_mtime;
1526
1527 size_t nameLen = strlen(ent->d_name);
1528 if(nameLen > maxNameLen) {
1529 maxNameLen = nameLen;
1530 }
1531
1532 if(new_entry.isDirectory) {
1533 file_array_add(&dirs, &dirs_alloc, &dircount, new_entry);
1534 }
else {
1535 file_array_add(&files, &files_alloc, &filecount, new_entry);
1536 }
1537 }
1538 closedir(dir);
1539
1540 data->fsb.dirs = dirs;
1541 data->fsb.files = files;
1542 data->fsb.dircount = dircount;
1543 data->fsb.filecount = filecount;
1544 data->fsb.maxnamelen = maxNameLen;
1545
1546
1547 qsort(dirs, dircount,
sizeof(FileElm), filecmp);
1548 qsort(files, filecount,
sizeof(FileElm), filecmp);
1549 }
1550
1551 Widget filterTF = XmDropDownGetText(data->fsb.filter);
1552 char *filter = XmTextFieldGetString(filterTF);
1553 char *filterStr = filter;
1554 if(!filter || strlen(filter) ==
0) {
1555 filterStr =
"*";
1556 }
1557
1558 if(view.useDirList) {
1559 FileListWidgetAdd(data, data->fsb.dirlist, data->fsb.showHidden,
NULL, data->fsb.dirs, data->fsb.dircount);
1560 view.update(
1561 (Widget)data,
1562 view.widget,
1563 NULL,
1564 0,
1565 data->fsb.files,
1566 data->fsb.filecount,
1567 filterStr,
1568 data->fsb.maxnamelen,
1569 view.userData);
1570 }
else {
1571 view.update(
1572 (Widget)data,
1573 view.widget,
1574 data->fsb.dirs,
1575 data->fsb.dircount,
1576 data->fsb.files,
1577 data->fsb.filecount,
1578 filterStr,
1579 data->fsb.maxnamelen,
1580 view.userData);
1581 }
1582
1583 if(filter) {
1584 XtFree(filter);
1585 }
1586
1587 return 0;
1588 }
1589
1590
1591 static void dirlist_activate(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb)
1592 {
1593 char *path = set_selected_path(data, cb->item);
1594 if(path) {
1595 if(!filedialog_update_dir(data, path)) {
1596 PathBarSetPath(data->fsb.pathBar, path);
1597 data->fsb.selIsDir =
TRUE;
1598 }
1599 }
1600 }
1601
1602 static void dirlist_select(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb)
1603 {
1604 char *path = set_selected_path(data, cb->item);
1605 if(path) {
1606 data->fsb.selIsDir =
TRUE;
1607 }
1608 }
1609
1610 static void filedialog_enable_detailview(Widget w, XnFileSelectionBox data, XmToggleButtonCallbackStruct *tb) {
1611 SelectView(data, tb->set);
1612 }
1613
1614
1615 static void filedialog_setshowhidden(
1616 Widget w,
1617 XnFileSelectionBox data,
1618 XmToggleButtonCallbackStruct *tb)
1619 {
1620 data->fsb.showHidden = tb->set;
1621 filedialog_update_dir(data,
NULL);
1622 }
1623
1624 static void filedialog_filter(Widget w, XnFileSelectionBox data, XtPointer c)
1625 {
1626 filedialog_update_dir(data,
NULL);
1627 }
1628
1629 static void filedialog_update_filter(Widget w, XnFileSelectionBox data, XtPointer c)
1630 {
1631 filedialog_update_dir(data,
NULL);
1632
1633 }
1634
1635 static void filedialog_goup(Widget w, XnFileSelectionBox data, XtPointer d)
1636 {
1637 char *newPath = ParentPath(data->fsb.currentPath);
1638 filedialog_update_dir(data, newPath);
1639 PathBarSetPath(data->fsb.pathBar, newPath);
1640 free(newPath);
1641 }
1642
1643 static void filedialog_ok(Widget w, XnFileSelectionBox data, XtPointer d)
1644 {
1645 if(data->fsb.type ==
FILEDIALOG_SAVE) {
1646 char *newName = XmTextFieldGetString(data->fsb.name);
1647 if(newName) {
1648 if(strchr(newName,
'/')) {
1649 ErrDialog(data, data->fsb.errorTitle, data->fsb.errorIllegalChar);
1650 XtFree(newName);
1651 return;
1652 }
1653
1654 if(strlen(newName) >
0) {
1655 char *selPath = ConcatPath(data->fsb.currentPath, newName);
1656 if(data->fsb.selectedPath) free(data->fsb.selectedPath);
1657 data->fsb.selectedPath = selPath;
1658 }
1659 XtFree(newName);
1660
1661 data->fsb.selIsDir = False;
1662 }
1663 }
1664
1665 if(data->fsb.selectedPath) {
1666 if(!data->fsb.selIsDir) {
1667 data->fsb.status =
FILEDIALOG_OK;
1668 data->fsb.end = True;
1669 FileSelectionCallback(data, data->fsb.okCallback, XmCR_OK, data->fsb.selectedPath);
1670 }
1671 }
1672 }
1673
1674 static void filedialog_cancel(Widget w, XnFileSelectionBox data, XtPointer d)
1675 {
1676 data->fsb.end =
1;
1677 data->fsb.status =
FILEDIALOG_CANCEL;
1678 FileSelectionCallback(data, data->fsb.cancelCallback, XmCR_CANCEL, data->fsb.currentPath);
1679 }
1680
1681 static void filedialog_help(Widget w, XnFileSelectionBox data, XtPointer d)
1682 {
1683 FileSelectionCallback(data, data->manager.help_callback, XmCR_HELP, data->fsb.currentPath);
1684 }
1685
1686 static void FileSelectionCallback(XnFileSelectionBox fsb, XtCallbackList cb,
int reason,
const char *value) {
1687 XmFileSelectionBoxCallbackStruct cbs;
1688 memset(&cbs,
0,
sizeof(XmFileSelectionBoxCallbackStruct));
1689
1690 char *dir = fsb->fsb.currentPath;
1691 size_t dirlen = dir ? strlen(dir) :
0;
1692 if(dir && dirlen >
0) {
1693 char *dir2 =
NULL;
1694 if(dir[dirlen
-1] !=
'/') {
1695
1696 dir2 = malloc(dirlen
+2);
1697 memcpy(dir2, dir, dirlen);
1698 dir2[dirlen] =
'/';
1699 dir2[dirlen
+1] =
'\0';
1700 dirlen++;
1701 dir = dir2;
1702 }
1703 cbs.dir = XmStringCreateLocalized(dir);
1704 cbs.dir_length = dirlen;
1705 if(dir2) {
1706 free(dir2);
1707 }
1708 }
else {
1709 cbs.dir = XmStringCreateLocalized(
"");
1710 cbs.dir_length =
0;
1711 }
1712 cbs.reason = reason;
1713
1714 cbs.value = XmStringCreateLocalized((
char*)value);
1715 cbs.length = strlen(value);
1716
1717 XtCallCallbackList((Widget)fsb, cb, (XtPointer)&cbs);
1718
1719 XmStringFree(cbs.dir);
1720 XmStringFree(cbs.value);
1721 }
1722
1723 static void CreateUI(XnFileSelectionBox w) {
1724 Arg args[
32];
1725 int n =
0;
1726 XmString str;
1727
1728 int widget_spacing = w->fsb.widgetSpacing;
1729 int window_spacing = w->fsb.windowSpacing;
1730
1731 Widget form = (Widget)w;
1732 int type = w->fsb.type;
1733
1734 XtVaSetValues((Widget)w, XmNautoUnmanage, False,
NULL);
1735
1736
1737
1738 n =
0;
1739 XtSetArg(args[n], XmNlabelString, w->fsb.labelDirUp); n++;
1740 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1741 XtSetArg(args[n], XmNtopOffset, window_spacing); n++;
1742 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1743 XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
1744 XtSetArg(args[n], XmNresizable, True); n++;
1745 XtSetArg(args[n], XmNarrowDirection, XmARROW_UP); n++;
1746 w->fsb.dirUp = XmCreatePushButton(form,
"DirUp", args, n);
1747 XtManageChild(w->fsb.dirUp);
1748 XtAddCallback(w->fsb.dirUp, XmNactivateCallback,
1749 (XtCallbackProc)filedialog_goup, w);
1750
1751
1752 n =
0;
1753 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1754 XtSetArg(args[n], XmNtopOffset, window_spacing); n++;
1755 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1756 XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
1757 XtSetArg(args[n], XmNshadowThickness,
0); n++;
1758 Widget viewframe = XmCreateForm(form,
"vframe", args, n);
1759 XtManageChild(viewframe);
1760
1761 w->fsb.viewMenu = XmCreatePulldownMenu(viewframe,
"menu",
NULL,
0);
1762
1763 Widget view;
1764 if(w->fsb.showViewMenu) {
1765 n =
0;
1766 XtSetArg(args[n], XmNsubMenuId, w->fsb.viewMenu); n++;
1767 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1768 XtSetArg(args[n], XmNmarginHeight,
0); n++;
1769 XtSetArg(args[n], XmNmarginWidth,
0); n++;
1770 view = XmCreateOptionMenu(viewframe,
"option_menu", args, n);
1771 XtManageChild(view);
1772 w->fsb.viewOption = view;
1773 w->fsb.detailToggleButton =
NULL;
1774 }
else {
1775 n =
0;
1776 str = XmStringCreateLocalized(w->fsb.labelDetailView);
1777 XtSetArg(args[n], XmNlabelString, str); n++;
1778 XtSetArg(args[n], XmNfillOnSelect, True); n++;
1779 XtSetArg(args[n], XmNindicatorOn, False); n++;
1780 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1781 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1782 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1783 if(w->fsb.selectedview ==
1) {
1784 XtSetArg(args[n], XmNset,
1); n++;
1785 }
1786 w->fsb.detailToggleButton = XmCreateToggleButton(viewframe,
"ToggleDetailView", args, n);
1787 XtManageChild(w->fsb.detailToggleButton);
1788 view = w->fsb.detailToggleButton;
1789 XmStringFree(str);
1790
1791 XtAddCallback(
1792 w->fsb.detailToggleButton,
1793 XmNvalueChangedCallback,
1794 (XtCallbackProc)filedialog_enable_detailview,
1795 w);
1796
1797 w->fsb.viewOption =
NULL;
1798 }
1799
1800 n =
0;
1801 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1802 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1803 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1804 XtSetArg(args[n], XmNrightWidget, view); n++;
1805 XtSetArg(args[n], XmNmarginHeight,
0); n++;
1806 XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
1807 XtSetArg(args[n], XmNlabelString, w->fsb.labelNewFolder); n++;
1808 w->fsb.newFolder = XmCreatePushButton(viewframe,
"NewFolder", args, n);
1809 XtManageChild(w->fsb.newFolder);
1810 XtAddCallback(
1811 w->fsb.newFolder,
1812 XmNactivateCallback,
1813 (XtCallbackProc)FSBNewFolder,
1814 w);
1815
1816
1817 n =
0;
1818 XtSetArg(args[n], XmNlabelString, w->fsb.labelHome); n++;
1819 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1820 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1821 XtSetArg(args[n], XmNrightWidget, w->fsb.newFolder); n++;
1822 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1823 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1824 w->fsb.home = XmCreatePushButton(viewframe,
"Home", args, n);
1825 XtManageChild(w->fsb.home);
1826 XtAddCallback(
1827 w->fsb.home,
1828 XmNactivateCallback,
1829 (XtCallbackProc)FSBHome,
1830 w);
1831
1832
1833 if(w->fsb.detailToggleButton) {
1834 Dimension highlight, shadow;
1835 XtVaGetValues(w->fsb.newFolder, XmNshadowThickness, &shadow, XmNhighlightThickness, &highlight,
NULL);
1836 XtVaSetValues(w->fsb.detailToggleButton, XmNshadowThickness, shadow, XmNhighlightThickness, highlight,
NULL);
1837 }
1838
1839
1840 n =
0;
1841 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1842 XtSetArg(args[n], XmNtopOffset, window_spacing); n++;
1843 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
1844 XtSetArg(args[n], XmNleftWidget, w->fsb.dirUp); n++;
1845 XtSetArg(args[n], XmNleftOffset, widget_spacing); n++;
1846 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1847 XtSetArg(args[n], XmNrightWidget, viewframe); n++;
1848 XtSetArg(args[n], XmNrightOffset, widget_spacing); n++;
1849 XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); n++;
1850 Widget pathBarFrame = XmCreateFrame(form,
"pathbar_frame", args, n);
1851 XtManageChild(pathBarFrame);
1852 w->fsb.pathBar = CreatePathBar(pathBarFrame, args,
0);
1853 w->fsb.pathBar->getpathelm = ui_default_pathelm_func;
1854 w->fsb.pathBar->updateDir = (updatedir_callback)filedialog_update_dir;
1855 w->fsb.pathBar->updateDirData = w;
1856 XtManageChild(w->fsb.pathBar->widget);
1857 w->fsb.path = XmCreateTextField(form,
"textfield", args,
0);
1858
1859 XtVaSetValues(w->fsb.dirUp, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, pathBarFrame,
NULL);
1860 if(!w->fsb.showViewMenu) {
1861 XtVaSetValues(viewframe, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, pathBarFrame,
NULL);
1862 }
1863
1864 n =
0;
1865 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1866 XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
1867 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1868 XtSetArg(args[n], XmNtopWidget, pathBarFrame); n++;
1869 XtSetArg(args[n], XmNtopOffset,
2*widget_spacing); n++;
1870 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1871 XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
1872 w->fsb.filterForm = XmCreateForm(form,
"filterform", args, n);
1873 XtManageChild(w->fsb.filterForm);
1874
1875 n =
0;
1876 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1877 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1878 XtSetArg(args[n], XmNlabelString, w->fsb.labelDirectories); n++;
1879 w->fsb.lsDirLabel = XmCreateLabel(w->fsb.filterForm,
"labelDirs", args, n);
1880 XtManageChild(w->fsb.lsDirLabel);
1881
1882 n =
0;
1883 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1884 XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
1885 XtSetArg(args[n], XmNleftPosition,
35); n++;
1886 XtSetArg(args[n], XmNleftOffset, widget_spacing); n++;
1887 XtSetArg(args[n], XmNlabelString, w->fsb.labelFiles); n++;
1888 w->fsb.lsFileLabel = XmCreateLabel(w->fsb.filterForm,
"labelFiles", args, n);
1889 XtManageChild(w->fsb.lsFileLabel);
1890
1891 if(w->fsb.showHiddenButton) {
1892 n =
0;
1893 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1894 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1895 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1896 XtSetArg(args[n], XmNlabelString, w->fsb.labelShowHiddenFiles); n++;
1897 XtSetArg(args[n], XmNset, w->fsb.showHidden); n++;
1898 w->fsb.showHiddenButtonW = XmCreateToggleButton(w->fsb.filterForm,
"showHidden", args, n);
1899 XtManageChild(w->fsb.showHiddenButtonW);
1900 XtAddCallback(w->fsb.showHiddenButtonW, XmNvalueChangedCallback,
1901 (XtCallbackProc)filedialog_setshowhidden, w);
1902 }
1903
1904 n =
0;
1905 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1906 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1907 XtSetArg(args[n], XmNlabelString, w->fsb.labelFilterButton); n++;
1908 if(w->fsb.showHiddenButton) {
1909 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1910 XtSetArg(args[n], XmNrightWidget, w->fsb.showHiddenButtonW); n++;
1911 }
else {
1912 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1913 }
1914 w->fsb.filterButton = XmCreatePushButton(w->fsb.filterForm,
"filedialog_filter", args, n);
1915 XtManageChild(w->fsb.filterButton);
1916 XtAddCallback(w->fsb.filterButton, XmNactivateCallback,
1917 (XtCallbackProc)filedialog_filter, w);
1918
1919 n =
0;
1920 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1921 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1922 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
1923 XtSetArg(args[n], XmNleftWidget, w->fsb.lsFileLabel); n++;
1924 XtSetArg(args[n], XmNleftOffset, widget_spacing); n++;
1925 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1926 XtSetArg(args[n], XmNrightWidget, w->fsb.filterButton); n++;
1927 XtSetArg(args[n], XmNrightOffset, widget_spacing); n++;
1928 XtSetArg(args[n], XmNshowLabel, False); n++;
1929 XtSetArg(args[n], XmNuseTextField, True); n++;
1930 XtSetArg(args[n], XmNverify, False); n++;
1931 w->fsb.filter = XmCreateDropDown(w->fsb.filterForm,
"filedialog_filter_textfield", args, n);
1932 XtManageChild(w->fsb.filter);
1933 XmTextFieldSetString(XmDropDownGetText(w->fsb.filter), w->fsb.filterStr);
1934 XtAddCallback(XmDropDownGetText(w->fsb.filter), XmNactivateCallback,
1935 (XtCallbackProc)filedialog_filter, w);
1936 XtAddCallback(w->fsb.filter, XmNupdateTextCallback,
1937 (XtCallbackProc)filedialog_update_filter, w);
1938 Widget filterList = XmDropDownGetList(w->fsb.filter);
1939 str = XmStringCreateSimple(
"*");
1940 XmListAddItem(filterList, str,
0);
1941 XmStringFree(str);
1942
1943
1944 n =
0;
1945 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1946 XtSetArg(args[n], XmNbottomOffset, window_spacing); n++;
1947 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1948 XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
1949 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1950 XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
1951 XtSetArg(args[n], XmNtopOffset, widget_spacing *
2); n++;
1952 Widget buttons = XmCreateForm(form,
"buttons", args, n);
1953 XtManageChild(buttons);
1954
1955 n =
0;
1956 str = type ==
FILEDIALOG_OPEN ? w->fsb.labelOpen : w->fsb.labelSave;
1957 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1958 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1959 XtSetArg(args[n], XmNlabelString, str); n++;
1960 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1961 XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
1962 XtSetArg(args[n], XmNrightPosition,
14); n++;
1963 w->fsb.okBtn = XmCreatePushButton(buttons,
"filedialog_open", args, n);
1964 XtManageChild(w->fsb.okBtn);
1965 XmStringFree(str);
1966 XtAddCallback(w->fsb.okBtn, XmNactivateCallback,
1967 (XtCallbackProc)filedialog_ok, w);
1968
1969 n =
0;
1970 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1971 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1972 XtSetArg(args[n], XmNlabelString, w->fsb.labelHelp); n++;
1973 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1974 XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
1975 XtSetArg(args[n], XmNleftPosition,
86); n++;
1976 w->fsb.helpBtn = XmCreatePushButton(buttons,
"filedialog_help", args, n);
1977 XtManageChild(w->fsb.helpBtn);
1978 XtAddCallback(w->fsb.helpBtn, XmNactivateCallback,
1979 (XtCallbackProc)filedialog_help, w);
1980
1981 n =
0;
1982 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1983 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1984 XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
1985 XtSetArg(args[n], XmNleftPosition,
43); n++;
1986 XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
1987 XtSetArg(args[n], XmNrightPosition,
57); n++;
1988 XtSetArg(args[n], XmNlabelString, w->fsb.labelCancel); n++;
1989 w->fsb.cancelBtn = XmCreatePushButton(buttons,
"filedialog_cancel", args, n);
1990 XtManageChild(w->fsb.cancelBtn);
1991 XtAddCallback(w->fsb.cancelBtn, XmNactivateCallback,
1992 (XtCallbackProc)filedialog_cancel, w);
1993
1994 n =
0;
1995 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
1996 XtSetArg(args[n], XmNbottomWidget, buttons); n++;
1997 XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
1998 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1999 XtSetArg(args[n], XmNleftOffset,
1); n++;
2000 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2001 XtSetArg(args[n], XmNrightOffset,
1); n++;
2002 w->fsb.separator = XmCreateSeparator(form,
"ofd_separator", args, n);
2003 XtManageChild(w->fsb.separator);
2004
2005 Widget bottomWidget = w->fsb.separator;
2006
2007 n =
0;
2008 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2009 XtSetArg(args[n], XmNbottomWidget, w->fsb.separator); n++;
2010 XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
2011 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2012 XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
2013 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2014 XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
2015 w->fsb.name = XmCreateTextField(form,
"textfield", args, n);
2016 XtAddCallback(w->fsb.name, XmNactivateCallback,
2017 (XtCallbackProc)filedialog_ok, w);
2018
2019 n =
0;
2020 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2021 XtSetArg(args[n], XmNbottomWidget, w->fsb.name); n++;
2022 XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
2023 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2024 XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
2025 XtSetArg(args[n], XmNlabelString, w->fsb.labelFileName); n++;
2026 w->fsb.nameLabel = XmCreateLabel(form,
"label", args, n);
2027
2028 if(type ==
FILEDIALOG_SAVE) {
2029 bottomWidget = w->fsb.nameLabel;
2030 XtManageChild(w->fsb.name);
2031 XtManageChild(w->fsb.nameLabel);
2032 }
2033 w->fsb.bottom_widget = bottomWidget;
2034
2035
2036
2037
2038 n =
0;
2039 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2040 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2041 XtSetArg(args[n], XmNtopWidget, w->fsb.filterForm); n++;
2042 XtSetArg(args[n], XmNtopOffset, widget_spacing); n++;
2043 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2044 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2045 XtSetArg(args[n], XmNbottomWidget, bottomWidget); n++;
2046 XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
2047 XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
2048 XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
2049 XtSetArg(args[n], XmNwidth,
580); n++;
2050 XtSetArg(args[n], XmNheight,
400); n++;
2051 w->fsb.listform = XmCreateForm(form,
"fds_listform", args, n);
2052
2053
2054
2055 n =
0;
2056 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2057 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2058 XtSetArg(args[n], XmNtopWidget, w->fsb.lsDirLabel); n++;
2059 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2060 XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
2061 XtSetArg(args[n], XmNrightPosition,
35); n++;
2062 w->fsb.dirlist = XmCreateScrolledList(w->fsb.listform,
"dirlist", args, n);
2063 Dimension width, height;
2064 XtMakeResizeRequest(w->fsb.dirlist,
150,
200, &width, &height);
2065 XtManageChild(w->fsb.dirlist);
2066
2067 XtAddCallback(
2068 w->fsb.dirlist,
2069 XmNdefaultActionCallback,
2070 (XtCallbackProc)dirlist_activate,
2071 w);
2072 XtAddCallback(
2073 w->fsb.dirlist,
2074 XmNbrowseSelectionCallback,
2075 (XtCallbackProc)dirlist_select,
2076 w);
2077
2078
2079 XnFileSelectionBoxAddView(
2080 (Widget)w,
2081 w->fsb.labelListView,
2082 CreateListView,
2083 FileListUpdate,
2084 FileListSelect,
2085 FileListCleanup,
2086 FileListDestroy,
2087 True,
2088 w);
2089
2090
2091 #ifdef FSB_ENABLE_DETAIL
2092 XnFileSelectionBoxAddView(
2093 (Widget)w,
2094 w->fsb.labelDetailView,
2095 CreateDetailView,
2096 FileListDetailUpdate,
2097 FileListDetailSelect,
2098 FileListDetailCleanup,
2099 FileListDetailDestroy,
2100 True,
2101 w);
2102 #endif
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118 XtManageChild(w->fsb.listform);
2119
2120 int selview = w->fsb.selectedview;
2121 if(selview <
2) {
2122 XtManageChild(w->fsb.view[selview].widget);
2123 }
else {
2124 w->fsb.selectedview =
0;
2125 }
2126
2127
2128 if(w->fsb.selectedPath) {
2129 char *parentPath = ParentPath(w->fsb.selectedPath);
2130 filedialog_update_dir(w, parentPath);
2131 PathBarSetPath(w->fsb.pathBar, parentPath);
2132 free(parentPath);
2133
2134 if(w->fsb.type ==
FILEDIALOG_SAVE) {
2135 XmTextFieldSetString(w->fsb.name, FileName(w->fsb.selectedPath));
2136 }
2137 }
else {
2138 char cwd[
PATH_MAX];
2139 const char *currentPath = w->fsb.currentPath;
2140 if(!currentPath) {
2141 if(getcwd(cwd,
PATH_MAX)) {
2142 currentPath = cwd;
2143 }
else {
2144 currentPath = GetHomeDir();
2145 }
2146 }
2147
2148 filedialog_update_dir(w, currentPath);
2149 PathBarSetPath(w->fsb.pathBar, w->fsb.currentPath);
2150 }
2151
2152
2153 w->fsb.selectedview = selview;
2154
2155 XtVaSetValues((Widget)w, XmNcancelButton, w->fsb.cancelBtn,
NULL);
2156
2157 w->fsb.gui_created =
1;
2158 }
2159
2160 static char* FSBDialogTitle(Widget widget) {
2161 XnFileSelectionBox w = (XnFileSelectionBox)widget;
2162 if(w->fsb.type ==
FILEDIALOG_OPEN) {
2163 return w->fsb.labelOpenFileTitle;
2164 }
else {
2165 return w->fsb.labelSaveFileTitle;
2166 }
2167 }
2168
2169 static FSBViewWidgets CreateView(XnFileSelectionBox w, FSBViewCreateProc create,
void *userData, Boolean useDirList) {
2170 Arg args[
64];
2171 int n =
0;
2172
2173 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2174 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2175 if(useDirList) {
2176 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2177 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
2178 XtSetArg(args[n], XmNleftWidget, w->fsb.dirlist); n++;
2179 XtSetArg(args[n], XmNleftOffset, w->fsb.widgetSpacing); n++;
2180 }
else {
2181 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2182 XtSetArg(args[n], XmNtopOffset, w->fsb.widgetSpacing); n++;
2183 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2184 }
2185
2186 return create(w->fsb.listform, args, n, userData);
2187 }
2188
2189
2190 typedef struct FSBViewSelection {
2191 XnFileSelectionBox fsb;
2192 int index;
2193 } FSBViewSelection;
2194
2195 static void SelectView(XnFileSelectionBox f,
int view) {
2196 FSBView current = f->fsb.view[f->fsb.selectedview];
2197 FSBView newview = f->fsb.view[view];
2198
2199 XtUnmanageChild(current.widget);
2200 if(newview.useDirList != current.useDirList) {
2201 if(current.useDirList) {
2202 XtUnmanageChild(f->fsb.listform);
2203 }
else {
2204 XtManageChild(f->fsb.listform);
2205 }
2206 }
2207
2208 current.cleanup((Widget)f, current.widget, current.userData);
2209 XtManageChild(newview.widget);
2210
2211 f->fsb.selectedview = view;
2212
2213 filedialog_update_dir(f,
NULL);
2214 XmProcessTraversal(newview.focus, XmTRAVERSE_CURRENT);
2215 }
2216
2217 static void SelectViewCallback(Widget w, FSBViewSelection *data, XtPointer u) {
2218 SelectView(data->fsb, data->index);
2219 }
2220
2221 static void SelectViewItemDestroy(Widget w, FSBViewSelection *data, XtPointer u) {
2222 free(data);
2223 }
2224
2225 static void AddViewMenuItem(XnFileSelectionBox w,
const char *name,
int viewIndex) {
2226 Arg args[
4];
2227 int n =
0;
2228
2229 XmString label = XmStringCreateLocalized((
char*)name);
2230
2231 XtSetArg(args[n], XmNlabelString, label); n++;
2232 XtSetArg(args[
1], XmNpositionIndex, w->fsb.selectedview == w->fsb.numviews ?
0 : w->fsb.numviews
+1); n++;
2233 Widget item = XmCreatePushButton(w->fsb.viewMenu,
"menuitem", args, n);
2234
2235 if(viewIndex ==
0) {
2236 w->fsb.viewSelectorList = item;
2237 }
else if(viewIndex ==
1) {
2238 w->fsb.viewSelectorDetail = item;
2239 }
2240
2241 XtManageChild(item);
2242 XmStringFree(label);
2243
2244 FSBViewSelection *data = malloc(
sizeof(FSBViewSelection));
2245 data->fsb = w;
2246 data->index = viewIndex;
2247
2248 XtAddCallback(
2249 item,
2250 XmNactivateCallback,
2251 (XtCallbackProc)SelectViewCallback,
2252 data);
2253 XtAddCallback(
2254 item,
2255 XmNdestroyCallback,
2256 (XtCallbackProc)SelectViewItemDestroy,
2257 data);
2258 }
2259
2260 static FSBViewWidgets CreateListView(Widget parent, ArgList args,
int n,
void *userData) {
2261 XnFileSelectionBox fsb = (XnFileSelectionBox)userData;
2262
2263 XtSetArg(args[n], XmNshadowThickness,
0); n++;
2264 Widget frame = XmCreateFrame(parent,
"filelistframe", args, n);
2265
2266 fsb->fsb.filelist = XmCreateScrolledList(frame,
"filelist",
NULL,
0);
2267 XtManageChild(fsb->fsb.filelist);
2268
2269 XtAddCallback(
2270 fsb->fsb.filelist,
2271 XmNdefaultActionCallback,
2272 (XtCallbackProc)FileListActivateCB,
2273 userData);
2274 XtAddCallback(
2275 fsb->fsb.filelist,
2276 XmNbrowseSelectionCallback,
2277 (XtCallbackProc)FileListSelectCB,
2278 userData);
2279
2280 fsb->fsb.listContextMenu = CreateContextMenu(fsb, fsb->fsb.filelist, FileContextMenuCB);
2281
2282 FSBViewWidgets widgets;
2283 widgets.view = frame;
2284 widgets.focus = fsb->fsb.filelist;
2285 return widgets;
2286 }
2287
2288 #ifdef FSB_ENABLE_DETAIL
2289 static void set_path_from_row(XnFileSelectionBox data,
int row) {
2290 FileElm *elm =
NULL;
2291 XmLGridRow rowPtr = XmLGridGetRow(data->fsb.grid, XmCONTENT, row);
2292 XtVaGetValues(data->fsb.grid, XmNrowPtr, rowPtr, XmNrowUserData, &elm,
NULL);
2293 if(!elm) {
2294 fprintf(stderr,
"error: no row data\n");
2295 return;
2296 }
2297
2298 char *path = strdup(elm->path);
2299
2300 data->fsb.selIsDir = False;
2301 if(data->fsb.type ==
FILEDIALOG_SAVE) {
2302 XmTextFieldSetString(data->fsb.name, FileName(path));
2303 }
2304
2305 if(data->fsb.selectedPath) {
2306 free(data->fsb.selectedPath);
2307 }
2308 data->fsb.selectedPath = path;
2309 }
2310
2311 static void grid_select(Widget w, XnFileSelectionBox data, XmLGridCallbackStruct *cb) {
2312 set_path_from_row(data, cb->row);
2313 }
2314
2315 static void grid_activate(Widget w, XnFileSelectionBox data, XmLGridCallbackStruct *cb) {
2316 set_path_from_row(data, cb->row);
2317 data->fsb.end = True;
2318 data->fsb.status =
FILEDIALOG_OK;
2319
2320 FileSelectionCallback(data, data->fsb.okCallback, XmCR_OK, data->fsb.selectedPath);
2321 }
2322
2323 static void grid_key_pressed(Widget w, XnFileSelectionBox data, XmLGridCallbackStruct *cb) {
2324 char chars[
16];
2325 KeySym keysym;
2326 int nchars;
2327
2328 nchars = XLookupString(&cb->event->xkey, chars,
15, &keysym,
NULL);
2329
2330 if(nchars ==
0)
return;
2331
2332
2333
2334
2335
2336 int row =
0;
2337 int selectedRow = XmLGridGetSelectedRow(w);
2338
2339 int match =
-1;
2340
2341 for(
int i=
0;i<data->fsb.filecount;i++) {
2342 const char *name = FileName(data->fsb.files[i].path);
2343 if(!data->fsb.showHidden && name[
0] ==
'.')
continue;
2344
2345 size_t namelen = strlen(name);
2346
2347 size_t cmplen = namelen < nchars ? namelen : nchars;
2348 if(!memcmp(name, chars, cmplen)) {
2349 if(row <= selectedRow) {
2350 if(match ==
-1) {
2351 match = row;
2352 }
2353 }
else {
2354 match = row;
2355 break;
2356 }
2357 }
2358
2359 row++;
2360 }
2361
2362 if(match >
-1) {
2363 XmLGridSelectRow(w, match, True);
2364 XmLGridFocusAndShowRow(w, match
+1);
2365 }
else {
2366 XBell(XtDisplay(w),
0);
2367 }
2368 }
2369
2370 static void grid_header_clicked(Widget w, XnFileSelectionBox data, XmLGridCallbackStruct *cb) {
2371 int new_cmp_field =
0;
2372 switch(cb->column) {
2373 case 0: {
2374 new_cmp_field =
0;
2375 break;
2376 }
2377 case 1: {
2378 new_cmp_field =
1;
2379 break;
2380 }
2381 case 2: {
2382 new_cmp_field =
2;
2383 break;
2384 }
2385 }
2386
2387 if(new_cmp_field == file_cmp_field) {
2388 file_cmp_order = -file_cmp_order;
2389 }
else {
2390 file_cmp_field = new_cmp_field;
2391 file_cmp_order =
1;
2392 }
2393
2394 int sort_type = file_cmp_order ==
1 ? XmSORT_ASCENDING : XmSORT_DESCENDING;
2395 XmLGridSetSort(data->fsb.grid, file_cmp_field, sort_type);
2396
2397 qsort(data->fsb.files, data->fsb.filecount,
sizeof(FileElm), filecmp);
2398
2399
2400 filedialog_update_dir(data,
NULL);
2401 }
2402
2403 static FSBViewWidgets CreateDetailView(Widget parent, ArgList args,
int n,
void *userData) {
2404 XnFileSelectionBox w = userData;
2405
2406 XtSetArg(args[n], XmNshadowThickness,
0); n++;
2407 Widget gridcontainer = XmCreateFrame(parent,
"gridcontainer", args, n);
2408 XtManageChild(gridcontainer);
2409
2410 n =
0;
2411 XtSetArg(args[n], XmNcolumns,
3); n++;
2412 XtSetArg(args[n], XmNheadingColumns,
0); n++;
2413 XtSetArg(args[n], XmNheadingRows,
1); n++;
2414 XtSetArg(args[n], XmNallowColumnResize,
1); n++;
2415 XtSetArg(args[n], XmNsimpleHeadings, w->fsb.detailHeadings); n++;
2416 XtSetArg(args[n], XmNhorizontalSizePolicy, XmCONSTANT); n++;
2417
2418 w->fsb.grid = XmLCreateGrid(gridcontainer,
"grid", args, n);
2419 XmLGridSetIgnoreModifyVerify(w->fsb.grid, True);
2420 XtManageChild(w->fsb.grid);
2421
2422 XtVaSetValues(
2423 w->fsb.grid,
2424 XmNcellDefaults, True,
2425 XtVaTypedArg, XmNblankBackground, XmRString,
"white",
6,
2426 XtVaTypedArg, XmNcellBackground, XmRString,
"white",
6,
2427 NULL);
2428
2429 XtAddCallback(w->fsb.grid, XmNselectCallback, (XtCallbackProc)grid_select, w);
2430 XtAddCallback(w->fsb.grid, XmNactivateCallback, (XtCallbackProc)grid_activate, w);
2431 XtAddCallback(w->fsb.grid, XmNheaderClickCallback, (XtCallbackProc)grid_header_clicked, w);
2432 XtAddCallback(w->fsb.grid, XmNgridKeyPressedCallback, (XtCallbackProc)grid_key_pressed, w);
2433
2434
2435 w->fsb.gridContextMenu = CreateContextMenu(w, w->fsb.grid, FileContextMenuCB);
2436
2437 FSBViewWidgets widgets;
2438 widgets.view = gridcontainer;
2439 widgets.focus = w->fsb.grid;
2440 return widgets;
2441 }
2442 #endif
2443
2444
2445
2446
2447 const char* GetHomeDir(
void) {
2448 char *home = getenv(
"HOME");
2449 if(!home) {
2450 home = getenv(
"USERPROFILE");
2451 if(!home) {
2452 home =
"/";
2453 }
2454 }
2455 return home;
2456 }
2457
2458 static char* ConcatPath(
const char *parent,
const char *name)
2459 {
2460 size_t parentlen = strlen(parent);
2461 size_t namelen = strlen(name);
2462
2463 size_t pathlen = parentlen + namelen +
2;
2464 char *path = malloc(pathlen);
2465
2466 memcpy(path, parent, parentlen);
2467 if(parentlen >
0 && parent[parentlen
-1] !=
'/') {
2468 path[parentlen] =
'/';
2469 parentlen++;
2470 }
2471 if(name[
0] ==
'/') {
2472 name++;
2473 namelen--;
2474 }
2475 memcpy(path+parentlen, name, namelen);
2476 path[parentlen+namelen] =
'\0';
2477 return path;
2478 }
2479
2480 static char* FileName(
char *path) {
2481 int si =
0;
2482 int osi =
0;
2483 int i =
0;
2484 int p =
0;
2485 char c;
2486 while((c = path[i]) !=
0) {
2487 if(c ==
'/') {
2488 osi = si;
2489 si = i;
2490 p =
1;
2491 }
2492 i++;
2493 }
2494
2495 char *name = path + si + p;
2496 if(name[
0] ==
0) {
2497 name = path + osi + p;
2498 if(name[
0] ==
0) {
2499 return path;
2500 }
2501 }
2502
2503 return name;
2504 }
2505
2506 static char* ParentPath(
const char *path) {
2507 char *name = FileName((
char*)path);
2508 size_t namelen = strlen(name);
2509 size_t pathlen = strlen(path);
2510 size_t parentlen = pathlen - namelen;
2511 if(parentlen ==
0) {
2512 parentlen++;
2513 }
2514 char *parent = malloc(parentlen +
1);
2515 memcpy(parent, path, parentlen);
2516 parent[parentlen] =
'\0';
2517 return parent;
2518 }
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537 Widget XnCreateFileSelectionDialog(
2538 Widget parent,
2539 String name,
2540 ArgList arglist,
2541 Cardinal argcount)
2542 {
2543 Widget dialog = XmCreateDialogShell(parent,
"FileDialog",
NULL,
0);
2544 Widget fsb = XnCreateFileSelectionBox(dialog, name, arglist, argcount);
2545 char *title = FSBDialogTitle(fsb);
2546 XtVaSetValues(dialog, XmNtitle, title,
NULL);
2547 return fsb;
2548 }
2549
2550 Widget XnCreateFileSelectionBox(
2551 Widget parent,
2552 String name,
2553 ArgList arglist,
2554 Cardinal argcount)
2555 {
2556 Widget fsb = XtCreateWidget(name, xnFsbWidgetClass, parent, arglist, argcount);
2557 return fsb;
2558 }
2559
2560 void XnFileSelectionBoxAddView(
2561 Widget fsb,
2562 const char *name,
2563 FSBViewCreateProc create,
2564 FSBViewUpdateProc update,
2565 FSBViewSelectProc select,
2566 FSBViewCleanupProc cleanup,
2567 FSBViewDestroyProc destroy,
2568 Boolean useDirList,
2569 void *userData)
2570 {
2571 XnFileSelectionBox f = (XnFileSelectionBox)fsb;
2572 if(f->fsb.numviews >=
FSB_MAX_VIEWS) {
2573 fprintf(stderr,
"XnFileSelectionBox: too many views\n");
2574 return;
2575 }
2576
2577 FSBView view;
2578 view.update = update;
2579 view.select = select;
2580 view.cleanup = cleanup;
2581 view.destroy = destroy;
2582 view.useDirList = useDirList;
2583 view.userData = userData;
2584
2585 FSBViewWidgets widgets = CreateView(f, create, userData, useDirList);
2586 view.widget = widgets.view;
2587 view.focus = widgets.focus;
2588
2589 AddViewMenuItem(f, name, f->fsb.numviews);
2590
2591 f->fsb.view[f->fsb.numviews++] = view;
2592 }
2593
2594
2595
2596
2597
2598
2599
2600
2601 Widget XnFileSelectionBoxWorkArea(Widget fsb) {
2602 XnFileSelectionBox f = (XnFileSelectionBox)fsb;
2603 return f->fsb.workarea;
2604 }
2605
2606 Widget XnFileSelectionBoxGetChild(Widget fsb,
enum XnFSBChild child) {
2607 XnFileSelectionBox w = (XnFileSelectionBox)fsb;
2608 switch(child) {
2609 case XnFSB_DIR_UP_BUTTON:
return w->fsb.dirUp;
2610 case XnFSB_HOME_BUTTON:
return w->fsb.home;
2611 case XnFSB_NEW_FOLDER_BUTTON:
return w->fsb.newFolder;
2612 case XnFSB_DETAIL_TOGGLE_BUTTON:
return w->fsb.detailToggleButton;
2613 case XnFSB_VIEW_OPTION_BUTTON:
return w->fsb.viewOption;
2614 case XnFSB_FILTER_DROPDOWN:
return w->fsb.filter;
2615 case XnFSB_FILTER_BUTTON:
return w->fsb.filterButton;
2616 case XnFSB_SHOW_HIDDEN_TOGGLE_BUTTON:
return w->fsb.showHiddenButtonW;
2617 case XnFSB_DIRECTORIES_LABEL:
return w->fsb.lsDirLabel;
2618 case XnFSB_FILES_LABEL:
return w->fsb.lsFileLabel;
2619 case XnFSB_DIRLIST:
return w->fsb.dirlist;
2620 case XnFSB_FILELIST:
return w->fsb.filelist;
2621 case XnFSB_GRID:
return w->fsb.grid;
2622 case XnFSB_OK_BUTTON:
return w->fsb.okBtn;
2623 case XnFSB_CANCEL_BUTTON:
return w->fsb.cancelBtn;
2624 case XnFSB_HELP_BUTTON:
return w->fsb.helpBtn;
2625 }
2626 return NULL;
2627 }
2628
2629 void XnFileSelectionBoxDeleteFilters(Widget fsb) {
2630 XnFileSelectionBox w = (XnFileSelectionBox)fsb;
2631 Widget filterList = XmDropDownGetList(w->fsb.filter);
2632 XmListDeleteAllItems(filterList);
2633 }
2634
2635 void XnFileSelectionBoxAddFilter(Widget fsb,
const char *filter) {
2636 XnFileSelectionBox w = (XnFileSelectionBox)fsb;
2637 Widget filterList = XmDropDownGetList(w->fsb.filter);
2638
2639 XmString str = XmStringCreateSimple((
char*)filter);
2640 XmListAddItem(filterList, str,
0);
2641 XmStringFree(str);
2642 }
2643