#include "Fsb.h"
#include "FsbP.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/stat.h>
#include <limits.h>
#include <dirent.h>
#include <fnmatch.h>
#include <Xm/XmAll.h>
#include <Xm/DropDown.h>
#include "pathbar.h"
#include "../common/utils.h"
#ifdef FSB_ENABLE_DETAIL
#include <XmL/Grid.h>
#endif
#define WIDGET_SPACING 5
#define WINDOW_SPACING 8
#define BUTTON_EXTRA_SPACE 4
#define DATE_FORMAT_SAME_YEAR "%b %d %H:%M"
#define DATE_FORMAT_OTHER_YEAR "%b %d %Y"
#define KB_SUFFIX "KiB"
#define MB_SUFFIX "MiB"
#define GB_SUFFIX "GiB"
#define TB_SUFFIX "TiB"
#define FSB_ERROR_TITLE "Error"
#define FSB_ERROR_CHAR "Character ''/'' is not allowed in file names"
#define FSB_ERROR_RENAME "Cannot rename file: %s"
#define FSB_ERROR_DELETE "Cannot delete file: %s"
#define FSB_ERROR_CREATE_FOLDER "Cannot create folder: %s"
#define FSB_ERROR_OPEN_DIR "Cannot open directory: %s"
#define FSB_DETAIL_HEADINGS "Name|Size|Last Modified"
static void fsb_class_init(
void);
static void fsb_class_part_init (WidgetClass wc);
static void fsb_init(Widget request, Widget neww, ArgList args, Cardinal *num_args);
static void fsb_resize(Widget widget);
static void fsb_realize(Widget widget, XtValueMask *mask, XSetWindowAttributes *attributes);
static void fsb_destroy(Widget widget);
static Boolean fsb_set_values(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args);
static Boolean fsb_acceptfocus(Widget widget, Time *time);
static void fsb_insert_child(Widget child);
static void fsb_mapcb(Widget widget, XtPointer u, XtPointer cb);
static int FSBGlobFilter(
const char *a,
const char *b);
static void FSBUpdateTitle(Widget w);
static void FocusInAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
static void ErrDialog(XnFileSelectionBox w,
const char *title,
const char *errmsg);
static void FSBRename(XnFileSelectionBox fsb,
const char *path);
static void FSBDelete(XnFileSelectionBox fsb,
const char *path);
static void FSBSelectItem(XnFileSelectionBox fsb,
const char *item);
static char* set_selected_path(XnFileSelectionBox data, XmString item);
static void FileContextMenuCB(Widget item, XtPointer index, XtPointer cd);
static Widget CreateContextMenu(XnFileSelectionBox fsb, Widget parent, XtCallbackProc callback);
static void FileListUpdate(Widget fsb, Widget view, FileElm *dirlist,
int dircount, FileElm *files,
int filecount,
const char *filter,
int maxnamelen,
void *userData);
static void FileListSelect(Widget fsb, Widget view,
const char *item);
static void FileListCleanup(Widget fsb, Widget view,
void *userData);
static void FileListDestroy(Widget fsb, Widget view,
void *userData);
static void FileListActivateCB(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb);
static void FileListSelectCB(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb);
static void FileListWidgetAdd(XnFileSelectionBox fsb, Widget w,
int showHidden,
const char *filter, FileElm *ls,
int count);
#ifdef FSB_ENABLE_DETAIL
static void FileListDetailUpdate(Widget fsb, Widget view, FileElm *dirlist,
int dircount, FileElm *files,
int filecount,
const char *filter,
int maxnamelen,
void *userData);
static void FileListDetailSelect(Widget fsb, Widget view,
const char *item);
static void FileListDetailCleanup(Widget fsb, Widget view,
void *userData);
static void FileListDetailDestroy(Widget fsb, Widget view,
void *userData);
static void FileListDetailAdjustColWidth(Widget grid);
static void FileListDetailAdd(XnFileSelectionBox fsb, Widget grid,
int showHidden,
const char *filter, FileElm *ls,
int count,
int maxWidth);
#endif
static void FSBNewFolder(Widget w, XnFileSelectionBox data, XtPointer u);
static void FSBHome(Widget w, XnFileSelectionBox data, XtPointer u);
static void FileSelectionCallback(XnFileSelectionBox fsb, XtCallbackList cb,
int reason,
const char *value);
static void CreateUI(XnFileSelectionBox w);
static FSBViewWidgets CreateView(XnFileSelectionBox w, FSBViewCreateProc createProc,
void *userData, Boolean useDirList);
static void AddViewMenuItem(XnFileSelectionBox w,
const char *name,
int viewIndex);
static void SelectView(XnFileSelectionBox f,
int view);
static char* FSBDialogTitle(Widget w);
static FSBViewWidgets CreateListView(Widget fsb, ArgList args,
int n,
void *userData);
static FSBViewWidgets CreateDetailView(Widget fsb, ArgList args,
int n,
void *userData);
static const char* GetHomeDir(
void);
static char* ConcatPath(
const char *parent,
const char *name);
static char* FileName(
char *path);
static char* ParentPath(
const char *path);
static int filedialog_update_dir(XnFileSelectionBox data,
const char *path);
static void filedialog_cleanup_filedata(XnFileSelectionBox data);
static XtResource resources[] = {
{XmNokCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), XtOffset(XnFileSelectionBox, fsb.okCallback), XmRCallback,
NULL},
{XmNcancelCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), XtOffset(XnFileSelectionBox, fsb.cancelCallback), XmRCallback,
NULL},
{XnNwidgetSpacing, XmCSpacing, XmRDimension,
sizeof(Dimension), XtOffset(XnFileSelectionBox, fsb.widgetSpacing), XmRImmediate, (XtPointer)
WIDGET_SPACING},
{XnNwindowSpacing, XmCSpacing, XmRDimension,
sizeof(Dimension), XtOffset(XnFileSelectionBox, fsb.windowSpacing), XmRImmediate, (XtPointer)
WINDOW_SPACING},
{XnNfsbType, XnCfsbType, XmRInt,
sizeof(
int), XtOffset(XnFileSelectionBox, fsb.type), XmRImmediate, (XtPointer)
FILEDIALOG_OPEN},
{XnNshowHidden, XnCshowHidden, XmRBoolean,
sizeof(Boolean), XtOffset(XnFileSelectionBox, fsb.showHidden), XmRImmediate, (XtPointer)False},
{XnNshowHiddenButton, XnCshowHiddenButton, XmRBoolean,
sizeof(Boolean), XtOffset(XnFileSelectionBox, fsb.showHiddenButton), XmRImmediate, (XtPointer)True},
{XnNshowViewMenu, XnCshowViewMenu, XmRBoolean,
sizeof(Boolean), XtOffset(XnFileSelectionBox, fsb.showViewMenu), XmRImmediate, (XtPointer)False},
{XnNselectedView, XnCselectedView, XmRInt,
sizeof(
int), XtOffset(XnFileSelectionBox, fsb.selectedview), XmRImmediate, (XtPointer)
0},
{XnNdirectory, XnCdirectory, XmRString,
sizeof(XmString), XtOffset(XnFileSelectionBox, fsb.currentPath), XmRString,
NULL},
{XnNselectedPath, XnCselectedPath, XmRString,
sizeof(XmString), XtOffset(XnFileSelectionBox, fsb.selectedPath), XmRString,
NULL},
{XnNhomePath, XnChomePath, XmRString,
sizeof(XmString), XtOffset(XnFileSelectionBox, fsb.homePath), XmRString,
NULL},
{XnNfilter,XnCfilter,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.filterStr), XmRString,
"*"},
{XnNfilterFunc,XnCfilterFunc,XmRFunction,
sizeof(FSBFilterFunc),XtOffset(XnFileSelectionBox, fsb.filterFunc), XmRFunction,
NULL},
{XnNlabelListView,XnClabelListView,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelListView), XmRString,
"List"},
{XnNlabelDetailView,XnClabelDetailView,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDetailView), XmRString,
"Detail"},
{XnNlabelOpenFileTitle,XnClabelOpenFileTitle,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelOpenFileTitle), XmRString,
"Open File"},
{XnNlabelSaveFileTitle,XnClabelSaveFileTitle,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelSaveFileTitle), XmRString,
"Save File"},
{XnNlabelDirUp,XnClabelDirUp,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDirUp), XmRString,
"Dir Up"},
{XnNlabelHome,XnClabelHome,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelHome), XmRString,
"Home"},
{XnNlabelNewFolder,XnClabelNewFolder,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelNewFolder), XmRString,
"New Folder"},
{XnNlabelFilterButton,XnClabelFilterButton,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelFilterButton), XmRString,
"Filter"},
{XnNlabelShowHiddenFiles,XnClabelShowHiddenFiles,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelShowHiddenFiles), XmRString,
"Show hiden files"},
{XnNlabelDirectories,XnClabelDirectories,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDirectories), XmRString,
"Directories"},
{XnNlabelFiles,XnClabelFiles,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelFiles), XmRString,
"Files"},
{XnNlabelRename,XnClabelRename,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelRename), XmRString,
"Rename"},
{XnNlabelDelete,XnClabelDelete,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDelete), XmRString,
"Delete"},
{XnNlabelOpen,XnClabelOpen,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelOpen), XmRString,
"Open"},
{XnNlabelSave,XnClabelSave,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelSave), XmRString,
"Save"},
{XnNlabelOk,XnClabelOk,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelOk), XmRString,
"OK"},
{XnNlabelCancel,XnClabelCancel,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelCancel), XmRString,
"Cancel"},
{XnNlabelHelp,XnClabelHelp,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelHelp), XmRString,
"Help"},
{XnNlabelFileName,XnClabelFileName,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelFileName), XmRString,
"New File Name"},
{XnNlabelDirectoryName,XnClabelDirectoryName,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDirectoryName), XmRString,
"Directory name:"},
{XnNlabelNewFileName,XnClabelNewFileName,XmRXmString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelNewFileName), XmRString,
"New file name:"},
{XnNlabelDeleteFile,XnClabelDeleteFile,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDeleteFile), XmRString,
"Delete file ''%s''?"},
{XnNdetailHeadings,XnCdetailHeadings,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.detailHeadings), XmRString,
FSB_DETAIL_HEADINGS},
{XnNdateFormatSameYear,XnCdateFormatSameYear,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.dateFormatSameYear), XmRString,
DATE_FORMAT_SAME_YEAR},
{XnNdateFormatOtherYear,XnNdateFormatOtherYear,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.dateFormatOtherYear), XmRString,
DATE_FORMAT_OTHER_YEAR},
{XnNsuffixBytes,XnCsuffixBytes,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixBytes), XmRString,
"bytes"},
{XnNsuffixKB,XnCsuffixKB,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixKB), XmRString,
KB_SUFFIX},
{XnNsuffixMB,XnCsuffixKB,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixMB), XmRString,
MB_SUFFIX},
{XnNsuffixGB,XnCsuffixKB,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixGB), XmRString,
GB_SUFFIX},
{XnNsuffixTB,XnCsuffixKB,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixTB), XmRString,
TB_SUFFIX},
{XnNerrorTitle,XnCerrorTitle,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorTitle), XmRString,
FSB_ERROR_TITLE},
{XnNerrorIllegalChar,XnCerrorIllegalChar,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorIllegalChar), XmRString,
FSB_ERROR_CHAR},
{XnNerrorRename,XnCerrorRename,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorRename), XmRString,
FSB_ERROR_RENAME},
{XnNerrorCreateFolder,XnCerrorCreateFolder,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorFolder), XmRString,
FSB_ERROR_CREATE_FOLDER},
{XnNerrorDelete,XnCerrorDelete,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorDelete), XmRString,
FSB_ERROR_DELETE},
{XnNerrorOpenDir,XnCerrorOpenDir,XmRString,
sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorOpenDir), XmRString,
FSB_ERROR_OPEN_DIR}
};
static XtActionsRec actionslist[] = {
{
"focusIn", FocusInAP},
{
"NULL",
NULL}
};
static char defaultTranslations[] =
"<FocusIn>: focusIn()";
static XtResource constraints[] = {};
FSBClassRec fsbWidgetClassRec = {
{
(WidgetClass)&xmFormClassRec,
"XnFSB",
sizeof(FSBRec),
fsb_class_init,
fsb_class_part_init,
FALSE,
fsb_init,
NULL,
fsb_realize,
actionslist,
XtNumber(actionslist),
resources,
XtNumber(resources),
NULLQUARK,
True,
True,
True,
False,
fsb_destroy,
fsb_resize,
XtInheritExpose,
fsb_set_values,
NULL,
XtInheritSetValuesAlmost,
NULL,
fsb_acceptfocus,
XtVersion,
NULL,
defaultTranslations,
XtInheritQueryGeometry,
XtInheritDisplayAccelerator,
NULL,
},
{
XtInheritGeometryManager,
XtInheritChangeManaged,
fsb_insert_child,
XtInheritDeleteChild,
NULL,
},
{
constraints,
XtNumber(constraints),
sizeof(XmFormConstraintRec),
NULL,
NULL,
NULL,
NULL,
},
{
XtInheritTranslations,
NULL,
0,
NULL,
0,
XmInheritParentProcess,
NULL
},
{
FALSE,
NULL,
XmInheritFocusMovedProc,
NULL
},
{
NULL
},
{
0
}
};
WidgetClass xnFsbWidgetClass = (WidgetClass)&fsbWidgetClassRec;
static void fsb_class_init(
void) {
}
static void fsb_class_part_init (WidgetClass wc) {
FSBClassRec *fsbClass = (FSBClassRec*)wc;
XmFormClassRec *formClass = (XmFormClassRec*)xmFormWidgetClass;
fsbClass->constraint_class.initialize = formClass->constraint_class.initialize;
fsbClass->constraint_class.set_values = formClass->constraint_class.set_values;
}
#define STRDUP_RES(a)
if(a) a = strdup(a)
#define XMS_STRDUP_RES(a)
if(a) a = XmStringCopy(a)
static void fsb_init(Widget request, Widget neww, ArgList args, Cardinal *num_args) {
XnFileSelectionBox fsb = (XnFileSelectionBox)neww;
(xmFormClassRec.core_class.initialize)(request, neww, args, num_args);
fsb->fsb.disable_set_values =
0;
STRDUP_RES(fsb->fsb.homePath);
STRDUP_RES(fsb->fsb.selectedPath);
STRDUP_RES(fsb->fsb.currentPath);
STRDUP_RES(fsb->fsb.filterStr);
STRDUP_RES(fsb->fsb.labelListView);
STRDUP_RES(fsb->fsb.labelDetailView);
STRDUP_RES(fsb->fsb.labelOpenFileTitle);
STRDUP_RES(fsb->fsb.labelSaveFileTitle);
XMS_STRDUP_RES(fsb->fsb.labelDirUp);
XMS_STRDUP_RES(fsb->fsb.labelHome);
XMS_STRDUP_RES(fsb->fsb.labelNewFolder);
XMS_STRDUP_RES(fsb->fsb.labelFilterButton);
XMS_STRDUP_RES(fsb->fsb.labelShowHiddenFiles);
XMS_STRDUP_RES(fsb->fsb.labelDirectories);
XMS_STRDUP_RES(fsb->fsb.labelFiles);
XMS_STRDUP_RES(fsb->fsb.labelRename);
XMS_STRDUP_RES(fsb->fsb.labelDelete);
XMS_STRDUP_RES(fsb->fsb.labelOpen);
XMS_STRDUP_RES(fsb->fsb.labelSave);
XMS_STRDUP_RES(fsb->fsb.labelCancel);
XMS_STRDUP_RES(fsb->fsb.labelHelp);
XMS_STRDUP_RES(fsb->fsb.labelFileName);
XMS_STRDUP_RES(fsb->fsb.labelDirectoryName);
XMS_STRDUP_RES(fsb->fsb.labelNewFileName);
STRDUP_RES(fsb->fsb.labelDeleteFile);
STRDUP_RES(fsb->fsb.detailHeadings);
STRDUP_RES(fsb->fsb.dateFormatSameYear);
STRDUP_RES(fsb->fsb.dateFormatOtherYear);
STRDUP_RES(fsb->fsb.suffixBytes);
STRDUP_RES(fsb->fsb.suffixKB);
STRDUP_RES(fsb->fsb.suffixMB);
STRDUP_RES(fsb->fsb.suffixGB);
STRDUP_RES(fsb->fsb.suffixTB);
STRDUP_RES(fsb->fsb.errorTitle);
STRDUP_RES(fsb->fsb.errorIllegalChar);
STRDUP_RES(fsb->fsb.errorRename);
STRDUP_RES(fsb->fsb.errorFolder);
STRDUP_RES(fsb->fsb.errorDelete);
STRDUP_RES(fsb->fsb.errorOpenDir);
CreateUI((XnFileSelectionBox)fsb);
XtAddCallback(neww, XmNmapCallback, fsb_mapcb,
NULL);
}
#define STR_FREE(a)
if(a) free(a)
#define XMSTR_FREE(a)
if(a) XmStringFree(a)
static void fsb_destroy(Widget widget) {
XnFileSelectionBox w = (XnFileSelectionBox)widget;
for(
int i=
0;i<w->fsb.numviews;i++) {
FSBView v = w->fsb.view[i];
v.destroy(widget, v.widget, v.userData);
}
STR_FREE(w->fsb.homePath);
filedialog_cleanup_filedata(w);
STR_FREE(w->fsb.currentPath);
STR_FREE(w->fsb.selectedPath);
STR_FREE(w->fsb.filterStr);
PathBarDestroy(w->fsb.pathBar);
STR_FREE(w->fsb.labelListView);
STR_FREE(w->fsb.labelDetailView);
STR_FREE(w->fsb.labelOpenFileTitle);
STR_FREE(w->fsb.labelSaveFileTitle);
XMSTR_FREE(w->fsb.labelDirUp);
XMSTR_FREE(w->fsb.labelHome);
XMSTR_FREE(w->fsb.labelNewFolder);
XMSTR_FREE(w->fsb.labelFilterButton);
XMSTR_FREE(w->fsb.labelShowHiddenFiles);
XMSTR_FREE(w->fsb.labelDirectories);
XMSTR_FREE(w->fsb.labelFiles);
XMSTR_FREE(w->fsb.labelRename);
XMSTR_FREE(w->fsb.labelDelete);
XMSTR_FREE(w->fsb.labelOpen);
XMSTR_FREE(w->fsb.labelSave);
XMSTR_FREE(w->fsb.labelCancel);
XMSTR_FREE(w->fsb.labelHelp);
XMSTR_FREE(w->fsb.labelFileName);
XMSTR_FREE(w->fsb.labelDirectoryName);
XMSTR_FREE(w->fsb.labelNewFileName);
STR_FREE(w->fsb.labelDeleteFile);
STR_FREE(w->fsb.detailHeadings);
STR_FREE(w->fsb.dateFormatSameYear);
STR_FREE(w->fsb.dateFormatOtherYear);
STR_FREE(w->fsb.suffixBytes);
STR_FREE(w->fsb.suffixKB);
STR_FREE(w->fsb.suffixMB);
STR_FREE(w->fsb.suffixGB);
STR_FREE(w->fsb.suffixTB);
STR_FREE(w->fsb.errorTitle);
STR_FREE(w->fsb.errorIllegalChar);
STR_FREE(w->fsb.errorRename);
STR_FREE(w->fsb.errorFolder);
STR_FREE(w->fsb.errorDelete);
STR_FREE(w->fsb.errorOpenDir);
}
static void fsb_resize(Widget widget) {
XnFileSelectionBox w = (XnFileSelectionBox)widget;
(xmFormClassRec.core_class.resize)(widget);
#ifdef FSB_ENABLE_DETAIL
if(w->fsb.view[w->fsb.selectedview].update == FileListDetailUpdate) {
FileListDetailAdjustColWidth(w->fsb.grid);
}
#endif
}
static void fsb_realize(Widget widget, XtValueMask *mask, XSetWindowAttributes *attributes) {
XnFileSelectionBox w = (XnFileSelectionBox)widget;
(xmFormClassRec.core_class.realize)(widget, mask, attributes);
FSBView view = w->fsb.view[w->fsb.selectedview];
XmProcessTraversal(view.focus, XmTRAVERSE_CURRENT);
#ifdef FSB_ENABLE_DETAIL
if(w->fsb.view[w->fsb.selectedview].update == FileListDetailUpdate) {
FileListDetailAdjustColWidth(w->fsb.grid);
}
#endif
}
static void FSBUpdateTitle(Widget w) {
if(XtParent(w)->core.widget_class == xmDialogShellWidgetClass) {
char *title = FSBDialogTitle(w);
XtVaSetValues(XtParent(w), XmNtitle, title,
NULL);
}
}
static Boolean fsb_set_values(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) {
Boolean r = False;
XnFileSelectionBox o = (XnFileSelectionBox)old;
XnFileSelectionBox n = (XnFileSelectionBox)neww;
int setOkBtnLabel =
0;
int ismanaged = XtIsManaged(neww);
Dimension width, height;
if(!ismanaged) {
width = n->core.width;
height = n->core.height;
if(n->fsb.pathBar) {
n->fsb.pathBar->disableResize = True;
}
}
if(o->fsb.selectedview != n->fsb.selectedview) {
int selectedview = n->fsb.selectedview;
n->fsb.selectedview = o->fsb.selectedview;
SelectView(n, selectedview);
}
char *updateDir =
NULL;
int selectItem =
0;
if(o->fsb.selectedPath != n->fsb.selectedPath) {
STR_FREE(o->fsb.selectedPath);
STRDUP_RES(n->fsb.selectedPath);
XmTextFieldSetString(n->fsb.name, FileName(n->fsb.selectedPath));
updateDir = ParentPath(n->fsb.selectedPath);
selectItem =
1;
}
if(o->fsb.currentPath != n->fsb.currentPath) {
STR_FREE(o->fsb.currentPath);
updateDir = strdup(n->fsb.currentPath);
n->fsb.currentPath =
NULL;
}
if(o->fsb.filterStr != n->fsb.filterStr) {
STR_FREE(o->fsb.filterStr);
STRDUP_RES(n->fsb.filterStr);
XmTextFieldSetString(XmDropDownGetText(n->fsb.filter), n->fsb.filterStr);
if(!updateDir) {
filedialog_update_dir(n,
NULL);
}
}
if(updateDir) {
filedialog_update_dir(n, updateDir);
PathBarSetPath(n->fsb.pathBar, updateDir);
free(updateDir);
}
if(o->fsb.type != n->fsb.type) {
if(n->fsb.type ==
FILEDIALOG_OPEN) {
XtVaSetValues(n->fsb.workarea, XmNbottomWidget, n->fsb.separator,
NULL);
XtUnmanageChild(n->fsb.name);
XtUnmanageChild(n->fsb.nameLabel);
}
else {
XtManageChild(n->fsb.name);
XtManageChild(n->fsb.nameLabel);
XtVaSetValues(n->fsb.workarea, XmNbottomWidget, n->fsb.nameLabel,
NULL);
}
FSBUpdateTitle(neww);
setOkBtnLabel =
1;
}
int updateTitle =
0;
if(o->fsb.labelListView != n->fsb.labelListView) {
STR_FREE(o->fsb.labelListView);
STRDUP_RES(n->fsb.labelListView);
XmString label = XmStringCreateLocalized(n->fsb.labelListView);
XtVaSetValues(n->fsb.viewSelectorList, XmNlabelString, label,
NULL);
XmStringFree(label);
}
if(o->fsb.labelDetailView != n->fsb.labelDetailView) {
STR_FREE(o->fsb.labelDetailView);
STRDUP_RES(n->fsb.labelDetailView);
XmString label = XmStringCreateLocalized(n->fsb.labelDetailView);
XtVaSetValues(n->fsb.viewSelectorDetail, XmNlabelString, label,
NULL);
if(n->fsb.detailToggleButton) {
XtVaSetValues(n->fsb.detailToggleButton, XmNlabelString, label,
NULL);
}
XmStringFree(label);
}
if(o->fsb.labelOpenFileTitle != n->fsb.labelOpenFileTitle) {
STR_FREE(o->fsb.labelOpenFileTitle);
STRDUP_RES(n->fsb.labelOpenFileTitle);
updateTitle =
1;
}
if(o->fsb.labelSaveFileTitle != n->fsb.labelSaveFileTitle) {
STR_FREE(o->fsb.labelSaveFileTitle);
STRDUP_RES(n->fsb.labelSaveFileTitle);
updateTitle =
1;
}
if(o->fsb.labelDirUp != n->fsb.labelDirUp) {
XMSTR_FREE(o->fsb.labelDirUp);
XMS_STRDUP_RES(n->fsb.labelDirUp);
XtVaSetValues(n->fsb.dirUp, XmNlabelString, n->fsb.labelDirUp,
NULL);
}
if(o->fsb.labelHome != n->fsb.labelHome) {
XMSTR_FREE(o->fsb.labelHome);
XMS_STRDUP_RES(n->fsb.labelHome);
XtVaSetValues(n->fsb.dirUp, XmNlabelString, n->fsb.labelHome,
NULL);
}
if(o->fsb.labelNewFolder != n->fsb.labelNewFolder) {
XMSTR_FREE(o->fsb.labelNewFolder);
XMS_STRDUP_RES(n->fsb.labelNewFolder);
XtVaSetValues(n->fsb.newFolder, XmNlabelString, n->fsb.labelNewFolder,
NULL);
}
if(o->fsb.labelFilterButton != n->fsb.labelFilterButton) {
XMSTR_FREE(o->fsb.labelFilterButton);
XMS_STRDUP_RES(n->fsb.labelFilterButton);
XtVaSetValues(n->fsb.filterButton, XmNlabelString, n->fsb.labelFilterButton,
NULL);
}
if(o->fsb.labelShowHiddenFiles != n->fsb.labelShowHiddenFiles) {
XMSTR_FREE(o->fsb.labelShowHiddenFiles);
XMS_STRDUP_RES(n->fsb.labelShowHiddenFiles);
XtVaSetValues(n->fsb.showHiddenButtonW, XmNlabelString, n->fsb.labelShowHiddenFiles,
NULL);
}
if(o->fsb.labelDirectories != n->fsb.labelDirectories) {
XMSTR_FREE(o->fsb.labelDirectories);
XMS_STRDUP_RES(n->fsb.labelDirectories);
XtVaSetValues(n->fsb.lsDirLabel, XmNlabelString, n->fsb.labelDirectories,
NULL);
}
if(o->fsb.labelFiles != n->fsb.labelFiles) {
XMSTR_FREE(o->fsb.labelFiles);
XMS_STRDUP_RES(n->fsb.labelFiles);
XtVaSetValues(n->fsb.lsFileLabel, XmNlabelString, n->fsb.labelFiles,
NULL);
}
int recreateContextMenu =
0;
if(o->fsb.labelRename != n->fsb.labelRename) {
XMSTR_FREE(o->fsb.labelRename);
XMS_STRDUP_RES(n->fsb.labelRename);
recreateContextMenu =
1;
}
if(o->fsb.labelDelete != n->fsb.labelDelete) {
XMSTR_FREE(o->fsb.labelDelete);
XMS_STRDUP_RES(n->fsb.labelDelete);
recreateContextMenu =
1;
}
if(o->fsb.labelOpen != n->fsb.labelOpen) {
XMSTR_FREE(o->fsb.labelOpen);
XMS_STRDUP_RES(n->fsb.labelOpen);
setOkBtnLabel =
1;
}
if(o->fsb.labelSave != n->fsb.labelSave) {
XMSTR_FREE(o->fsb.labelSave);
XMS_STRDUP_RES(n->fsb.labelSave);
setOkBtnLabel =
1;
}
if(o->fsb.labelCancel != n->fsb.labelCancel) {
XMSTR_FREE(o->fsb.labelCancel);
XMS_STRDUP_RES(n->fsb.labelCancel);
XtVaSetValues(n->fsb.cancelBtn, XmNlabelString, n->fsb.labelCancel,
NULL);
}
if(o->fsb.labelHelp != n->fsb.labelHelp) {
XMSTR_FREE(o->fsb.labelHelp);
XMS_STRDUP_RES(n->fsb.labelHelp);
XtVaSetValues(n->fsb.helpBtn, XmNlabelString, n->fsb.labelHelp,
NULL);
}
if(o->fsb.labelFileName != n->fsb.labelFileName) {
XMSTR_FREE(o->fsb.labelFileName);
XMS_STRDUP_RES(n->fsb.labelFileName);
XtVaSetValues(n->fsb.nameLabel, XmNlabelString, n->fsb.labelFileName,
NULL);
}
if(o->fsb.labelDirectoryName != n->fsb.labelDirectoryName) {
XMSTR_FREE(o->fsb.labelDirectoryName);
XMS_STRDUP_RES(n->fsb.labelDirectoryName);
}
if(o->fsb.labelNewFileName != n->fsb.labelNewFileName) {
XMSTR_FREE(o->fsb.labelNewFileName);
XMS_STRDUP_RES(n->fsb.labelNewFileName);
}
if(o->fsb.labelDeleteFile != n->fsb.labelDeleteFile) {
STR_FREE(o->fsb.labelDeleteFile);
STRDUP_RES(n->fsb.labelDeleteFile);
}
#ifdef FSB_ENABLE_DETAIL
if(o->fsb.detailHeadings != n->fsb.detailHeadings) {
STR_FREE(o->fsb.detailHeadings);
STRDUP_RES(n->fsb.detailHeadings);
XtVaSetValues(n->fsb.grid, XmNsimpleHeadings, n->fsb.detailHeadings,
NULL);
}
#endif
if(o->fsb.dateFormatSameYear != n->fsb.dateFormatSameYear) {
STR_FREE(o->fsb.dateFormatSameYear);
STRDUP_RES(n->fsb.dateFormatSameYear);
}
if(o->fsb.dateFormatOtherYear != n->fsb.dateFormatOtherYear) {
STR_FREE(o->fsb.dateFormatOtherYear);
STRDUP_RES(n->fsb.dateFormatOtherYear);
}
if(o->fsb.suffixBytes != n->fsb.suffixBytes) {
STR_FREE(o->fsb.suffixBytes);
STRDUP_RES(n->fsb.suffixBytes);
}
if(o->fsb.suffixMB != n->fsb.suffixMB) {
STR_FREE(o->fsb.suffixMB);
STRDUP_RES(n->fsb.suffixMB);
}
if(o->fsb.suffixGB != n->fsb.suffixGB) {
STR_FREE(o->fsb.suffixGB);
STRDUP_RES(n->fsb.suffixGB);
}
if(o->fsb.suffixTB != n->fsb.suffixTB) {
STR_FREE(o->fsb.suffixTB);
STRDUP_RES(n->fsb.suffixTB);
}
if(o->fsb.errorTitle != n->fsb.errorTitle) {
STR_FREE(o->fsb.errorTitle);
STRDUP_RES(n->fsb.errorTitle);
}
if(o->fsb.errorIllegalChar != n->fsb.errorIllegalChar) {
STR_FREE(o->fsb.errorIllegalChar);
STRDUP_RES(n->fsb.errorIllegalChar);
}
if(o->fsb.errorRename != n->fsb.errorRename) {
STR_FREE(o->fsb.errorRename);
STRDUP_RES(n->fsb.errorRename);
}
if(o->fsb.errorFolder != n->fsb.errorFolder) {
STR_FREE(o->fsb.errorFolder);
STRDUP_RES(n->fsb.errorFolder);
}
if(o->fsb.errorDelete != n->fsb.errorDelete) {
STR_FREE(o->fsb.errorDelete);
STRDUP_RES(n->fsb.errorDelete);
}
if(o->fsb.errorOpenDir != n->fsb.errorOpenDir) {
STR_FREE(o->fsb.errorOpenDir);
STRDUP_RES(n->fsb.errorOpenDir);
}
if(updateTitle) {
FSBUpdateTitle(neww);
}
if(recreateContextMenu) {
XtDestroyWidget(n->fsb.listContextMenu);
XtDestroyWidget(n->fsb.gridContextMenu);
n->fsb.listContextMenu = CreateContextMenu(n, n->fsb.filelist, FileContextMenuCB);
n->fsb.gridContextMenu = CreateContextMenu(n, n->fsb.grid, FileContextMenuCB);
}
if(setOkBtnLabel) {
XtVaSetValues(n->fsb.okBtn, XmNlabelString, n->fsb.type ==
FILEDIALOG_OPEN ? n->fsb.labelOpen : n->fsb.labelSave,
NULL);
}
if(!ismanaged && !n->fsb.disable_set_values) {
n->fsb.disable_set_values =
1;
XtVaSetValues(neww, XmNwidth, width, XmNheight, height,
NULL);
n->fsb.disable_set_values =
0;
if(n->fsb.pathBar)
n->fsb.pathBar->disableResize = False;
}
if(selectItem) {
if(ismanaged) {
FSBSelectItem(n, FileName(n->fsb.selectedPath));
}
}
Boolean fr = (xmFormClassRec.core_class.set_values)(old, request, neww, args, num_args);
return fr ? fr : r;
}
static void fsb_insert_child(Widget child) {
XnFileSelectionBox p = (XnFileSelectionBox)XtParent(child);
(xmFormClassRec.composite_class.insert_child)(child);
if(!p->fsb.gui_created) {
return;
}
XtVaSetValues(child,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, p->fsb.bottom_widget,
XmNbottomOffset, p->fsb.widgetSpacing,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, p->fsb.windowSpacing,
XmNrightAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
XmNrightOffset, p->fsb.windowSpacing,
NULL);
XtVaSetValues(p->fsb.listform,
XmNbottomWidget, child,
XmNbottomOffset,
0,
NULL);
p->fsb.workarea = child;
}
Boolean fsb_acceptfocus(Widget widget, Time *time) {
return 0;
}
static void fsb_mapcb(Widget widget, XtPointer u, XtPointer cb) {
XnFileSelectionBox w = (XnFileSelectionBox)widget;
pathbar_resize(w->fsb.pathBar->widget, w->fsb.pathBar,
NULL);
if(w->fsb.type ==
FILEDIALOG_OPEN) {
FSBView view = w->fsb.view[w->fsb.selectedview];
XmProcessTraversal(view.focus, XmTRAVERSE_CURRENT);
}
else {
XmProcessTraversal(w->fsb.name, XmTRAVERSE_CURRENT);
}
if(w->fsb.selectedPath) {
FSBSelectItem(w, FileName(w->fsb.selectedPath));
}
}
static void FocusInAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) {
}
static int apply_filter(XnFileSelectionBox w,
const char *pattern,
const char *string) {
if(!pattern)
return 0;
FSBFilterFunc func = w->fsb.filterFunc ? w->fsb.filterFunc : FSBGlobFilter;
return func(pattern, string);
}
static int FSBGlobFilter(
const char *a,
const char *b) {
return fnmatch(a, b,
0);
}
static void errCB(Widget w, XtPointer d, XtPointer cbs) {
XtDestroyWidget(w);
}
static void ErrDialog(XnFileSelectionBox w,
const char *title,
const char *errmsg) {
Arg args[
16];
int n =
0;
XmString titleStr = XmStringCreateLocalized((
char*)title);
XmString msg = XmStringCreateLocalized((
char*)errmsg);
XtSetArg(args[n], XmNdialogTitle, titleStr); n++;
XtSetArg(args[n], XmNselectionLabelString, msg); n++;
XtSetArg(args[n], XmNokLabelString, w->fsb.labelOk); n++;
XtSetArg(args[n], XmNcancelLabelString, w->fsb.labelCancel); n++;
Widget dialog = XmCreatePromptDialog ((Widget)w,
"NewFolderPrompt", args, n);
Widget help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
XtUnmanageChild(help);
Widget cancel = XmSelectionBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON);
XtUnmanageChild(cancel);
Widget text = XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT);
XtUnmanageChild(text);
XtAddCallback(dialog, XmNokCallback, errCB,
NULL);
XtManageChild(dialog);
XmStringFree(titleStr);
XmStringFree(msg);
}
static void rename_file_cb(Widget w,
const char *path, XmSelectionBoxCallbackStruct *cb) {
XnFileSelectionBox fsb =
NULL;
XtVaGetValues(w, XmNuserData, &fsb,
NULL);
char *fileName =
NULL;
XmStringGetLtoR(cb->value, XmSTRING_DEFAULT_CHARSET, &fileName);
if(strchr(fileName,
'/')) {
ErrDialog(fsb, fsb->fsb.errorTitle, fsb->fsb.errorIllegalChar);
XtFree(fileName);
return;
}
char *parentPath = ParentPath(path);
char *newPath = ConcatPath(parentPath, fileName);
if(rename(path, newPath)) {
char errmsg[
256];
snprintf(errmsg,
256, fsb->fsb.errorRename, strerror(errno));
ErrDialog(fsb, fsb->fsb.errorTitle, errmsg);
}
else {
filedialog_update_dir(fsb, parentPath);
}
free(parentPath);
free(newPath);
XtFree(fileName);
XtDestroyWidget(XtParent(w));
}
static void selectionbox_cancel(Widget w, XtPointer data, XtPointer d) {
XtDestroyWidget(XtParent(w));
}
static void FSBRename(XnFileSelectionBox fsb,
const char *path) {
Arg args[
16];
int n =
0;
Widget w = (Widget)fsb;
char *name = FileName((
char*)path);
XmString filename = XmStringCreateLocalized(name);
XtSetArg(args[n], XmNselectionLabelString,fsb->fsb.labelNewFileName); n++;
XtSetArg(args[n], XmNtextString, filename); n++;
XtSetArg(args[n], XmNuserData, fsb); n++;
XtSetArg(args[n], XmNdialogTitle, fsb->fsb.labelRename); n++;
XtSetArg(args[n], XmNokLabelString, fsb->fsb.labelOk); n++;
XtSetArg(args[n], XmNcancelLabelString, fsb->fsb.labelCancel); n++;
Widget dialog = XmCreatePromptDialog (w,
"RenameFilePrompt", args, n);
Widget help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
XtUnmanageChild(help);
XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)rename_file_cb, (
char*)path);
XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)selectionbox_cancel,
NULL);
XmStringFree(filename);
XtManageChild(dialog);
}
static void delete_file_cb(Widget w,
const char *path, XmSelectionBoxCallbackStruct *cb) {
XnFileSelectionBox fsb =
NULL;
XtVaGetValues(w, XmNuserData, &fsb,
NULL);
if(unlink(path)) {
char errmsg[
256];
snprintf(errmsg,
256, fsb->fsb.errorDelete, strerror(errno));
ErrDialog(fsb, fsb->fsb.errorTitle, errmsg);
}
else {
char *parentPath = ParentPath(path);
filedialog_update_dir(fsb, parentPath);
free(parentPath);
}
XtDestroyWidget(XtParent(w));
}
static void FSBDelete(XnFileSelectionBox fsb,
const char *path) {
Arg args[
16];
int n =
0;
Widget w = (Widget)fsb;
char *name = FileName((
char*)path);
size_t len = strlen(name);
size_t msglen = len + strlen(fsb->fsb.labelDeleteFile) +
4;
char *msg = malloc(msglen);
snprintf(msg, msglen, fsb->fsb.labelDeleteFile, name);
XmString prompt = XmStringCreateLocalized(msg);
XtSetArg(args[n], XmNselectionLabelString, prompt); n++;
XtSetArg(args[n], XmNuserData, fsb); n++;
XtSetArg(args[n], XmNdialogTitle, fsb->fsb.labelDelete); n++;
XtSetArg(args[n], XmNokLabelString, fsb->fsb.labelOk); n++;
XtSetArg(args[n], XmNcancelLabelString, fsb->fsb.labelCancel); n++;
Widget dialog = XmCreatePromptDialog (w,
"DeleteFilePrompt", args, n);
Widget help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
XtUnmanageChild(help);
Widget text = XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT);
XtUnmanageChild(text);
XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)delete_file_cb, (
char*)path);
XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)selectionbox_cancel,
NULL);
free(msg);
XmStringFree(prompt);
XtManageChild(dialog);
}
static void FSBSelectItem(XnFileSelectionBox fsb,
const char *item) {
FSBView view = fsb->fsb.view[fsb->fsb.selectedview];
if(view.select) {
view.select((Widget)fsb, view.widget, item);
}
}
static char* set_selected_path(XnFileSelectionBox data, XmString item)
{
char *name =
NULL;
XmStringGetLtoR(item, XmFONTLIST_DEFAULT_TAG, &name);
if(!name) {
return NULL;
}
char *path = ConcatPath(data->fsb.currentPath, name);
XtFree(name);
if(data->fsb.selectedPath) {
free(data->fsb.selectedPath);
}
data->fsb.selectedPath = path;
return path;
}
static void FileContextMenuCB(Widget item, XtPointer index, XtPointer cd) {
intptr_t i = (
intptr_t)index;
Widget parent = XtParent(item);
XnFileSelectionBox fsb =
NULL;
XtVaGetValues(parent, XmNuserData, &fsb,
NULL);
const char *path = fsb->fsb.selectedPath;
if(path) {
if(i ==
0) {
FSBRename(fsb, path);
}
else if(i ==
1) {
FSBDelete(fsb, path);
}
}
}
static Widget CreateContextMenu(XnFileSelectionBox fsb, Widget parent, XtCallbackProc callback) {
return XmVaCreateSimplePopupMenu(
parent,
"popup", callback, XmNpopupEnabled, XmPOPUP_AUTOMATIC,
XmNuserData, fsb,
XmVaPUSHBUTTON, fsb->fsb.labelRename,
'R',
NULL,
NULL,
XmVaPUSHBUTTON, fsb->fsb.labelDelete,
'D',
NULL,
NULL,
NULL);
}
static void FileListUpdate(Widget fsb, Widget view, FileElm *dirs,
int dircount, FileElm *files,
int filecount,
const char *filter,
int maxnamelen,
void *userData) {
XnFileSelectionBox data = userData;
FileListWidgetAdd(data, data->fsb.filelist, data->fsb.showHidden, filter, files, filecount);
}
static void FileListSelect(Widget fsb, Widget view,
const char *item) {
XnFileSelectionBox w = (XnFileSelectionBox)fsb;
int numItems =
0;
XmStringTable items =
NULL;
XtVaGetValues(w->fsb.filelist, XmNitemCount, &numItems, XmNitems, &items,
NULL);
for(
int i=
0;i<numItems;i++) {
char *str =
NULL;
XmStringGetLtoR(items[i], XmFONTLIST_DEFAULT_TAG, &str);
if(!strcmp(str, item)) {
XmListSelectPos(w->fsb.filelist, i
+1, False);
break;
}
XtFree(str);
}
}
static void FileListCleanup(Widget fsb, Widget view,
void *userData) {
XnFileSelectionBox data = userData;
XmListDeleteAllItems(data->fsb.filelist);
}
static void FileListDestroy(Widget fsb, Widget view,
void *userData) {
}
static void FileListActivateCB(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb)
{
char *path = set_selected_path(data, cb->item);
if(path) {
data->fsb.end = True;
data->fsb.status =
FILEDIALOG_OK;
data->fsb.selIsDir = False;
FileSelectionCallback(data, data->fsb.okCallback, XmCR_OK, data->fsb.selectedPath);
}
}
static void FileListSelectCB(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb)
{
if(data->fsb.type ==
FILEDIALOG_SAVE) {
char *name =
NULL;
XmStringGetLtoR(cb->item, XmFONTLIST_DEFAULT_TAG, &name);
XmTextFieldSetString(data->fsb.name, name);
XtFree(name);
}
else {
char *path = set_selected_path(data, cb->item);
if(path) {
data->fsb.selIsDir = False;
}
}
}
static void FileListWidgetAdd(XnFileSelectionBox fsb, Widget w,
int showHidden,
const char *filter, FileElm *ls,
int count)
{
if(count >
0) {
XmStringTable items = calloc(count,
sizeof(XmString));
int i =
0;
for(
int j=
0;j<count;j++) {
FileElm *e = &ls[j];
char *name = FileName(e->path);
if((!showHidden && name[
0] ==
'.') || apply_filter(fsb, filter, name)) {
continue;
}
items[i] = XmStringCreateLocalized(name);
i++;
}
XmListAddItems(w, items, i,
0);
for(i=
0;i<count;i++) {
XmStringFree(items[i]);
}
free(items);
}
}
#ifdef FSB_ENABLE_DETAIL
static void FileListDetailUpdate(Widget fsb, Widget view, FileElm *dirs,
int dircount, FileElm *files,
int filecount,
const char *filter,
int maxnamelen,
void *userData) {
XnFileSelectionBox data = userData;
FileListDetailAdd(data, data->fsb.grid, data->fsb.showHidden, filter, files, filecount, maxnamelen);
}
#endif
static char* size_str(XnFileSelectionBox fsb, FileElm *f) {
char *str = malloc(
16);
uint64_t size = f->size;
if(f->isDirectory) {
str[
0] =
'\0';
}
else if(size <
0x400) {
snprintf(str,
16,
"%d %s", (
int)size, fsb->fsb.suffixBytes);
}
else if(size <
0x100000) {
float s = (
float)size/
0x400;
int diff = (s*
100 - (
int)s*
100);
if(diff >
90) {
diff =
0;
s +=
0.10f;
}
if(size <
0x2800 && diff !=
0) {
snprintf(str,
16,
"%.1f %s", s, fsb->fsb.suffixKB);
}
else {
snprintf(str,
16,
"%.0f %s", s, fsb->fsb.suffixKB);
}
}
else if(size <
0x40000000) {
float s = (
float)size/
0x100000;
int diff = (s*
100 - (
int)s*
100);
if(diff >
90) {
diff =
0;
s +=
0.10f;
}
if(size <
0xa00000 && diff !=
0) {
snprintf(str,
16,
"%.1f %s", s, fsb->fsb.suffixMB);
}
else {
snprintf(str,
16,
"%.0f %s", s, fsb->fsb.suffixMB);
}
}
else if(size <
0x1000000000ULL) {
float s = (
float)size/
0x40000000;
int diff = (s*
100 - (
int)s*
100);
if(diff >
90) {
diff =
0;
s +=
0.10f;
}
if(size <
0x280000000 && diff !=
0) {
snprintf(str,
16,
"%.1f %s", s, fsb->fsb.suffixGB);
}
else {
snprintf(str,
16,
"%.0f %s", s, fsb->fsb.suffixGB);
}
}
else {
size /=
1024;
float s = (
float)size/
0x40000000;
int diff = (s*
100 - (
int)s*
100);
if(diff >
90) {
diff =
0;
s +=
0.10f;
}
if(size <
0x280000000 && diff !=
0) {
snprintf(str,
16,
"%.1f %s", s, fsb->fsb.suffixTB);
}
else {
snprintf(str,
16,
"%.0f %s", s, fsb->fsb.suffixTB);
}
}
return str;
}
static char* date_str(XnFileSelectionBox fsb,
time_t tm) {
struct tm t;
struct tm n;
time_t now = time(
NULL);
localtime_r(&tm, &t);
localtime_r(&now, &n);
char *str = malloc(
24);
if(t.tm_year == n.tm_year) {
strftime(str,
24, fsb->fsb.dateFormatSameYear, &t);
}
else {
strftime(str,
24, fsb->fsb.dateFormatOtherYear, &t);
}
return str;
}
#ifdef FSB_ENABLE_DETAIL
static void FileListDetailAdjustColWidth(Widget grid) {
XmLGridColumn column0 = XmLGridGetColumn(grid, XmCONTENT,
0);
XmLGridColumn column1 = XmLGridGetColumn(grid, XmCONTENT,
1);
XmLGridColumn column2 = XmLGridGetColumn(grid, XmCONTENT,
2);
Dimension col0Width = XmLGridColumnWidthInPixels(column0);
Dimension col1Width = XmLGridColumnWidthInPixels(column1);
Dimension col2Width = XmLGridColumnWidthInPixels(column2);
Dimension totalWidth = col0Width + col1Width + col2Width;
Dimension gridWidth =
0;
Dimension gridShadow =
0;
XtVaGetValues(grid, XmNwidth, &gridWidth, XmNshadowThickness, &gridShadow,
NULL);
Dimension widthDiff = gridWidth - totalWidth - gridShadow - gridShadow;
if(gridWidth > totalWidth) {
XtVaSetValues(grid,
XmNcolumnRangeStart,
0,
XmNcolumnRangeEnd,
0,
XmNcolumnWidth, col0Width + widthDiff - XmLGridVSBWidth(grid) -
2,
XmNcolumnSizePolicy, XmCONSTANT,
NULL);
}
}
static void FileListDetailAdd(XnFileSelectionBox fsb, Widget grid,
int showHidden,
const char *filter, FileElm *ls,
int count,
int maxWidth)
{
XmLGridAddRows(grid, XmCONTENT,
1, count);
int row =
0;
for(
int i=
0;i<count;i++) {
FileElm *e = &ls[i];
char *name = FileName(e->path);
if((!showHidden && name[
0] ==
'.') || (!e->isDirectory && apply_filter(fsb, filter, name))) {
continue;
}
XmString str = XmStringCreateLocalized(name);
XtVaSetValues(grid,
XmNcolumn,
0,
XmNrow, row,
XmNcellString, str,
NULL);
XmStringFree(str);
char *szbuf = size_str(fsb, e);
str = XmStringCreateLocalized(szbuf);
XtVaSetValues(grid,
XmNcolumn,
1,
XmNrow, row,
XmNcellString, str,
NULL);
free(szbuf);
XmStringFree(str);
char *datebuf = date_str(fsb, e->lastModified);
str = XmStringCreateLocalized(datebuf);
XtVaSetValues(grid,
XmNcolumn,
2,
XmNrow, row,
XmNcellString, str,
NULL);
free(datebuf);
XmStringFree(str);
XtVaSetValues(grid, XmNrow, row, XmNrowUserData, e,
NULL);
row++;
}
if(count > row) {
XmLGridDeleteRows(grid, XmCONTENT, row, count-row);
}
if(maxWidth <
16) {
maxWidth =
16;
}
XtVaSetValues(grid,
XmNcolumnRangeStart,
0,
XmNcolumnRangeEnd,
0,
XmNcolumnWidth, maxWidth,
XmNcellAlignment, XmALIGNMENT_LEFT,
XmNcolumnSizePolicy, XmVARIABLE,
NULL);
XtVaSetValues(grid,
XmNcolumnRangeStart,
1,
XmNcolumnRangeEnd,
1,
XmNcolumnWidth,
9,
XmNcellAlignment, XmALIGNMENT_LEFT,
XmNcolumnSizePolicy, XmVARIABLE,
NULL);
XtVaSetValues(grid,
XmNcolumnRangeStart,
2,
XmNcolumnRangeEnd,
2,
XmNcolumnWidth,
16,
XmNcellAlignment, XmALIGNMENT_RIGHT,
XmNcolumnSizePolicy, XmVARIABLE,
NULL);
FileListDetailAdjustColWidth(grid);
}
static void FileListDetailSelect(Widget fsb, Widget view,
const char *item) {
XnFileSelectionBox w = (XnFileSelectionBox)fsb;
int numRows =
0;
XtVaGetValues(w->fsb.grid, XmNrows, &numRows,
NULL);
XmLGridColumn col = XmLGridGetColumn(w->fsb.grid, XmCONTENT,
0);
for(
int i=
0;i<numRows;i++) {
XmLGridRow row = XmLGridGetRow(w->fsb.grid, XmCONTENT, i);
FileElm *elm =
NULL;
XtVaGetValues(w->fsb.grid, XmNrowPtr, row, XmNcolumnPtr, col, XmNrowUserData, &elm,
NULL);
if(elm) {
if(!strcmp(item, FileName(elm->path))) {
XmLGridSelectRow(w->fsb.grid, i, False);
XmLGridFocusAndShowRow(w->fsb.grid, i
+1);
break;
}
}
}
}
static void FileListDetailCleanup(Widget fsb, Widget view,
void *userData) {
XnFileSelectionBox data = userData;
Cardinal rows =
0;
XtVaGetValues(data->fsb.grid, XmNrows, &rows,
NULL);
XmLGridDeleteRows(data->fsb.grid, XmCONTENT,
0, rows);
}
static void FileListDetailDestroy(Widget fsb, Widget view,
void *userData) {
}
#endif
static void create_folder(Widget w, XnFileSelectionBox data, XmSelectionBoxCallbackStruct *cbs) {
char *fileName =
NULL;
XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &fileName);
char *newFolder = ConcatPath(data->fsb.currentPath ? data->fsb.currentPath :
"", fileName);
if(mkdir(newFolder,
S_IRWXU |
S_IRGRP |
S_IXGRP |
S_IROTH |
S_IXOTH)) {
char errmsg[
256];
snprintf(errmsg,
256, data->fsb.errorFolder, strerror(errno));
ErrDialog(data, data->fsb.errorTitle, errmsg);
}
else {
char *p = strdup(data->fsb.currentPath);
filedialog_update_dir(data, p);
free(p);
}
free(newFolder);
XtDestroyWidget(XtParent(w));
}
static void new_folder_cancel(Widget w, XnFileSelectionBox data, XtPointer d) {
XtDestroyWidget(XtParent(w));
}
static void FSBNewFolder(Widget w, XnFileSelectionBox data, XtPointer u)
{
Arg args[
16];
int n =
0;
XtSetArg(args[n], XmNdialogTitle, data->fsb.labelNewFolder); n++;
XtSetArg (args[n], XmNselectionLabelString, data->fsb.labelDirectoryName); n++;
XtSetArg(args[n], XmNokLabelString, data->fsb.labelOk); n++;
XtSetArg(args[n], XmNcancelLabelString, data->fsb.labelCancel); n++;
Widget dialog = XmCreatePromptDialog (w,
"NewFolderPrompt", args, n);
Widget help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
XtUnmanageChild(help);
XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)create_folder, data);
XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)new_folder_cancel, data);
XtManageChild(dialog);
}
static void FSBHome(Widget w, XnFileSelectionBox data, XtPointer u) {
const char *homePath = data->fsb.homePath ? data->fsb.homePath : GetHomeDir();
filedialog_update_dir(data, homePath);
PathBarSetPath(data->fsb.pathBar, homePath);
}
static int file_cmp_field =
0;
static int file_cmp_order =
1;
static int filecmp(
const void *f1,
const void *f2)
{
const FileElm *file1 = f1;
const FileElm *file2 = f2;
if(file1->isDirectory != file2->isDirectory) {
return file1->isDirectory < file2->isDirectory;
}
int cmp_field = file_cmp_field;
int cmp_order = file_cmp_order;
if(file1->isDirectory) {
cmp_field =
0;
cmp_order =
1;
}
int ret =
0;
switch(cmp_field) {
case 0: {
ret = strcmp(FileName(file1->path), FileName(file2->path));
break;
}
case 1: {
if(file1->size < file2->size) {
ret =
-1;
}
else if(file1->size == file2->size) {
ret =
0;
}
else {
ret =
1;
}
break;
}
case 2: {
if(file1->lastModified < file2->lastModified) {
ret =
-1;
}
else if(file1->lastModified == file2->lastModified) {
ret =
0;
}
else {
ret =
1;
}
break;
}
}
return ret * cmp_order;
}
static void free_files(FileElm *ls,
int count)
{
for(
int i=
0;i<count;i++) {
if(ls[i].path) {
free(ls[i].path);
}
}
free(ls);
}
static void filedialog_cleanup_filedata(XnFileSelectionBox data)
{
free_files(data->fsb.dirs, data->fsb.dircount);
free_files(data->fsb.files, data->fsb.filecount);
data->fsb.dirs =
NULL;
data->fsb.files =
NULL;
data->fsb.dircount =
0;
data->fsb.filecount =
0;
data->fsb.maxnamelen =
0;
}
#define FILE_ARRAY_SIZE 1024
static void file_array_add(FileElm **files,
int *alloc,
int *count, FileElm elm) {
int c = *count;
int a = *alloc;
if(c >= a) {
a *=
2;
FileElm *newarray = realloc(*files,
sizeof(FileElm) * a);
*files = newarray;
*alloc = a;
}
(*files)[c] = elm;
c++;
*count = c;
}
static int filedialog_update_dir(XnFileSelectionBox data,
const char *path)
{
DIR *dir =
NULL;
if(path) {
dir = opendir(path);
if(!dir) {
char errmsg[
256];
snprintf(errmsg,
256, data->fsb.errorOpenDir, strerror(errno));
ErrDialog(data, data->fsb.errorTitle, errmsg);
return 1;
}
}
FSBView view = data->fsb.view[data->fsb.selectedview];
view.cleanup((Widget)data, view.widget, view.userData);
if(view.useDirList) {
XmListDeleteAllItems(data->fsb.dirlist);
}
if(path) {
int dircount =
0;
int filecount =
0;
size_t maxNameLen =
0;
FileElm *dirs = calloc(
sizeof(FileElm),
FILE_ARRAY_SIZE);
FileElm *files = calloc(
sizeof(FileElm),
FILE_ARRAY_SIZE);
int dirs_alloc =
FILE_ARRAY_SIZE;
int files_alloc =
FILE_ARRAY_SIZE;
filedialog_cleanup_filedata(data);
XmTextFieldSetString(data->fsb.path, (
char*)path);
char *oldPath = data->fsb.currentPath;
data->fsb.currentPath = strdup(path);
if(oldPath) {
free(oldPath);
}
path = data->fsb.currentPath;
struct dirent *ent;
while((ent = readdir(dir)) !=
NULL) {
if(!strcmp(ent->d_name,
".") || !strcmp(ent->d_name,
"..")) {
continue;
}
char *entpath = ConcatPath(path, ent->d_name);
struct stat s;
if(stat(entpath, &s)) {
free(entpath);
continue;
}
FileElm new_entry;
new_entry.path = entpath;
new_entry.isDirectory =
S_ISDIR(s.st_mode);
new_entry.size = (
uint64_t)s.st_size;
new_entry.lastModified = s.st_mtime;
size_t nameLen = strlen(ent->d_name);
if(nameLen > maxNameLen) {
maxNameLen = nameLen;
}
if(new_entry.isDirectory) {
file_array_add(&dirs, &dirs_alloc, &dircount, new_entry);
}
else {
file_array_add(&files, &files_alloc, &filecount, new_entry);
}
}
closedir(dir);
data->fsb.dirs = dirs;
data->fsb.files = files;
data->fsb.dircount = dircount;
data->fsb.filecount = filecount;
data->fsb.maxnamelen = maxNameLen;
qsort(dirs, dircount,
sizeof(FileElm), filecmp);
qsort(files, filecount,
sizeof(FileElm), filecmp);
}
Widget filterTF = XmDropDownGetText(data->fsb.filter);
char *filter = XmTextFieldGetString(filterTF);
char *filterStr = filter;
if(!filter || strlen(filter) ==
0) {
filterStr =
"*";
}
if(view.useDirList) {
FileListWidgetAdd(data, data->fsb.dirlist, data->fsb.showHidden,
NULL, data->fsb.dirs, data->fsb.dircount);
view.update(
(Widget)data,
view.widget,
NULL,
0,
data->fsb.files,
data->fsb.filecount,
filterStr,
data->fsb.maxnamelen,
view.userData);
}
else {
view.update(
(Widget)data,
view.widget,
data->fsb.dirs,
data->fsb.dircount,
data->fsb.files,
data->fsb.filecount,
filterStr,
data->fsb.maxnamelen,
view.userData);
}
if(filter) {
XtFree(filter);
}
return 0;
}
static void dirlist_activate(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb)
{
char *path = set_selected_path(data, cb->item);
if(path) {
if(!filedialog_update_dir(data, path)) {
PathBarSetPath(data->fsb.pathBar, path);
data->fsb.selIsDir =
TRUE;
}
}
}
static void dirlist_select(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb)
{
char *path = set_selected_path(data, cb->item);
if(path) {
data->fsb.selIsDir =
TRUE;
}
}
static void filedialog_enable_detailview(Widget w, XnFileSelectionBox data, XmToggleButtonCallbackStruct *tb) {
SelectView(data, tb->set);
}
static void filedialog_setshowhidden(
Widget w,
XnFileSelectionBox data,
XmToggleButtonCallbackStruct *tb)
{
data->fsb.showHidden = tb->set;
filedialog_update_dir(data,
NULL);
}
static void filedialog_filter(Widget w, XnFileSelectionBox data, XtPointer c)
{
filedialog_update_dir(data,
NULL);
}
static void filedialog_update_filter(Widget w, XnFileSelectionBox data, XtPointer c)
{
filedialog_update_dir(data,
NULL);
}
static void filedialog_goup(Widget w, XnFileSelectionBox data, XtPointer d)
{
char *newPath = ParentPath(data->fsb.currentPath);
filedialog_update_dir(data, newPath);
PathBarSetPath(data->fsb.pathBar, newPath);
free(newPath);
}
static void filedialog_ok(Widget w, XnFileSelectionBox data, XtPointer d)
{
if(data->fsb.type ==
FILEDIALOG_SAVE) {
char *newName = XmTextFieldGetString(data->fsb.name);
if(newName) {
if(strchr(newName,
'/')) {
ErrDialog(data, data->fsb.errorTitle, data->fsb.errorIllegalChar);
XtFree(newName);
return;
}
if(strlen(newName) >
0) {
char *selPath = ConcatPath(data->fsb.currentPath, newName);
if(data->fsb.selectedPath) free(data->fsb.selectedPath);
data->fsb.selectedPath = selPath;
}
XtFree(newName);
data->fsb.selIsDir = False;
}
}
if(data->fsb.selectedPath) {
if(!data->fsb.selIsDir) {
data->fsb.status =
FILEDIALOG_OK;
data->fsb.end = True;
FileSelectionCallback(data, data->fsb.okCallback, XmCR_OK, data->fsb.selectedPath);
}
}
}
static void filedialog_cancel(Widget w, XnFileSelectionBox data, XtPointer d)
{
data->fsb.end =
1;
data->fsb.status =
FILEDIALOG_CANCEL;
FileSelectionCallback(data, data->fsb.cancelCallback, XmCR_CANCEL, data->fsb.currentPath);
}
static void filedialog_help(Widget w, XnFileSelectionBox data, XtPointer d)
{
FileSelectionCallback(data, data->manager.help_callback, XmCR_HELP, data->fsb.currentPath);
}
static void FileSelectionCallback(XnFileSelectionBox fsb, XtCallbackList cb,
int reason,
const char *value) {
XmFileSelectionBoxCallbackStruct cbs;
memset(&cbs,
0,
sizeof(XmFileSelectionBoxCallbackStruct));
char *dir = fsb->fsb.currentPath;
size_t dirlen = dir ? strlen(dir) :
0;
if(dir && dirlen >
0) {
char *dir2 =
NULL;
if(dir[dirlen
-1] !=
'/') {
dir2 = malloc(dirlen
+2);
memcpy(dir2, dir, dirlen);
dir2[dirlen] =
'/';
dir2[dirlen
+1] =
'\0';
dirlen++;
dir = dir2;
}
cbs.dir = XmStringCreateLocalized(dir);
cbs.dir_length = dirlen;
if(dir2) {
free(dir2);
}
}
else {
cbs.dir = XmStringCreateLocalized(
"");
cbs.dir_length =
0;
}
cbs.reason = reason;
cbs.value = XmStringCreateLocalized((
char*)value);
cbs.length = strlen(value);
XtCallCallbackList((Widget)fsb, cb, (XtPointer)&cbs);
XmStringFree(cbs.dir);
XmStringFree(cbs.value);
}
static void CreateUI(XnFileSelectionBox w) {
Arg args[
32];
int n =
0;
XmString str;
int widget_spacing = w->fsb.widgetSpacing;
int window_spacing = w->fsb.windowSpacing;
Widget form = (Widget)w;
int type = w->fsb.type;
XtVaSetValues((Widget)w, XmNautoUnmanage, False,
NULL);
n =
0;
XtSetArg(args[n], XmNlabelString, w->fsb.labelDirUp); n++;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopOffset, window_spacing); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
XtSetArg(args[n], XmNresizable, True); n++;
XtSetArg(args[n], XmNarrowDirection, XmARROW_UP); n++;
w->fsb.dirUp = XmCreatePushButton(form,
"DirUp", args, n);
XtManageChild(w->fsb.dirUp);
XtAddCallback(w->fsb.dirUp, XmNactivateCallback,
(XtCallbackProc)filedialog_goup, w);
n =
0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopOffset, window_spacing); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
XtSetArg(args[n], XmNshadowThickness,
0); n++;
Widget viewframe = XmCreateForm(form,
"vframe", args, n);
XtManageChild(viewframe);
w->fsb.viewMenu = XmCreatePulldownMenu(viewframe,
"menu",
NULL,
0);
Widget view;
if(w->fsb.showViewMenu) {
n =
0;
XtSetArg(args[n], XmNsubMenuId, w->fsb.viewMenu); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNmarginHeight,
0); n++;
XtSetArg(args[n], XmNmarginWidth,
0); n++;
view = XmCreateOptionMenu(viewframe,
"option_menu", args, n);
XtManageChild(view);
w->fsb.viewOption = view;
w->fsb.detailToggleButton =
NULL;
}
else {
n =
0;
str = XmStringCreateLocalized(w->fsb.labelDetailView);
XtSetArg(args[n], XmNlabelString, str); n++;
XtSetArg(args[n], XmNfillOnSelect, True); n++;
XtSetArg(args[n], XmNindicatorOn, False); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
if(w->fsb.selectedview ==
1) {
XtSetArg(args[n], XmNset,
1); n++;
}
w->fsb.detailToggleButton = XmCreateToggleButton(viewframe,
"ToggleDetailView", args, n);
XtManageChild(w->fsb.detailToggleButton);
view = w->fsb.detailToggleButton;
XmStringFree(str);
XtAddCallback(
w->fsb.detailToggleButton,
XmNvalueChangedCallback,
(XtCallbackProc)filedialog_enable_detailview,
w);
w->fsb.viewOption =
NULL;
}
n =
0;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightWidget, view); n++;
XtSetArg(args[n], XmNmarginHeight,
0); n++;
XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
XtSetArg(args[n], XmNlabelString, w->fsb.labelNewFolder); n++;
w->fsb.newFolder = XmCreatePushButton(viewframe,
"NewFolder", args, n);
XtManageChild(w->fsb.newFolder);
XtAddCallback(
w->fsb.newFolder,
XmNactivateCallback,
(XtCallbackProc)FSBNewFolder,
w);
n =
0;
XtSetArg(args[n], XmNlabelString, w->fsb.labelHome); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNrightWidget, w->fsb.newFolder); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
w->fsb.home = XmCreatePushButton(viewframe,
"Home", args, n);
XtManageChild(w->fsb.home);
XtAddCallback(
w->fsb.home,
XmNactivateCallback,
(XtCallbackProc)FSBHome,
w);
if(w->fsb.detailToggleButton) {
Dimension highlight, shadow;
XtVaGetValues(w->fsb.newFolder, XmNshadowThickness, &shadow, XmNhighlightThickness, &highlight,
NULL);
XtVaSetValues(w->fsb.detailToggleButton, XmNshadowThickness, shadow, XmNhighlightThickness, highlight,
NULL);
}
n =
0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopOffset, window_spacing); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNleftWidget, w->fsb.dirUp); n++;
XtSetArg(args[n], XmNleftOffset, widget_spacing); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNrightWidget, viewframe); n++;
XtSetArg(args[n], XmNrightOffset, widget_spacing); n++;
XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); n++;
Widget pathBarFrame = XmCreateFrame(form,
"pathbar_frame", args, n);
XtManageChild(pathBarFrame);
w->fsb.pathBar = CreatePathBar(pathBarFrame, args,
0);
w->fsb.pathBar->getpathelm = ui_default_pathelm_func;
w->fsb.pathBar->updateDir = (updatedir_callback)filedialog_update_dir;
w->fsb.pathBar->updateDirData = w;
XtManageChild(w->fsb.pathBar->widget);
w->fsb.path = XmCreateTextField(form,
"textfield", args,
0);
XtVaSetValues(w->fsb.dirUp, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, pathBarFrame,
NULL);
if(!w->fsb.showViewMenu) {
XtVaSetValues(viewframe, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, pathBarFrame,
NULL);
}
n =
0;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNtopWidget, pathBarFrame); n++;
XtSetArg(args[n], XmNtopOffset,
2*widget_spacing); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
w->fsb.filterForm = XmCreateForm(form,
"filterform", args, n);
XtManageChild(w->fsb.filterForm);
n =
0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNlabelString, w->fsb.labelDirectories); n++;
w->fsb.lsDirLabel = XmCreateLabel(w->fsb.filterForm,
"labelDirs", args, n);
XtManageChild(w->fsb.lsDirLabel);
n =
0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNleftPosition,
35); n++;
XtSetArg(args[n], XmNleftOffset, widget_spacing); n++;
XtSetArg(args[n], XmNlabelString, w->fsb.labelFiles); n++;
w->fsb.lsFileLabel = XmCreateLabel(w->fsb.filterForm,
"labelFiles", args, n);
XtManageChild(w->fsb.lsFileLabel);
if(w->fsb.showHiddenButton) {
n =
0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNlabelString, w->fsb.labelShowHiddenFiles); n++;
XtSetArg(args[n], XmNset, w->fsb.showHidden); n++;
w->fsb.showHiddenButtonW = XmCreateToggleButton(w->fsb.filterForm,
"showHidden", args, n);
XtManageChild(w->fsb.showHiddenButtonW);
XtAddCallback(w->fsb.showHiddenButtonW, XmNvalueChangedCallback,
(XtCallbackProc)filedialog_setshowhidden, w);
}
n =
0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNlabelString, w->fsb.labelFilterButton); n++;
if(w->fsb.showHiddenButton) {
XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNrightWidget, w->fsb.showHiddenButtonW); n++;
}
else {
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
}
w->fsb.filterButton = XmCreatePushButton(w->fsb.filterForm,
"filedialog_filter", args, n);
XtManageChild(w->fsb.filterButton);
XtAddCallback(w->fsb.filterButton, XmNactivateCallback,
(XtCallbackProc)filedialog_filter, w);
n =
0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNleftWidget, w->fsb.lsFileLabel); n++;
XtSetArg(args[n], XmNleftOffset, widget_spacing); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNrightWidget, w->fsb.filterButton); n++;
XtSetArg(args[n], XmNrightOffset, widget_spacing); n++;
XtSetArg(args[n], XmNshowLabel, False); n++;
XtSetArg(args[n], XmNuseTextField, True); n++;
XtSetArg(args[n], XmNverify, False); n++;
w->fsb.filter = XmCreateDropDown(w->fsb.filterForm,
"filedialog_filter_textfield", args, n);
XtManageChild(w->fsb.filter);
XmTextFieldSetString(XmDropDownGetText(w->fsb.filter), w->fsb.filterStr);
XtAddCallback(XmDropDownGetText(w->fsb.filter), XmNactivateCallback,
(XtCallbackProc)filedialog_filter, w);
XtAddCallback(w->fsb.filter, XmNupdateTextCallback,
(XtCallbackProc)filedialog_update_filter, w);
Widget filterList = XmDropDownGetList(w->fsb.filter);
str = XmStringCreateSimple(
"*");
XmListAddItem(filterList, str,
0);
XmStringFree(str);
n =
0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomOffset, window_spacing); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
XtSetArg(args[n], XmNtopOffset, widget_spacing *
2); n++;
Widget buttons = XmCreateForm(form,
"buttons", args, n);
XtManageChild(buttons);
n =
0;
str = type ==
FILEDIALOG_OPEN ? w->fsb.labelOpen : w->fsb.labelSave;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNlabelString, str); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNrightPosition,
14); n++;
w->fsb.okBtn = XmCreatePushButton(buttons,
"filedialog_open", args, n);
XtManageChild(w->fsb.okBtn);
XmStringFree(str);
XtAddCallback(w->fsb.okBtn, XmNactivateCallback,
(XtCallbackProc)filedialog_ok, w);
n =
0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNlabelString, w->fsb.labelHelp); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNleftPosition,
86); n++;
w->fsb.helpBtn = XmCreatePushButton(buttons,
"filedialog_help", args, n);
XtManageChild(w->fsb.helpBtn);
XtAddCallback(w->fsb.helpBtn, XmNactivateCallback,
(XtCallbackProc)filedialog_help, w);
n =
0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNleftPosition,
43); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNrightPosition,
57); n++;
XtSetArg(args[n], XmNlabelString, w->fsb.labelCancel); n++;
w->fsb.cancelBtn = XmCreatePushButton(buttons,
"filedialog_cancel", args, n);
XtManageChild(w->fsb.cancelBtn);
XtAddCallback(w->fsb.cancelBtn, XmNactivateCallback,
(XtCallbackProc)filedialog_cancel, w);
n =
0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNbottomWidget, buttons); n++;
XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftOffset,
1); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset,
1); n++;
w->fsb.separator = XmCreateSeparator(form,
"ofd_separator", args, n);
XtManageChild(w->fsb.separator);
Widget bottomWidget = w->fsb.separator;
n =
0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNbottomWidget, w->fsb.separator); n++;
XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
w->fsb.name = XmCreateTextField(form,
"textfield", args, n);
XtAddCallback(w->fsb.name, XmNactivateCallback,
(XtCallbackProc)filedialog_ok, w);
n =
0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNbottomWidget, w->fsb.name); n++;
XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
XtSetArg(args[n], XmNlabelString, w->fsb.labelFileName); n++;
w->fsb.nameLabel = XmCreateLabel(form,
"label", args, n);
if(type ==
FILEDIALOG_SAVE) {
bottomWidget = w->fsb.nameLabel;
XtManageChild(w->fsb.name);
XtManageChild(w->fsb.nameLabel);
}
w->fsb.bottom_widget = bottomWidget;
n =
0;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNtopWidget, w->fsb.filterForm); n++;
XtSetArg(args[n], XmNtopOffset, widget_spacing); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNbottomWidget, bottomWidget); n++;
XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
XtSetArg(args[n], XmNwidth,
580); n++;
XtSetArg(args[n], XmNheight,
400); n++;
w->fsb.listform = XmCreateForm(form,
"fds_listform", args, n);
n =
0;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopWidget, w->fsb.lsDirLabel); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNrightPosition,
35); n++;
w->fsb.dirlist = XmCreateScrolledList(w->fsb.listform,
"dirlist", args, n);
Dimension width, height;
XtMakeResizeRequest(w->fsb.dirlist,
150,
200, &width, &height);
XtManageChild(w->fsb.dirlist);
XtAddCallback(
w->fsb.dirlist,
XmNdefaultActionCallback,
(XtCallbackProc)dirlist_activate,
w);
XtAddCallback(
w->fsb.dirlist,
XmNbrowseSelectionCallback,
(XtCallbackProc)dirlist_select,
w);
XnFileSelectionBoxAddView(
(Widget)w,
w->fsb.labelListView,
CreateListView,
FileListUpdate,
FileListSelect,
FileListCleanup,
FileListDestroy,
True,
w);
#ifdef FSB_ENABLE_DETAIL
XnFileSelectionBoxAddView(
(Widget)w,
w->fsb.labelDetailView,
CreateDetailView,
FileListDetailUpdate,
FileListDetailSelect,
FileListDetailCleanup,
FileListDetailDestroy,
True,
w);
#endif
XtManageChild(w->fsb.listform);
int selview = w->fsb.selectedview;
if(selview <
2) {
XtManageChild(w->fsb.view[selview].widget);
}
else {
w->fsb.selectedview =
0;
}
if(w->fsb.selectedPath) {
char *parentPath = ParentPath(w->fsb.selectedPath);
filedialog_update_dir(w, parentPath);
PathBarSetPath(w->fsb.pathBar, parentPath);
free(parentPath);
if(w->fsb.type ==
FILEDIALOG_SAVE) {
XmTextFieldSetString(w->fsb.name, FileName(w->fsb.selectedPath));
}
}
else {
char cwd[
PATH_MAX];
const char *currentPath = w->fsb.currentPath;
if(!currentPath) {
if(getcwd(cwd,
PATH_MAX)) {
currentPath = cwd;
}
else {
currentPath = GetHomeDir();
}
}
filedialog_update_dir(w, currentPath);
PathBarSetPath(w->fsb.pathBar, w->fsb.currentPath);
}
w->fsb.selectedview = selview;
XtVaSetValues((Widget)w, XmNcancelButton, w->fsb.cancelBtn,
NULL);
w->fsb.gui_created =
1;
}
static char* FSBDialogTitle(Widget widget) {
XnFileSelectionBox w = (XnFileSelectionBox)widget;
if(w->fsb.type ==
FILEDIALOG_OPEN) {
return w->fsb.labelOpenFileTitle;
}
else {
return w->fsb.labelSaveFileTitle;
}
}
static FSBViewWidgets CreateView(XnFileSelectionBox w, FSBViewCreateProc create,
void *userData, Boolean useDirList) {
Arg args[
64];
int n =
0;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
if(useDirList) {
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNleftWidget, w->fsb.dirlist); n++;
XtSetArg(args[n], XmNleftOffset, w->fsb.widgetSpacing); n++;
}
else {
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopOffset, w->fsb.widgetSpacing); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
}
return create(w->fsb.listform, args, n, userData);
}
typedef struct FSBViewSelection {
XnFileSelectionBox fsb;
int index;
} FSBViewSelection;
static void SelectView(XnFileSelectionBox f,
int view) {
FSBView current = f->fsb.view[f->fsb.selectedview];
FSBView newview = f->fsb.view[view];
XtUnmanageChild(current.widget);
if(newview.useDirList != current.useDirList) {
if(current.useDirList) {
XtUnmanageChild(f->fsb.listform);
}
else {
XtManageChild(f->fsb.listform);
}
}
current.cleanup((Widget)f, current.widget, current.userData);
XtManageChild(newview.widget);
f->fsb.selectedview = view;
filedialog_update_dir(f,
NULL);
XmProcessTraversal(newview.focus, XmTRAVERSE_CURRENT);
}
static void SelectViewCallback(Widget w, FSBViewSelection *data, XtPointer u) {
SelectView(data->fsb, data->index);
}
static void SelectViewItemDestroy(Widget w, FSBViewSelection *data, XtPointer u) {
free(data);
}
static void AddViewMenuItem(XnFileSelectionBox w,
const char *name,
int viewIndex) {
Arg args[
4];
int n =
0;
XmString label = XmStringCreateLocalized((
char*)name);
XtSetArg(args[n], XmNlabelString, label); n++;
XtSetArg(args[
1], XmNpositionIndex, w->fsb.selectedview == w->fsb.numviews ?
0 : w->fsb.numviews
+1); n++;
Widget item = XmCreatePushButton(w->fsb.viewMenu,
"menuitem", args, n);
if(viewIndex ==
0) {
w->fsb.viewSelectorList = item;
}
else if(viewIndex ==
1) {
w->fsb.viewSelectorDetail = item;
}
XtManageChild(item);
XmStringFree(label);
FSBViewSelection *data = malloc(
sizeof(FSBViewSelection));
data->fsb = w;
data->index = viewIndex;
XtAddCallback(
item,
XmNactivateCallback,
(XtCallbackProc)SelectViewCallback,
data);
XtAddCallback(
item,
XmNdestroyCallback,
(XtCallbackProc)SelectViewItemDestroy,
data);
}
static FSBViewWidgets CreateListView(Widget parent, ArgList args,
int n,
void *userData) {
XnFileSelectionBox fsb = (XnFileSelectionBox)userData;
XtSetArg(args[n], XmNshadowThickness,
0); n++;
Widget frame = XmCreateFrame(parent,
"filelistframe", args, n);
fsb->fsb.filelist = XmCreateScrolledList(frame,
"filelist",
NULL,
0);
XtManageChild(fsb->fsb.filelist);
XtAddCallback(
fsb->fsb.filelist,
XmNdefaultActionCallback,
(XtCallbackProc)FileListActivateCB,
userData);
XtAddCallback(
fsb->fsb.filelist,
XmNbrowseSelectionCallback,
(XtCallbackProc)FileListSelectCB,
userData);
fsb->fsb.listContextMenu = CreateContextMenu(fsb, fsb->fsb.filelist, FileContextMenuCB);
FSBViewWidgets widgets;
widgets.view = frame;
widgets.focus = fsb->fsb.filelist;
return widgets;
}
#ifdef FSB_ENABLE_DETAIL
static void set_path_from_row(XnFileSelectionBox data,
int row) {
FileElm *elm =
NULL;
XmLGridRow rowPtr = XmLGridGetRow(data->fsb.grid, XmCONTENT, row);
XtVaGetValues(data->fsb.grid, XmNrowPtr, rowPtr, XmNrowUserData, &elm,
NULL);
if(!elm) {
fprintf(stderr,
"error: no row data\n");
return;
}
char *path = strdup(elm->path);
data->fsb.selIsDir = False;
if(data->fsb.type ==
FILEDIALOG_SAVE) {
XmTextFieldSetString(data->fsb.name, FileName(path));
}
if(data->fsb.selectedPath) {
free(data->fsb.selectedPath);
}
data->fsb.selectedPath = path;
}
static void grid_select(Widget w, XnFileSelectionBox data, XmLGridCallbackStruct *cb) {
set_path_from_row(data, cb->row);
}
static void grid_activate(Widget w, XnFileSelectionBox data, XmLGridCallbackStruct *cb) {
set_path_from_row(data, cb->row);
data->fsb.end = True;
data->fsb.status =
FILEDIALOG_OK;
FileSelectionCallback(data, data->fsb.okCallback, XmCR_OK, data->fsb.selectedPath);
}
static void grid_key_pressed(Widget w, XnFileSelectionBox data, XmLGridCallbackStruct *cb) {
char chars[
16];
KeySym keysym;
int nchars;
nchars = XLookupString(&cb->event->xkey, chars,
15, &keysym,
NULL);
if(nchars ==
0)
return;
int row =
0;
int selectedRow = XmLGridGetSelectedRow(w);
int match =
-1;
for(
int i=
0;i<data->fsb.filecount;i++) {
const char *name = FileName(data->fsb.files[i].path);
if(!data->fsb.showHidden && name[
0] ==
'.')
continue;
size_t namelen = strlen(name);
size_t cmplen = namelen < nchars ? namelen : nchars;
if(!memcmp(name, chars, cmplen)) {
if(row <= selectedRow) {
if(match ==
-1) {
match = row;
}
}
else {
match = row;
break;
}
}
row++;
}
if(match >
-1) {
XmLGridSelectRow(w, match, True);
XmLGridFocusAndShowRow(w, match
+1);
}
else {
XBell(XtDisplay(w),
0);
}
}
static void grid_header_clicked(Widget w, XnFileSelectionBox data, XmLGridCallbackStruct *cb) {
int new_cmp_field =
0;
switch(cb->column) {
case 0: {
new_cmp_field =
0;
break;
}
case 1: {
new_cmp_field =
1;
break;
}
case 2: {
new_cmp_field =
2;
break;
}
}
if(new_cmp_field == file_cmp_field) {
file_cmp_order = -file_cmp_order;
}
else {
file_cmp_field = new_cmp_field;
file_cmp_order =
1;
}
int sort_type = file_cmp_order ==
1 ? XmSORT_ASCENDING : XmSORT_DESCENDING;
XmLGridSetSort(data->fsb.grid, file_cmp_field, sort_type);
qsort(data->fsb.files, data->fsb.filecount,
sizeof(FileElm), filecmp);
filedialog_update_dir(data,
NULL);
}
static FSBViewWidgets CreateDetailView(Widget parent, ArgList args,
int n,
void *userData) {
XnFileSelectionBox w = userData;
XtSetArg(args[n], XmNshadowThickness,
0); n++;
Widget gridcontainer = XmCreateFrame(parent,
"gridcontainer", args, n);
XtManageChild(gridcontainer);
n =
0;
XtSetArg(args[n], XmNcolumns,
3); n++;
XtSetArg(args[n], XmNheadingColumns,
0); n++;
XtSetArg(args[n], XmNheadingRows,
1); n++;
XtSetArg(args[n], XmNallowColumnResize,
1); n++;
XtSetArg(args[n], XmNsimpleHeadings, w->fsb.detailHeadings); n++;
XtSetArg(args[n], XmNhorizontalSizePolicy, XmCONSTANT); n++;
w->fsb.grid = XmLCreateGrid(gridcontainer,
"grid", args, n);
XmLGridSetIgnoreModifyVerify(w->fsb.grid, True);
XtManageChild(w->fsb.grid);
XtVaSetValues(
w->fsb.grid,
XmNcellDefaults, True,
XtVaTypedArg, XmNblankBackground, XmRString,
"white",
6,
XtVaTypedArg, XmNcellBackground, XmRString,
"white",
6,
NULL);
XtAddCallback(w->fsb.grid, XmNselectCallback, (XtCallbackProc)grid_select, w);
XtAddCallback(w->fsb.grid, XmNactivateCallback, (XtCallbackProc)grid_activate, w);
XtAddCallback(w->fsb.grid, XmNheaderClickCallback, (XtCallbackProc)grid_header_clicked, w);
XtAddCallback(w->fsb.grid, XmNgridKeyPressedCallback, (XtCallbackProc)grid_key_pressed, w);
w->fsb.gridContextMenu = CreateContextMenu(w, w->fsb.grid, FileContextMenuCB);
FSBViewWidgets widgets;
widgets.view = gridcontainer;
widgets.focus = w->fsb.grid;
return widgets;
}
#endif
const char* GetHomeDir(
void) {
char *home = getenv(
"HOME");
if(!home) {
home = getenv(
"USERPROFILE");
if(!home) {
home =
"/";
}
}
return home;
}
static char* ConcatPath(
const char *parent,
const char *name)
{
size_t parentlen = strlen(parent);
size_t namelen = strlen(name);
size_t pathlen = parentlen + namelen +
2;
char *path = malloc(pathlen);
memcpy(path, parent, parentlen);
if(parentlen >
0 && parent[parentlen
-1] !=
'/') {
path[parentlen] =
'/';
parentlen++;
}
if(name[
0] ==
'/') {
name++;
namelen--;
}
memcpy(path+parentlen, name, namelen);
path[parentlen+namelen] =
'\0';
return path;
}
static char* FileName(
char *path) {
int si =
0;
int osi =
0;
int i =
0;
int p =
0;
char c;
while((c = path[i]) !=
0) {
if(c ==
'/') {
osi = si;
si = i;
p =
1;
}
i++;
}
char *name = path + si + p;
if(name[
0] ==
0) {
name = path + osi + p;
if(name[
0] ==
0) {
return path;
}
}
return name;
}
static char* ParentPath(
const char *path) {
char *name = FileName((
char*)path);
size_t namelen = strlen(name);
size_t pathlen = strlen(path);
size_t parentlen = pathlen - namelen;
if(parentlen ==
0) {
parentlen++;
}
char *parent = malloc(parentlen +
1);
memcpy(parent, path, parentlen);
parent[parentlen] =
'\0';
return parent;
}
Widget XnCreateFileSelectionDialog(
Widget parent,
String name,
ArgList arglist,
Cardinal argcount)
{
Widget dialog = XmCreateDialogShell(parent,
"FileDialog",
NULL,
0);
Widget fsb = XnCreateFileSelectionBox(dialog, name, arglist, argcount);
char *title = FSBDialogTitle(fsb);
XtVaSetValues(dialog, XmNtitle, title,
NULL);
return fsb;
}
Widget XnCreateFileSelectionBox(
Widget parent,
String name,
ArgList arglist,
Cardinal argcount)
{
Widget fsb = XtCreateWidget(name, xnFsbWidgetClass, parent, arglist, argcount);
return fsb;
}
void XnFileSelectionBoxAddView(
Widget fsb,
const char *name,
FSBViewCreateProc create,
FSBViewUpdateProc update,
FSBViewSelectProc select,
FSBViewCleanupProc cleanup,
FSBViewDestroyProc destroy,
Boolean useDirList,
void *userData)
{
XnFileSelectionBox f = (XnFileSelectionBox)fsb;
if(f->fsb.numviews >=
FSB_MAX_VIEWS) {
fprintf(stderr,
"XnFileSelectionBox: too many views\n");
return;
}
FSBView view;
view.update = update;
view.select = select;
view.cleanup = cleanup;
view.destroy = destroy;
view.useDirList = useDirList;
view.userData = userData;
FSBViewWidgets widgets = CreateView(f, create, userData, useDirList);
view.widget = widgets.view;
view.focus = widgets.focus;
AddViewMenuItem(f, name, f->fsb.numviews);
f->fsb.view[f->fsb.numviews++] = view;
}
Widget XnFileSelectionBoxWorkArea(Widget fsb) {
XnFileSelectionBox f = (XnFileSelectionBox)fsb;
return f->fsb.workarea;
}
Widget XnFileSelectionBoxGetChild(Widget fsb,
enum XnFSBChild child) {
XnFileSelectionBox w = (XnFileSelectionBox)fsb;
switch(child) {
case XnFSB_DIR_UP_BUTTON:
return w->fsb.dirUp;
case XnFSB_HOME_BUTTON:
return w->fsb.home;
case XnFSB_NEW_FOLDER_BUTTON:
return w->fsb.newFolder;
case XnFSB_DETAIL_TOGGLE_BUTTON:
return w->fsb.detailToggleButton;
case XnFSB_VIEW_OPTION_BUTTON:
return w->fsb.viewOption;
case XnFSB_FILTER_DROPDOWN:
return w->fsb.filter;
case XnFSB_FILTER_BUTTON:
return w->fsb.filterButton;
case XnFSB_SHOW_HIDDEN_TOGGLE_BUTTON:
return w->fsb.showHiddenButtonW;
case XnFSB_DIRECTORIES_LABEL:
return w->fsb.lsDirLabel;
case XnFSB_FILES_LABEL:
return w->fsb.lsFileLabel;
case XnFSB_DIRLIST:
return w->fsb.dirlist;
case XnFSB_FILELIST:
return w->fsb.filelist;
case XnFSB_GRID:
return w->fsb.grid;
case XnFSB_OK_BUTTON:
return w->fsb.okBtn;
case XnFSB_CANCEL_BUTTON:
return w->fsb.cancelBtn;
case XnFSB_HELP_BUTTON:
return w->fsb.helpBtn;
}
return NULL;
}
void XnFileSelectionBoxDeleteFilters(Widget fsb) {
XnFileSelectionBox w = (XnFileSelectionBox)fsb;
Widget filterList = XmDropDownGetList(w->fsb.filter);
XmListDeleteAllItems(filterList);
}
void XnFileSelectionBoxAddFilter(Widget fsb,
const char *filter) {
XnFileSelectionBox w = (XnFileSelectionBox)fsb;
Widget filterList = XmDropDownGetList(w->fsb.filter);
XmString str = XmStringCreateSimple((
char*)filter);
XmListAddItem(filterList, str,
0);
XmStringFree(str);
}