UNIXworkcode

1 /* 2 * Copyright 2021 Olaf Wintermann 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 23 //define FSB_ENABLE_DETAIL 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 //static int CheckFileName(const char *name); 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 // Core Class 221 { 222 (WidgetClass)&xmFormClassRec, 223 "XnFSB", // class_name 224 sizeof(FSBRec), // widget_size 225 fsb_class_init, // class_initialize 226 fsb_class_part_init, // class_part_initialize 227 FALSE, // class_inited 228 fsb_init, // initialize 229 NULL, // initialize_hook 230 fsb_realize, // realize 231 actionslist, // actions 232 XtNumber(actionslist), // num_actions 233 resources, // resources 234 XtNumber(resources), // num_resources 235 NULLQUARK, // xrm_class 236 True, // compress_motion 237 True, // compress_exposure 238 True, // compress_enterleave 239 False, // visible_interest 240 fsb_destroy, // destroy 241 fsb_resize, // resize 242 XtInheritExpose, // expose 243 fsb_set_values, // set_values 244 NULL, // set_values_hook 245 XtInheritSetValuesAlmost, // set_values_almost 246 NULL, // get_values_hook 247 fsb_acceptfocus, // accept_focus 248 XtVersion, // version 249 NULL, // callback_offsets 250 defaultTranslations, // tm_table 251 XtInheritQueryGeometry, // query_geometry 252 XtInheritDisplayAccelerator, // display_accelerator 253 NULL, // extension 254 }, 255 // Composite Class 256 { 257 XtInheritGeometryManager, // geometry_manager 258 XtInheritChangeManaged, // change_managed 259 fsb_insert_child, // insert_child 260 XtInheritDeleteChild, // delete_child 261 NULL, // extension 262 }, 263 // Constraint Class 264 { 265 constraints, // resources 266 XtNumber(constraints), // num_resources 267 sizeof(XmFormConstraintRec), // constraint_size 268 NULL, // initialize 269 NULL, // destroy 270 NULL, // set_value 271 NULL, // extension 272 }, 273 // XmManager Class 274 { 275 XtInheritTranslations, // translations 276 NULL, // syn_resources 277 0, // num_syn_resources 278 NULL, // syn_constraint_resources 279 0, // num_syn_constraint_resources 280 XmInheritParentProcess, // parent_process 281 NULL // extension 282 }, 283 // XmBulletinBoard 284 { 285 FALSE, 286 NULL, 287 XmInheritFocusMovedProc, 288 NULL 289 }, 290 // XmForm Class 291 { 292 NULL 293 }, 294 // FSB Class 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 // destroy all views 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 // free filelists 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 // free strings 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 // also update current directory 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 // label strings 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 // custom child widget insert 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 // make sure the new file name doesn't contain a path separator 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 // item0: rename 971 // item1: delete 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 // unused 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 * create file size string with kb/mb/gb/tb suffix 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 // size < 10 KiB 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 // size < 10 MiB 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 // size < 10 GiB 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 // size < 10 TiB 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 // name 1216 XmString str = XmStringCreateLocalized(name); 1217 XtVaSetValues(grid, 1218 XmNcolumn, 0, 1219 XmNrow, row, 1220 XmNcellString, str, NULL); 1221 XmStringFree(str); 1222 // size 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 // date 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 // remove unused rows 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 // cleanup grid 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 // unused 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 * file_cmp_field 1366 * 0: compare path 1367 * 1: compare size 1368 * 2: compare mtime 1369 */ 1370 static int file_cmp_field = 0; 1371 1372 /* 1373 * 1 or -1 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 // try to check first, if we can open the path 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 /* read dir and insert items */ 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 /* dir reading complete - set the path textfield */ 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 // sort file arrays 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); // 0: list, 1: detail 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 // add a trailing / to the dir string 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 /* upper part of the gui */ 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 // View Option Menu 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 // match visual appearance of detailToggleButton with the other buttons 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 // pathbar 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 /* lower part */ 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 // middle 2037 // form for dir/file lists 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 // dir/file lists 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 // FileList 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 // Detail FileList 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 n = 0; 2106 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; 2107 XtSetArg(args[n], XmNleftWidget, w->fsb.dirlist); n++; 2108 XtSetArg(args[n], XmNleftOffset, widget_spacing); n++; 2109 //XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; 2110 //XtSetArg(args[n], XmNbottomWidget, w->fsb.filelist); n++; 2111 XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++; 2112 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; 2113 XtSetArg(args[n], XmNlabelString, w->fsb.labelFiles); n++; 2114 w->fsb.lsFileLabel = XmCreateLabel(w->fsb.listform, "label", args, n); 2115 XtManageChild(w->fsb.lsFileLabel); 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 // if data->showHidden is 0, data->files contains more items than the grid 2333 // this means SelectedRow might not be the correct index for data->files 2334 // we have to count files manually and increase 'row', if the file 2335 // is actually displayed in the grid 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; // revert sort order 2389 } else { 2390 file_cmp_field = new_cmp_field; // change file cmp order to new 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 // refresh widget 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 // context menu 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 /* ------------------------------ Path Utils ------------------------------ */ 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 // unused at the moment, maybe reactivate if more illegal characters 2521 // are defined 2522 /* 2523 static int CheckFileName(const char *fileName) { 2524 size_t len = strlen(fileName); 2525 for(int i=0;i<len;i++) { 2526 if(fileName[i] == '/') { 2527 return 0; 2528 } 2529 } 2530 return 1; 2531 } 2532 */ 2533 2534 2535 /* ------------------------------ public API ------------------------------ */ 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 void XnFileSelectionBoxSetDirList(Widget fsb, const char **dirlist, size_t nelm) { 2596 XnFileSelectionBox f = (XnFileSelectionBox)fsb; 2597 PathBarSetDirList(f->fsb.pathBar, dirlist, nelm); 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