WINGs: Added 'const' attribute to function 'WMCreateHashTable'
[wmaker-crm.git] / WINGs / wfilepanel.c
blob10eea3362b296b3cd381bfb82388a67d7f25bed6
2 #include <sys/types.h>
3 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <dirent.h>
7 #include <limits.h>
8 #include <errno.h>
9 #include <stdint.h>
11 #include "WINGsP.h"
12 #include "wconfig.h"
14 #ifndef PATH_MAX
15 #define PATH_MAX 1024
16 #endif
18 typedef struct W_FilePanel {
19 WMWindow *win;
21 WMLabel *iconLabel;
22 WMLabel *titleLabel;
24 WMFrame *line;
26 WMLabel *nameLabel;
27 WMBrowser *browser;
29 WMButton *okButton;
30 WMButton *cancelButton;
32 WMButton *homeButton;
33 WMButton *trashcanButton;
34 WMButton *createDirButton;
35 WMButton *disketteButton;
36 WMButton *unmountButton;
38 WMView *accessoryView;
40 WMTextField *fileField;
42 char **fileTypes;
44 struct {
45 unsigned int canExit:1;
46 unsigned int canceled:1; /* clicked on cancel */
47 unsigned int filtered:1;
48 unsigned int canChooseFiles:1;
49 unsigned int canChooseDirectories:1;
50 unsigned int autoCompletion:1;
51 unsigned int showAllFiles:1;
52 unsigned int canFreeFileTypes:1;
53 unsigned int fileMustExist:1;
54 unsigned int panelType:1;
55 } flags;
56 } W_FilePanel;
58 /* Type of panel */
59 #define WP_OPEN 0
60 #define WP_SAVE 1
62 #define PWIDTH 330
63 #define PHEIGHT 360
65 static void listDirectoryOnColumn(WMFilePanel * panel, int column, const char *path);
66 static void browserClick(WMWidget *widget, void *p_panel);
67 static void browserDClick(WMWidget *widget, void *p_panel);
69 static void fillColumn(WMBrowserDelegate * self, WMBrowser * bPtr, int column, WMList * list);
71 static void normalizePath(char *s);
73 static void deleteFile(WMWidget *widget, void *p_panel);
74 static void createDir(WMWidget *widget, void *p_panel);
75 static void goHome(WMWidget *widget, void *p_panel);
76 static void goFloppy(WMWidget *widget, void *p_panel);
77 static void goUnmount(WMWidget *widget, void *p_panel);
78 static void buttonClick(WMWidget *widget, void *p_panel);
80 static char *getCurrentFileName(WMFilePanel * panel);
82 static void handleEvents(XEvent * event, void *data);
84 static WMBrowserDelegate browserDelegate = {
85 NULL, /* data */
86 fillColumn, /* createRowsForColumn */
87 NULL, /* titleOfColumn */
88 NULL, /* didScroll */
89 NULL /* willScroll */
92 static int closestListItem(WMList * list, const char *text, Bool exact)
94 WMListItem *item;
95 WMArray *items = WMGetListItems(list);
96 int i, nb_item, len = strlen(text);
98 if (len == 0)
99 return -1;
101 nb_item = WMGetArrayItemCount(items);
102 for (i = 0; i < nb_item; i++) {
103 item = WMGetFromArray(items, i);
104 if ((exact && strcmp(item->text, text) == 0) ||
105 (!exact && strncmp(item->text, text, len) == 0)) {
106 return i;
110 return -1;
113 static void textChangedObserver(void *observerData, WMNotification * notification)
115 W_FilePanel *panel = (W_FilePanel *) observerData;
116 char *text;
117 WMList *list;
118 int col = WMGetBrowserNumberOfColumns(panel->browser) - 1;
119 int i;
120 uintptr_t textEvent;
122 if (!(list = WMGetBrowserListInColumn(panel->browser, col)))
123 return;
125 text = WMGetTextFieldText(panel->fileField);
126 textEvent = (uintptr_t)WMGetNotificationClientData(notification);
128 if (panel->flags.autoCompletion && textEvent != WMDeleteTextEvent)
129 i = closestListItem(list, text, False);
130 else
131 i = closestListItem(list, text, True);
133 WMSelectListItem(list, i);
134 if (i >= 0 && panel->flags.autoCompletion) {
135 WMListItem *item = WMGetListItem(list, i);
136 int textLen = strlen(text), itemTextLen = strlen(item->text);
137 int visibleItems = WMWidgetHeight(list) / WMGetListItemHeight(list);
139 WMSetListPosition(list, i - visibleItems / 2);
141 if (textEvent != WMDeleteTextEvent) {
142 WMRange range;
144 WMInsertTextFieldText(panel->fileField, &item->text[textLen], textLen);
145 range.position = textLen;
146 range.count = itemTextLen - textLen;
147 WMSelectTextFieldRange(panel->fileField, range);
148 /*WMSetTextFieldCursorPosition(panel->fileField, itemTextLen); */
152 wfree(text);
155 static void textEditedObserver(void *observerData, WMNotification * notification)
157 W_FilePanel *panel = (W_FilePanel *) observerData;
159 if ((uintptr_t)WMGetNotificationClientData(notification) == WMReturnTextMovement) {
160 WMPerformButtonClick(panel->okButton);
164 static WMFilePanel *makeFilePanel(WMScreen * scrPtr, const char *name, const char *title)
166 WMFilePanel *fPtr;
167 WMFont *largeFont;
168 WMPixmap *icon;
170 fPtr = wmalloc(sizeof(WMFilePanel));
172 fPtr->win = WMCreateWindowWithStyle(scrPtr, name, WMTitledWindowMask | WMResizableWindowMask);
173 WMResizeWidget(fPtr->win, PWIDTH, PHEIGHT);
174 WMSetWindowTitle(fPtr->win, "");
176 WMCreateEventHandler(WMWidgetView(fPtr->win), StructureNotifyMask, handleEvents, fPtr);
177 WMSetWindowMinSize(fPtr->win, PWIDTH, PHEIGHT);
179 fPtr->iconLabel = WMCreateLabel(fPtr->win);
180 WMResizeWidget(fPtr->iconLabel, 64, 64);
181 WMMoveWidget(fPtr->iconLabel, 0, 0);
182 WMSetLabelImagePosition(fPtr->iconLabel, WIPImageOnly);
183 icon = WMCreateApplicationIconBlendedPixmap(scrPtr, (RColor *) NULL);
184 if (icon) {
185 WMSetLabelImage(fPtr->iconLabel, icon);
186 WMReleasePixmap(icon);
187 } else {
188 WMSetLabelImage(fPtr->iconLabel, scrPtr->applicationIconPixmap);
191 fPtr->titleLabel = WMCreateLabel(fPtr->win);
192 WMResizeWidget(fPtr->titleLabel, PWIDTH - 64, 64);
193 WMMoveWidget(fPtr->titleLabel, 64, 0);
194 largeFont = WMBoldSystemFontOfSize(scrPtr, 24);
195 WMSetLabelFont(fPtr->titleLabel, largeFont);
196 WMReleaseFont(largeFont);
197 WMSetLabelText(fPtr->titleLabel, title);
199 fPtr->line = WMCreateFrame(fPtr->win);
200 WMMoveWidget(fPtr->line, 0, 64);
201 WMResizeWidget(fPtr->line, PWIDTH, 2);
202 WMSetFrameRelief(fPtr->line, WRGroove);
204 fPtr->browser = WMCreateBrowser(fPtr->win);
205 WMSetBrowserAllowEmptySelection(fPtr->browser, True);
206 WMSetBrowserDelegate(fPtr->browser, &browserDelegate);
207 WMSetBrowserAction(fPtr->browser, browserClick, fPtr);
208 WMSetBrowserDoubleAction(fPtr->browser, browserDClick, fPtr);
209 WMMoveWidget(fPtr->browser, 7, 72);
210 WMResizeWidget(fPtr->browser, PWIDTH - 14, 200);
211 WMHangData(fPtr->browser, fPtr);
213 fPtr->nameLabel = WMCreateLabel(fPtr->win);
214 WMMoveWidget(fPtr->nameLabel, 7, 282);
215 WMResizeWidget(fPtr->nameLabel, 55, 14);
216 WMSetLabelText(fPtr->nameLabel, _("Name:"));
218 fPtr->fileField = WMCreateTextField(fPtr->win);
219 WMMoveWidget(fPtr->fileField, 60, 278);
220 WMResizeWidget(fPtr->fileField, PWIDTH - 60 - 10, 24);
221 WMAddNotificationObserver(textEditedObserver, fPtr, WMTextDidEndEditingNotification, fPtr->fileField);
222 WMAddNotificationObserver(textChangedObserver, fPtr, WMTextDidChangeNotification, fPtr->fileField);
224 fPtr->okButton = WMCreateCommandButton(fPtr->win);
225 WMMoveWidget(fPtr->okButton, 245, 325);
226 WMResizeWidget(fPtr->okButton, 75, 28);
227 WMSetButtonText(fPtr->okButton, _("OK"));
228 WMSetButtonImage(fPtr->okButton, scrPtr->buttonArrow);
229 WMSetButtonAltImage(fPtr->okButton, scrPtr->pushedButtonArrow);
230 WMSetButtonImagePosition(fPtr->okButton, WIPRight);
231 WMSetButtonAction(fPtr->okButton, buttonClick, fPtr);
233 fPtr->cancelButton = WMCreateCommandButton(fPtr->win);
234 WMMoveWidget(fPtr->cancelButton, 165, 325);
235 WMResizeWidget(fPtr->cancelButton, 75, 28);
236 WMSetButtonText(fPtr->cancelButton, _("Cancel"));
237 WMSetButtonAction(fPtr->cancelButton, buttonClick, fPtr);
239 fPtr->trashcanButton = WMCreateCommandButton(fPtr->win);
240 WMMoveWidget(fPtr->trashcanButton, 7, 325);
241 WMResizeWidget(fPtr->trashcanButton, 28, 28);
242 WMSetButtonImagePosition(fPtr->trashcanButton, WIPImageOnly);
243 WMSetButtonImage(fPtr->trashcanButton, scrPtr->trashcanIcon);
244 WMSetButtonAltImage(fPtr->trashcanButton, scrPtr->altTrashcanIcon);
245 WMSetButtonAction(fPtr->trashcanButton, deleteFile, fPtr);
247 fPtr->createDirButton = WMCreateCommandButton(fPtr->win);
248 WMMoveWidget(fPtr->createDirButton, 37, 325);
249 WMResizeWidget(fPtr->createDirButton, 28, 28);
250 WMSetButtonImagePosition(fPtr->createDirButton, WIPImageOnly);
251 WMSetButtonImage(fPtr->createDirButton, scrPtr->createDirIcon);
252 WMSetButtonAltImage(fPtr->createDirButton, scrPtr->altCreateDirIcon);
253 WMSetButtonAction(fPtr->createDirButton, createDir, fPtr);
255 fPtr->homeButton = WMCreateCommandButton(fPtr->win);
256 WMMoveWidget(fPtr->homeButton, 67, 325);
257 WMResizeWidget(fPtr->homeButton, 28, 28);
258 WMSetButtonImagePosition(fPtr->homeButton, WIPImageOnly);
259 WMSetButtonImage(fPtr->homeButton, scrPtr->homeIcon);
260 WMSetButtonAltImage(fPtr->homeButton, scrPtr->altHomeIcon);
261 WMSetButtonAction(fPtr->homeButton, goHome, fPtr);
263 fPtr->disketteButton = WMCreateCommandButton(fPtr->win);
264 WMMoveWidget(fPtr->disketteButton, 97, 325);
265 WMResizeWidget(fPtr->disketteButton, 28, 28);
266 WMSetButtonImagePosition(fPtr->disketteButton, WIPImageOnly);
267 WMSetButtonImage(fPtr->disketteButton, scrPtr->disketteIcon);
268 WMSetButtonAltImage(fPtr->disketteButton, scrPtr->altDisketteIcon);
269 WMSetButtonAction(fPtr->disketteButton, goFloppy, fPtr);
271 fPtr->unmountButton = WMCreateCommandButton(fPtr->win);
272 WMMoveWidget(fPtr->unmountButton, 127, 325);
273 WMResizeWidget(fPtr->unmountButton, 28, 28);
274 WMSetButtonImagePosition(fPtr->unmountButton, WIPImageOnly);
275 WMSetButtonImage(fPtr->unmountButton, scrPtr->unmountIcon);
276 WMSetButtonAltImage(fPtr->unmountButton, scrPtr->altUnmountIcon);
277 WMSetButtonAction(fPtr->unmountButton, goUnmount, fPtr);
278 WMSetButtonEnabled(fPtr->unmountButton, False);
280 WMRealizeWidget(fPtr->win);
281 WMMapSubwidgets(fPtr->win);
283 WMSetFocusToWidget(fPtr->fileField);
284 WMSetTextFieldCursorPosition(fPtr->fileField, 0);
286 WMLoadBrowserColumnZero(fPtr->browser);
288 WMSetWindowInitialPosition(fPtr->win,
289 (scrPtr->rootView->size.width - WMWidgetWidth(fPtr->win)) / 2,
290 (scrPtr->rootView->size.height - WMWidgetHeight(fPtr->win)) / 2);
292 fPtr->flags.canChooseFiles = 1;
293 fPtr->flags.canChooseDirectories = 1;
294 fPtr->flags.autoCompletion = 1;
296 return fPtr;
299 WMOpenPanel *WMGetOpenPanel(WMScreen * scrPtr)
301 WMFilePanel *panel;
303 if (scrPtr->sharedOpenPanel)
304 return scrPtr->sharedOpenPanel;
306 panel = makeFilePanel(scrPtr, "openFilePanel", _("Open"));
307 panel->flags.fileMustExist = 1;
308 panel->flags.panelType = WP_OPEN;
310 scrPtr->sharedOpenPanel = panel;
312 return panel;
315 WMSavePanel *WMGetSavePanel(WMScreen * scrPtr)
317 WMFilePanel *panel;
319 if (scrPtr->sharedSavePanel)
320 return scrPtr->sharedSavePanel;
322 panel = makeFilePanel(scrPtr, "saveFilePanel", _("Save"));
323 panel->flags.fileMustExist = 0;
324 panel->flags.panelType = WP_SAVE;
326 scrPtr->sharedSavePanel = panel;
328 return panel;
331 void WMFreeFilePanel(WMFilePanel * panel)
333 if (panel == WMWidgetScreen(panel->win)->sharedSavePanel) {
334 WMWidgetScreen(panel->win)->sharedSavePanel = NULL;
336 if (panel == WMWidgetScreen(panel->win)->sharedOpenPanel) {
337 WMWidgetScreen(panel->win)->sharedOpenPanel = NULL;
339 WMRemoveNotificationObserver(panel);
340 WMUnmapWidget(panel->win);
341 WMDestroyWidget(panel->win);
342 wfree(panel);
346 WMRunModalFilePanelForDirectory(WMFilePanel * panel, WMWindow * owner, char *path, const char *name, char **fileTypes)
348 WMScreen *scr = WMWidgetScreen(panel->win);
350 if (name && !owner) {
351 WMSetWindowTitle(panel->win, name);
354 WMChangePanelOwner(panel->win, owner);
356 WMSetFilePanelDirectory(panel, path);
358 switch (panel->flags.panelType) {
359 case WP_OPEN:
360 if (fileTypes)
361 panel->flags.filtered = 1;
362 panel->fileTypes = fileTypes;
363 if (name == NULL)
364 name = _("Open");
365 break;
366 case WP_SAVE:
367 panel->fileTypes = NULL;
368 panel->flags.filtered = 0;
369 if (name == NULL)
370 name = _("Save");
371 break;
372 default:
373 break;
376 WMSetLabelText(panel->titleLabel, name);
378 WMMapWidget(panel->win);
380 WMRunModalLoop(scr, W_VIEW(panel->win));
382 /* Must withdraw window because the next time we map
383 * it, it might have a different transient owner.
385 WMCloseWindow(panel->win);
387 return (panel->flags.canceled ? False : True);
390 void WMSetFilePanelDirectory(WMFilePanel * panel, char *path)
392 WMList *list;
393 WMListItem *item;
394 int col;
395 char *rest;
397 rest = WMSetBrowserPath(panel->browser, path);
398 if (strcmp(path, "/") == 0)
399 rest = NULL;
401 col = WMGetBrowserSelectedColumn(panel->browser);
402 list = WMGetBrowserListInColumn(panel->browser, col);
403 if (list && (item = WMGetListSelectedItem(list))) {
404 if (item->isBranch) {
405 WMSetTextFieldText(panel->fileField, rest);
406 } else {
407 WMSetTextFieldText(panel->fileField, item->text);
409 } else {
410 WMSetTextFieldText(panel->fileField, rest);
414 void WMSetFilePanelCanChooseDirectories(WMFilePanel * panel, Bool flag)
416 panel->flags.canChooseDirectories = ((flag == 0) ? 0 : 1);
419 void WMSetFilePanelCanChooseFiles(WMFilePanel * panel, Bool flag)
421 panel->flags.canChooseFiles = ((flag == 0) ? 0 : 1);
424 void WMSetFilePanelAutoCompletion(WMFilePanel * panel, Bool flag)
426 panel->flags.autoCompletion = ((flag == 0) ? 0 : 1);
429 char *WMGetFilePanelFileName(WMFilePanel * panel)
431 return getCurrentFileName(panel);
434 void WMSetFilePanelAccessoryView(WMFilePanel * panel, WMView * view)
436 WMView *v;
438 panel->accessoryView = view;
440 v = WMWidgetView(panel->win);
442 W_ReparentView(view, v, 0, 0);
444 W_MoveView(view, (v->size.width - v->size.width) / 2, 300);
447 WMView *WMGetFilePanelAccessoryView(WMFilePanel * panel)
449 return panel->accessoryView;
452 static char *get_name_from_path(const char *path)
454 int size;
456 assert(path != NULL);
458 size = strlen(path);
460 /* remove trailing / */
461 while (size > 0 && path[size - 1] == '/')
462 size--;
463 /* directory was root */
464 if (size == 0)
465 return wstrdup("/");
467 while (size > 0 && path[size - 1] != '/')
468 size--;
470 return wstrdup(&(path[size]));
473 static Bool filterFileName(WMFilePanel * panel, const char *file, Bool isDirectory)
475 return True;
478 #define CAST(item) (*((WMListItem**)item))
479 static int comparer(const void *a, const void *b)
481 if (CAST(a)->isBranch == CAST(b)->isBranch)
482 return (strcmp(CAST(a)->text, CAST(b)->text));
483 if (CAST(a)->isBranch)
484 return (-1);
485 return (1);
488 #undef CAST
490 static void listDirectoryOnColumn(WMFilePanel * panel, int column, const char *path)
492 WMBrowser *bPtr = panel->browser;
493 struct dirent *dentry;
494 DIR *dir;
495 struct stat stat_buf;
496 char pbuf[PATH_MAX + 16];
497 char *name;
499 assert(column >= 0);
500 assert(path != NULL);
502 /* put directory name in the title */
503 name = get_name_from_path(path);
504 WMSetBrowserColumnTitle(bPtr, column, name);
505 wfree(name);
507 dir = opendir(path);
509 if (!dir) {
510 #ifdef VERBOSE
511 printf(_("WINGs: could not open directory %s\n"), path);
512 #endif
513 return;
516 /* list contents in the column */
517 while ((dentry = readdir(dir))) {
518 if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
519 continue;
521 if (wstrlcpy(pbuf, path, sizeof(pbuf)) >= sizeof(pbuf))
522 goto out;
523 if (strcmp(path, "/") != 0 &&
524 wstrlcat(pbuf, "/", sizeof(pbuf)) >= sizeof(pbuf))
525 goto out;
526 if (wstrlcat(pbuf, dentry->d_name, sizeof(pbuf)) >= sizeof(pbuf))
527 goto out;
529 if (stat(pbuf, &stat_buf) != 0) {
530 #ifdef VERBOSE
531 printf(_("WINGs: could not stat %s\n"), pbuf);
532 #endif
533 continue;
534 } else {
535 int isDirectory;
537 isDirectory = S_ISDIR(stat_buf.st_mode);
539 if (filterFileName(panel, dentry->d_name, isDirectory))
540 WMInsertBrowserItem(bPtr, column, -1, dentry->d_name, isDirectory);
543 WMSortBrowserColumnWithComparer(bPtr, column, comparer);
545 out:
546 closedir(dir);
549 static void fillColumn(WMBrowserDelegate * self, WMBrowser * bPtr, int column, WMList * list)
551 char *path;
552 WMFilePanel *panel;
554 /* Parameter not used, but tell the compiler that it is ok */
555 (void) self;
556 (void) list;
558 if (column > 0) {
559 path = WMGetBrowserPathToColumn(bPtr, column - 1);
560 } else {
561 path = wstrdup("/");
564 panel = WMGetHangedData(bPtr);
565 listDirectoryOnColumn(panel, column, path);
566 wfree(path);
569 static void browserDClick(WMWidget *widget, void *p_panel)
571 WMFilePanel *panel = p_panel;
573 /* Parameter not used, but tell the compiler that it is ok */
574 (void) widget;
576 WMPerformButtonClick(panel->okButton);
579 static void browserClick(WMWidget *widget, void *p_panel)
581 WMBrowser *bPtr = (WMBrowser *) widget;
582 WMFilePanel *panel = p_panel;
583 int col = WMGetBrowserSelectedColumn(bPtr);
584 WMListItem *item = WMGetBrowserSelectedItemInColumn(bPtr, col);
586 if (!item || item->isBranch)
587 WMSetTextFieldText(panel->fileField, NULL);
588 else {
589 WMSetTextFieldText(panel->fileField, item->text);
593 static void showError(WMScreen * scr, WMWindow * owner, const char *s, const char *file)
595 char *errStr;
597 if (file) {
598 errStr = wmalloc(strlen(file) + strlen(s) + 1);
599 sprintf(errStr, s, file);
600 } else {
601 errStr = wstrdup(s);
603 WMRunAlertPanel(scr, owner, _("Error"), errStr, _("OK"), NULL, NULL);
604 wfree(errStr);
607 static void createDir(WMWidget *widget, void *p_panel)
609 WMFilePanel *panel = p_panel;
610 char *dirName, *directory, *file;
611 size_t slen;
612 WMScreen *scr = WMWidgetScreen(panel->win);
614 /* Parameter not used, but tell the compiler that it is ok */
615 (void) widget;
617 dirName = WMRunInputPanel(scr, panel->win, _("Create Directory"),
618 _("Enter directory name"), "", _("OK"), _("Cancel"));
619 if (!dirName)
620 return;
622 /* if `dirName' is an absolute path, don't mind `directory'.
623 * normalize as needed (possibly not needed at all?) */
624 normalizePath(dirName);
625 if (*dirName != '/') {
626 directory = getCurrentFileName(panel);
627 normalizePath(directory);
628 } else {
629 directory = NULL;
632 slen = strlen(dirName) + (directory ? strlen(directory) + 1 /* "/" */ : 0) + 1 /* NULL */;
633 file = wmalloc(slen);
635 if (directory &&
636 (wstrlcat(file, directory, slen) >= slen ||
637 wstrlcat(file, "/", slen) >= slen))
638 goto out;
640 if (wstrlcat(file, dirName, slen) >= slen)
641 goto out;
643 if (mkdir(file, 00777) != 0) {
644 #define __msgbufsize__ 512
645 char *buffer = wmalloc(__msgbufsize__);
646 snprintf(buffer, __msgbufsize__, _("Can not create %s: %s"), file, strerror(errno));
647 showError(scr, panel->win, buffer, NULL);
648 wfree(buffer);
649 #undef __msgbufsize__
650 } else {
651 WMSetFilePanelDirectory(panel, file);
654 out:
655 if (dirName)
656 wfree(dirName);
657 if (directory)
658 wfree(directory);
659 if (file)
660 wfree(file);
664 *----------------------------------------------------------------------
665 * normalizePath--
666 * Remove multiple consecutive and any trailing slashes from
667 * a path.
668 *----------------------------------------------------------------------
670 static void normalizePath(char *s)
672 int i, j, found;
674 found = 0;
675 for (i = 0; s[i]; (void)(!found && i++)) {
676 found = 0;
677 if (s[i] == '/' && s[i+1] == '/') {
678 int nslash = 1;
679 found = 1;
680 i++;
681 while (s[i+nslash] == '/')
682 nslash++;
683 for (j = 0; s[i+j+nslash]; j++)
684 s[i+j] = s[i+j+nslash];
685 s[i+j] = '\0';
688 if (i > 1 && s[--i] == '/')
689 s[i] = '\0';
693 static void deleteFile(WMWidget *widget, void *p_panel)
695 WMFilePanel *panel = p_panel;
696 char *file;
697 char buffer[512];
698 struct stat filestat;
699 WMScreen *scr = WMWidgetScreen(panel->win);
701 /* Parameter not used, but tell the compiler that it is ok */
702 (void) widget;
704 file = getCurrentFileName(panel);
705 normalizePath(file);
707 if (stat(file, &filestat) == -1) {
708 snprintf(buffer, sizeof(buffer),
709 _("Can not find %s: %s"),
710 file, strerror(errno));
711 showError(scr, panel->win, buffer, NULL);
712 goto out;
715 snprintf(buffer, sizeof(buffer), _("Delete %s %s?"),
716 S_ISDIR(filestat.st_mode) ? _("directory") : _("file"), file);
718 if (!WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
719 _("Warning"), buffer, _("OK"), _("Cancel"), NULL)) {
721 if (remove(file) == -1) {
722 snprintf(buffer, sizeof(buffer),
723 _("Removing %s failed: %s"),
724 file, strerror(errno));
725 showError(scr, panel->win, buffer, NULL);
726 } else {
727 char *s = strrchr(file, '/');
728 if (s)
729 s[0] = 0;
730 WMSetFilePanelDirectory(panel, file);
734 out:
735 if (file)
736 wfree(file);
739 static void goUnmount(WMWidget *widget, void *p_panel)
743 static void goFloppy(WMWidget *widget, void *p_panel)
745 WMFilePanel *panel = p_panel;
746 struct stat filestat;
747 WMScreen *scr = WMWidgetScreen(panel->win);
749 /* Parameter not used, but tell the compiler that it is ok */
750 (void) widget;
752 if (stat(WINGsConfiguration.floppyPath, &filestat)) {
753 showError(scr, panel->win, _("An error occured browsing '%s'."), WINGsConfiguration.floppyPath);
754 return;
755 } else if (!S_ISDIR(filestat.st_mode)) {
756 showError(scr, panel->win, _("'%s' is not a directory."), WINGsConfiguration.floppyPath);
757 return;
760 WMSetFilePanelDirectory(panel, WINGsConfiguration.floppyPath);
763 static void goHome(WMWidget *widget, void *p_panel)
765 WMFilePanel *panel = p_panel;
766 char *home;
768 /* Parameter not used, but tell the compiler that it is ok */
769 (void) widget;
771 /* home is statically allocated. Don't free it! */
772 home = wgethomedir();
773 if (!home)
774 return;
776 WMSetFilePanelDirectory(panel, home);
779 static void handleEvents(XEvent * event, void *data)
781 W_FilePanel *pPtr = (W_FilePanel *) data;
782 W_View *view = WMWidgetView(pPtr->win);
784 if (event->type == ConfigureNotify) {
785 if (event->xconfigure.width != view->size.width || event->xconfigure.height != view->size.height) {
786 unsigned int newWidth = event->xconfigure.width;
787 unsigned int newHeight = event->xconfigure.height;
788 int newColumnCount;
790 W_ResizeView(view, newWidth, newHeight);
791 WMResizeWidget(pPtr->line, newWidth, 2);
792 WMResizeWidget(pPtr->browser, newWidth - 14, newHeight - (PHEIGHT - 200));
793 WMResizeWidget(pPtr->fileField, newWidth - 60 - 10, 24);
794 WMMoveWidget(pPtr->nameLabel, 7, newHeight - (PHEIGHT - 282));
795 WMMoveWidget(pPtr->fileField, 60, newHeight - (PHEIGHT - 278));
796 WMMoveWidget(pPtr->okButton, newWidth - (PWIDTH - 245), newHeight - (PHEIGHT - 325));
797 WMMoveWidget(pPtr->cancelButton, newWidth - (PWIDTH - 165), newHeight - (PHEIGHT - 325));
799 WMMoveWidget(pPtr->trashcanButton, 7, newHeight - (PHEIGHT - 325));
800 WMMoveWidget(pPtr->createDirButton, 37, newHeight - (PHEIGHT - 325));
801 WMMoveWidget(pPtr->homeButton, 67, newHeight - (PHEIGHT - 325));
802 WMMoveWidget(pPtr->disketteButton, 97, newHeight - (PHEIGHT - 325));
803 WMMoveWidget(pPtr->unmountButton, 127, newHeight - (PHEIGHT - 325));
805 newColumnCount = (newWidth - 14) / 140;
806 WMSetBrowserMaxVisibleColumns(pPtr->browser, newColumnCount);
811 static char *getCurrentFileName(WMFilePanel * panel)
813 char *path;
814 char *file;
815 char *ret;
816 size_t slen;
818 path = WMGetBrowserPath(panel->browser);
820 if (!path)
821 return NULL;
823 if (path[strlen(path) -1] != '/')
824 return path;
826 file = WMGetTextFieldText(panel->fileField);
827 slen = strlen(path) + strlen(file) + 1;
828 ret = wmalloc(slen);
830 if (*file != '/' &&
831 wstrlcat(ret, path, slen) >= slen)
832 goto error;
834 if (wstrlcat(ret, file, slen) >= slen)
835 goto error;
837 wfree(file);
838 wfree(path);
839 return ret;
841 error:
842 wfree(file);
843 wfree(path);
844 wfree(ret);
846 return NULL;
850 static Bool validOpenFile(WMFilePanel * panel)
852 WMListItem *item;
853 int col, haveFile = 0;
854 char *file = WMGetTextFieldText(panel->fileField);
856 if (file[0] != '\0')
857 haveFile = 1;
858 wfree(file);
860 col = WMGetBrowserSelectedColumn(panel->browser);
861 item = WMGetBrowserSelectedItemInColumn(panel->browser, col);
862 if (item) {
863 if (item->isBranch && !panel->flags.canChooseDirectories && !haveFile)
864 return False;
865 else if (!item->isBranch && !panel->flags.canChooseFiles)
866 return False;
867 else
868 return True;
869 } else {
870 /* we compute for / here */
871 if (!panel->flags.canChooseDirectories && !haveFile)
872 return False;
873 else
874 return True;
876 return True;
879 static void buttonClick(WMWidget *widget, void *p_panel)
881 WMButton *bPtr = (WMButton *) widget;
882 WMFilePanel *panel = p_panel;
883 WMRange range;
885 if (bPtr == panel->okButton) {
886 if (!validOpenFile(panel))
887 return;
888 if (panel->flags.fileMustExist) {
889 char *file;
891 file = getCurrentFileName(panel);
892 if (access(file, F_OK) != 0) {
893 WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
894 _("Error"), _("File does not exist."), _("OK"), NULL, NULL);
895 wfree(file);
896 return;
898 wfree(file);
900 panel->flags.canceled = 0;
901 } else
902 panel->flags.canceled = 1;
904 range.count = range.position = 0;
905 WMSelectTextFieldRange(panel->fileField, range);
906 WMBreakModalLoop(WMWidgetScreen(bPtr));