bag tree finished.. updated code to new bags
[wmaker-crm.git] / WINGs / wfilepanel.c
blob6852020c58ccea8768d0b4d0987429d470157dcd
2 #include "WINGsP.h"
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include <dirent.h>
8 #include <limits.h>
9 #include <errno.h>
11 #ifndef PATH_MAX
12 #define PATH_MAX 1024
13 #endif
15 #ifndef FLOPPY_PATH
16 #define FLOPPY_PATH "/floppy"
17 #endif
19 typedef struct W_FilePanel {
20 WMWindow *win;
22 WMLabel *iconLabel;
23 WMLabel *titleLabel;
25 WMFrame *line;
27 WMLabel *nameLabel;
28 WMBrowser *browser;
30 WMButton *okButton;
31 WMButton *cancelButton;
33 WMButton *homeButton;
34 WMButton *trashcanButton;
35 WMButton *createDirButton;
36 WMButton *disketteButton;
37 WMButton *unmountButton;
39 WMView *accessoryView;
41 WMTextField *fileField;
43 char **fileTypes;
45 struct {
46 unsigned int canExit:1;
47 unsigned int canceled:1; /* clicked on cancel */
48 unsigned int done:1;
49 unsigned int filtered:1;
50 unsigned int canChooseFiles:1;
51 unsigned int canChooseDirectories:1;
52 unsigned int autoCompletion:1;
53 unsigned int showAllFiles:1;
54 unsigned int canFreeFileTypes:1;
55 unsigned int fileMustExist:1;
56 unsigned int panelType:1;
57 } flags;
58 } W_FilePanel;
61 /* Type of panel */
62 #define WP_OPEN 0
63 #define WP_SAVE 1
65 #define PWIDTH 330
66 #define PHEIGHT 360
68 static void listDirectoryOnColumn(WMFilePanel *panel, int column, char *path);
69 static void browserClick();
70 static void browserDClick();
72 static void fillColumn(WMBrowserDelegate *self, WMBrowser *bPtr, int column,
73 WMList *list);
75 static void deleteFile();
77 static void createDir();
79 static void goHome();
81 static void goFloppy();
83 static void goUnmount();
85 static void buttonClick();
87 static char *getCurrentFileName(WMFilePanel *panel);
89 static void handleEvents(XEvent *event, void *data);
93 static WMBrowserDelegate browserDelegate = {
94 NULL, /* data */
95 fillColumn, /* createRowsForColumn */
96 NULL, /* titleOfColumn */
97 NULL, /* didScroll */
98 NULL /* willScroll */
102 static int
103 closestListItem(WMList *list, char *text, Bool exact)
105 WMListItem *item;
106 WMBag *items = WMGetListItems(list);
107 WMBagIterator i;
108 int len = strlen(text);
110 if (len==0)
111 return -1;
113 WM_ITERATE_BAG(items, item, i) {
114 if (strlen(item->text) >= len &&
115 ((exact && strcmp(item->text, text)==0) ||
116 (!exact && strncmp(item->text, text, len)==0))) {
117 return WMBagIndexForIterator(items, i);
121 return -1;
125 static void
126 textChangedObserver(void *observerData, WMNotification *notification)
128 W_FilePanel *panel = (W_FilePanel*)observerData;
129 char *text;
130 WMList *list;
131 int col = WMGetBrowserNumberOfColumns(panel->browser) - 1;
132 int i, textEvent;
134 if (!(list = WMGetBrowserListInColumn(panel->browser, col)))
135 return;
137 text = WMGetTextFieldText(panel->fileField);
138 textEvent = (int)WMGetNotificationClientData(notification);
140 if (panel->flags.autoCompletion && textEvent!=WMDeleteTextEvent)
141 i = closestListItem(list, text, False);
142 else
143 i = closestListItem(list, text, True);
145 WMSelectListItem(list, i);
146 if (i>=0 && panel->flags.autoCompletion) {
147 WMListItem *item = WMGetListItem(list, i);
148 int textLen = strlen(text), itemTextLen = strlen(item->text);
149 int visibleItems = WMWidgetHeight(list)/WMGetListItemHeight(list);
151 WMSetListPosition(list, i - visibleItems/2);
153 if (textEvent!=WMDeleteTextEvent) {
154 WMRange range;
156 WMInsertTextFieldText(panel->fileField, &item->text[textLen],
157 textLen);
158 range.position = textLen;
159 range.count = itemTextLen - textLen;
160 WMSelectTextFieldRange(panel->fileField, range);
161 /*WMSetTextFieldCursorPosition(panel->fileField, itemTextLen);*/
165 wfree(text);
169 static void
170 textEditedObserver(void *observerData, WMNotification *notification)
172 W_FilePanel *panel = (W_FilePanel*)observerData;
174 if ((int)WMGetNotificationClientData(notification)==WMReturnTextMovement) {
175 WMPerformButtonClick(panel->okButton);
181 static WMFilePanel*
182 makeFilePanel(WMScreen *scrPtr, char *name, char *title)
184 WMFilePanel *fPtr;
185 WMFont *largeFont;
187 fPtr = wmalloc(sizeof(WMFilePanel));
188 memset(fPtr, 0, sizeof(WMFilePanel));
190 fPtr->win = WMCreateWindowWithStyle(scrPtr, name, WMTitledWindowMask
191 |WMResizableWindowMask);
192 WMResizeWidget(fPtr->win, PWIDTH, PHEIGHT);
193 WMSetWindowTitle(fPtr->win, "");
195 WMCreateEventHandler(WMWidgetView(fPtr->win), StructureNotifyMask,
196 handleEvents, fPtr);
197 WMSetWindowMinSize(fPtr->win, PWIDTH, PHEIGHT);
200 fPtr->iconLabel = WMCreateLabel(fPtr->win);
201 WMResizeWidget(fPtr->iconLabel, 64, 64);
202 WMMoveWidget(fPtr->iconLabel, 0, 0);
203 WMSetLabelImagePosition(fPtr->iconLabel, WIPImageOnly);
204 WMSetLabelImage(fPtr->iconLabel, scrPtr->applicationIcon);
206 fPtr->titleLabel = WMCreateLabel(fPtr->win);
207 WMResizeWidget(fPtr->titleLabel, PWIDTH-64, 64);
208 WMMoveWidget(fPtr->titleLabel, 64, 0);
209 largeFont = WMBoldSystemFontOfSize(scrPtr, 24);
210 WMSetLabelFont(fPtr->titleLabel, largeFont);
211 WMReleaseFont(largeFont);
212 WMSetLabelText(fPtr->titleLabel, title);
214 fPtr->line = WMCreateFrame(fPtr->win);
215 WMMoveWidget(fPtr->line, 0, 64);
216 WMResizeWidget(fPtr->line, PWIDTH, 2);
217 WMSetFrameRelief(fPtr->line, WRGroove);
219 fPtr->browser = WMCreateBrowser(fPtr->win);
220 WMSetBrowserDelegate(fPtr->browser, &browserDelegate);
221 WMSetBrowserAction(fPtr->browser, browserClick, fPtr);
222 WMSetBrowserDoubleAction(fPtr->browser, browserDClick, fPtr);
223 WMMoveWidget(fPtr->browser, 7, 72);
224 WMResizeWidget(fPtr->browser, PWIDTH-14,200);
225 WMHangData(fPtr->browser, fPtr);
227 fPtr->nameLabel = WMCreateLabel(fPtr->win);
228 WMMoveWidget(fPtr->nameLabel, 7, 282);
229 WMResizeWidget(fPtr->nameLabel, 55, 14);
230 WMSetLabelText(fPtr->nameLabel, "Name:");
232 fPtr->fileField = WMCreateTextField(fPtr->win);
233 WMMoveWidget(fPtr->fileField, 60, 278);
234 WMResizeWidget(fPtr->fileField, PWIDTH-60-10, 24);
235 WMAddNotificationObserver(textEditedObserver, fPtr,
236 WMTextDidEndEditingNotification,
237 fPtr->fileField);
238 WMAddNotificationObserver(textChangedObserver, fPtr,
239 WMTextDidChangeNotification,
240 fPtr->fileField);
242 fPtr->okButton = WMCreateCommandButton(fPtr->win);
243 WMMoveWidget(fPtr->okButton, 245, 325);
244 WMResizeWidget(fPtr->okButton, 75, 28);
245 WMSetButtonText(fPtr->okButton, "OK");
246 WMSetButtonImage(fPtr->okButton, scrPtr->buttonArrow);
247 WMSetButtonAltImage(fPtr->okButton, scrPtr->pushedButtonArrow);
248 WMSetButtonImagePosition(fPtr->okButton, WIPRight);
249 WMSetButtonAction(fPtr->okButton, buttonClick, fPtr);
251 fPtr->cancelButton = WMCreateCommandButton(fPtr->win);
252 WMMoveWidget(fPtr->cancelButton, 165, 325);
253 WMResizeWidget(fPtr->cancelButton, 75, 28);
254 WMSetButtonText(fPtr->cancelButton, "Cancel");
255 WMSetButtonAction(fPtr->cancelButton, buttonClick, fPtr);
257 fPtr->trashcanButton = WMCreateCommandButton(fPtr->win);
258 WMMoveWidget(fPtr->trashcanButton, 7, 325);
259 WMResizeWidget(fPtr->trashcanButton, 28, 28);
260 WMSetButtonImagePosition(fPtr->trashcanButton, WIPImageOnly);
261 WMSetButtonImage(fPtr->trashcanButton, scrPtr->trashcanIcon);
262 WMSetButtonAltImage(fPtr->trashcanButton, scrPtr->altTrashcanIcon);
263 WMSetButtonAction(fPtr->trashcanButton, deleteFile, fPtr);
265 fPtr->createDirButton = WMCreateCommandButton(fPtr->win);
266 WMMoveWidget(fPtr->createDirButton, 37, 325);
267 WMResizeWidget(fPtr->createDirButton, 28, 28);
268 WMSetButtonImagePosition(fPtr->createDirButton, WIPImageOnly);
269 WMSetButtonImage(fPtr->createDirButton, scrPtr->createDirIcon);
270 WMSetButtonAltImage(fPtr->createDirButton, scrPtr->altCreateDirIcon);
271 WMSetButtonAction(fPtr->createDirButton, createDir, fPtr);
273 fPtr->homeButton = WMCreateCommandButton(fPtr->win);
274 WMMoveWidget(fPtr->homeButton, 67, 325);
275 WMResizeWidget(fPtr->homeButton, 28, 28);
276 WMSetButtonImagePosition(fPtr->homeButton, WIPImageOnly);
277 WMSetButtonImage(fPtr->homeButton, scrPtr->homeIcon);
278 WMSetButtonAltImage(fPtr->homeButton, scrPtr->altHomeIcon);
279 WMSetButtonAction(fPtr->homeButton, goHome, fPtr);
281 fPtr->disketteButton = WMCreateCommandButton(fPtr->win);
282 WMMoveWidget(fPtr->disketteButton, 97, 325);
283 WMResizeWidget(fPtr->disketteButton, 28, 28);
284 WMSetButtonImagePosition(fPtr->disketteButton, WIPImageOnly);
285 WMSetButtonImage(fPtr->disketteButton, scrPtr->disketteIcon);
286 WMSetButtonAltImage(fPtr->disketteButton, scrPtr->altDisketteIcon);
287 WMSetButtonAction(fPtr->disketteButton, goFloppy, fPtr);
289 fPtr->unmountButton = WMCreateCommandButton(fPtr->win);
290 WMMoveWidget(fPtr->unmountButton, 127, 325);
291 WMResizeWidget(fPtr->unmountButton, 28, 28);
292 WMSetButtonImagePosition(fPtr->unmountButton, WIPImageOnly);
293 WMSetButtonImage(fPtr->unmountButton, scrPtr->unmountIcon);
294 WMSetButtonAltImage(fPtr->unmountButton, scrPtr->altUnmountIcon);
295 WMSetButtonAction(fPtr->unmountButton, goUnmount, fPtr);
296 WMSetButtonEnabled(fPtr->unmountButton, False);
299 WMRealizeWidget(fPtr->win);
300 WMMapSubwidgets(fPtr->win);
302 WMSetFocusToWidget(fPtr->fileField);
303 WMSetTextFieldCursorPosition(fPtr->fileField, 0);
305 WMLoadBrowserColumnZero(fPtr->browser);
307 WMSetWindowInitialPosition(fPtr->win,
308 (scrPtr->rootView->size.width - WMWidgetWidth(fPtr->win))/2,
309 (scrPtr->rootView->size.height - WMWidgetHeight(fPtr->win))/2);
311 fPtr->flags.canChooseFiles = 1;
312 fPtr->flags.canChooseDirectories = 1;
313 fPtr->flags.autoCompletion = 1;
315 return fPtr;
319 WMOpenPanel*
320 WMGetOpenPanel(WMScreen *scrPtr)
322 WMFilePanel *panel;
324 if (scrPtr->sharedOpenPanel)
325 return scrPtr->sharedOpenPanel;
327 panel = makeFilePanel(scrPtr, "openFilePanel", "Open");
328 panel->flags.fileMustExist = 1;
329 panel->flags.panelType = WP_OPEN;
331 scrPtr->sharedOpenPanel = panel;
333 return panel;
337 WMSavePanel*
338 WMGetSavePanel(WMScreen *scrPtr)
340 WMFilePanel *panel;
342 if (scrPtr->sharedSavePanel)
343 return scrPtr->sharedSavePanel;
345 panel = makeFilePanel(scrPtr, "saveFilePanel", "Save");
346 panel->flags.fileMustExist = 0;
347 panel->flags.panelType = WP_SAVE;
349 scrPtr->sharedSavePanel = panel;
351 return panel;
355 void
356 WMFreeFilePanel(WMFilePanel *panel)
358 if (panel == WMWidgetScreen(panel->win)->sharedSavePanel) {
359 WMWidgetScreen(panel->win)->sharedSavePanel = NULL;
361 if (panel == WMWidgetScreen(panel->win)->sharedOpenPanel) {
362 WMWidgetScreen(panel->win)->sharedOpenPanel = NULL;
364 WMRemoveNotificationObserver(panel);
365 WMUnmapWidget(panel->win);
366 WMDestroyWidget(panel->win);
367 wfree(panel);
372 WMRunModalFilePanelForDirectory(WMFilePanel *panel, WMWindow *owner,
373 char *path, char *name, char **fileTypes)
375 WMScreen *scr = WMWidgetScreen(panel->win);
376 XEvent event;
378 if (name && !owner) {
379 WMSetWindowTitle(panel->win, name);
382 WMChangePanelOwner(panel->win, owner);
384 WMSetFilePanelDirectory(panel, path);
386 panel->flags.done = 0;
387 switch(panel->flags.panelType) {
388 case WP_OPEN:
389 if (fileTypes)
390 panel->flags.filtered = 1;
391 panel->fileTypes = fileTypes;
392 if (name == NULL)
393 name = "Open";
394 break;
395 case WP_SAVE:
396 panel->fileTypes = NULL;
397 panel->flags.filtered = 0;
398 if (name == NULL)
399 name = "Save";
400 break;
401 default:
402 break;
405 WMSetLabelText(panel->titleLabel, name);
407 scr->modalView = W_VIEW(panel->win);
408 WMMapWidget(panel->win);
410 scr->modal = 1;
411 while (!panel->flags.done) {
412 WMNextEvent(scr->display, &event);
413 WMHandleEvent(&event);
415 scr->modal = 0;
417 /* Must withdraw window because the next time we map
418 * it, it might have a different transient owner.
420 WMCloseWindow(panel->win);
422 return (panel->flags.canceled ? False : True);
428 void
429 WMSetFilePanelDirectory(WMFilePanel *panel, char *path)
431 WMList *list;
432 WMListItem *item;
433 int col;
434 char *rest;
436 rest = WMSetBrowserPath(panel->browser, path);
437 if (strcmp(path, "/")==0)
438 rest = NULL;
440 col = WMGetBrowserSelectedColumn(panel->browser);
441 list = WMGetBrowserListInColumn(panel->browser, col);
442 if (list && (item = WMGetListSelectedItem(list))) {
443 if (item->isBranch) {
444 WMSetTextFieldText(panel->fileField, rest);
445 } else {
446 WMSetTextFieldText(panel->fileField, item->text);
448 } else {
449 WMSetTextFieldText(panel->fileField, rest);
454 void
455 WMSetFilePanelCanChooseDirectories(WMFilePanel *panel, Bool flag)
457 panel->flags.canChooseDirectories = flag;
460 void
461 WMSetFilePanelCanChooseFiles(WMFilePanel *panel, Bool flag)
463 panel->flags.canChooseFiles = flag;
467 void
468 WMSetFilePanelAutoCompletion(WMFilePanel *panel, Bool flag)
470 panel->flags.autoCompletion = flag;
474 char*
475 WMGetFilePanelFileName(WMFilePanel *panel)
477 return getCurrentFileName(panel);
481 void
482 WMSetFilePanelAccessoryView(WMFilePanel *panel, WMView *view)
484 WMView *v;
486 panel->accessoryView = view;
488 v = WMWidgetView(panel->win);
490 W_ReparentView(view, v, 0, 0);
492 W_MoveView(view, (v->size.width - v->size.width)/2, 300);
496 WMView*
497 WMGetFilePanelAccessoryView(WMFilePanel *panel)
499 return panel->accessoryView;
503 static char*
504 get_name_from_path(char *path)
506 int size;
508 assert(path!=NULL);
510 size = strlen(path);
512 /* remove trailing / */
513 while (size > 0 && path[size-1]=='/')
514 size--;
515 /* directory was root */
516 if (size == 0)
517 return wstrdup("/");
519 while (size > 0 && path[size-1] != '/')
520 size--;
522 return wstrdup(&(path[size]));
526 static int
527 filterFileName(WMFilePanel *panel, char *file, Bool isDirectory)
529 return True;
533 #define CAST(item) (*((WMListItem**)item))
534 static int
535 comparer(const void *a, const void *b)
537 if (CAST(a)->isBranch == CAST(b)->isBranch)
538 return (strcmp(CAST(a)->text, CAST(b)->text));
539 if (CAST(a)->isBranch)
540 return (-1);
541 return (1);
543 #undef CAST
546 static void
547 listDirectoryOnColumn(WMFilePanel *panel, int column, char *path)
549 WMBrowser *bPtr = panel->browser;
550 struct dirent *dentry;
551 DIR *dir;
552 struct stat stat_buf;
553 char pbuf[PATH_MAX+16];
555 assert(column >= 0);
556 assert(path != NULL);
558 /* put directory name in the title */
559 WMSetBrowserColumnTitle(bPtr, column, get_name_from_path(path));
561 dir = opendir(path);
563 if (!dir) {
564 #ifdef VERBOSE
565 printf("WINGs: could not open directory %s\n", path);
566 #endif
567 return;
570 /* list contents in the column */
571 while ((dentry = readdir(dir))) {
572 if (strcmp(dentry->d_name, ".")==0 ||
573 strcmp(dentry->d_name, "..")==0)
574 continue;
576 strcpy(pbuf, path);
577 if (strcmp(path, "/")!=0)
578 strcat(pbuf, "/");
579 strcat(pbuf, dentry->d_name);
581 if (stat(pbuf, &stat_buf)!=0) {
582 #ifdef VERBOSE
583 printf("WINGs: could not stat %s\n", pbuf);
584 #endif
585 continue;
586 } else {
587 int isDirectory;
589 isDirectory = S_ISDIR(stat_buf.st_mode);
591 if (filterFileName(panel, dentry->d_name, isDirectory))
592 WMInsertBrowserItem(bPtr, column, -1, dentry->d_name, isDirectory);
595 WMSortBrowserColumnWithComparer(bPtr, column, comparer);
597 closedir(dir);
601 static void
602 fillColumn(WMBrowserDelegate *self, WMBrowser *bPtr, int column, WMList *list)
604 char *path;
605 WMFilePanel *panel;
607 if (column > 0) {
608 path = WMGetBrowserPathToColumn(bPtr, column-1);
609 } else {
610 path = wstrdup("/");
613 panel = WMGetHangedData(bPtr);
614 listDirectoryOnColumn(panel, column, path);
615 wfree(path);
619 static void
620 browserDClick(WMBrowser *bPtr, WMFilePanel *panel)
622 WMPerformButtonClick(panel->okButton);
625 static void
626 browserClick(WMBrowser *bPtr, WMFilePanel *panel)
628 int col = WMGetBrowserSelectedColumn(bPtr);
629 WMListItem *item = WMGetBrowserSelectedItemInColumn(bPtr, col);
631 if (!item || item->isBranch)
632 WMSetTextFieldText(panel->fileField, NULL);
633 else {
634 WMSetTextFieldText(panel->fileField, item->text);
639 static void
640 showError(WMScreen *scr, WMWindow *owner, char *s, char *file)
642 char *errStr;
644 if (file) {
645 errStr = wmalloc(strlen(file)+strlen(s));
646 sprintf(errStr, s, file);
647 } else {
648 errStr = wstrdup(s);
650 WMRunAlertPanel(scr, owner, "Error", errStr, "OK", NULL, NULL);
651 wfree(errStr);
655 static void
656 createDir(WMButton *bPre, WMFilePanel *panel)
658 char *directory_name;
659 char *directory;
660 char *file;
661 char *s;
662 WMScreen *scr = WMWidgetScreen(panel->win);
663 WMInputPanel *_panel;
665 _panel = WMCreateInputPanel(scr, panel->win,
666 "Create Directory", "Enter directory name", "", "OK", "Cancel");
667 scr->modalView = W_VIEW(_panel->win);
668 WMMapWidget(_panel->win);
669 scr->modal = 1;
670 while (!_panel->done || WMScreenPending(scr)) {
671 XEvent event;
672 WMNextEvent(scr->display, &event);
673 WMHandleEvent(&event);
675 scr->modal = 0;
677 if (_panel->result == WAPRDefault)
678 directory_name = WMGetTextFieldText(_panel->text);
679 else {
680 WMDestroyInputPanel(_panel);
681 return;
684 WMDestroyInputPanel(_panel);
686 directory = getCurrentFileName(panel);
688 char *s = strrchr(directory,'/');
689 if (s) s[1] = 0;
692 if (directory_name[0] == '/') {
693 directory[0] = 0;
694 } else {
695 while ((s = strstr(directory,"//"))) {
696 int i;
697 for (i = 2;s[i] == '/';i++);
698 strcpy(s, &s[i-1]);
700 if ((s = strrchr(directory, '/')) && !s[1]) s[0] = 0;
702 while ((s = strstr(directory_name,"//"))) {
703 int i;
704 for (i = 2;s[i] == '/';i++);
705 strcpy(s, &s[i-1]);
707 if ((s = strrchr(directory_name, '/')) && !s[1]) s[0] = 0;
709 file = wmalloc(strlen(directory_name)+strlen(directory)+1);
710 sprintf(file, "%s/%s", directory, directory_name);
711 while ((s = strstr(file,"//"))) {
712 int i;
713 for (i = 2;s[i] == '/';i++);
714 strcpy(s, &s[i-1]);
717 if (mkdir(file,0xfff) != 0) {
718 switch (errno) {
719 case EACCES:
720 showError(scr, panel->win, "Permission denied.", NULL);
721 break;
722 case EEXIST:
723 showError(scr, panel->win, "'%s' already existes.", file);
724 break;
725 case ENOENT:
726 showError(scr, panel->win, "Path does not exist.", NULL);
729 else WMSetFilePanelDirectory(panel, file);
731 wfree(directory_name);
732 wfree(directory);
733 wfree(file);
737 static void
738 deleteFile(WMButton *bPre, WMFilePanel *panel)
740 char *file;
741 char *buffer, *s;
742 struct stat filestat;
743 WMScreen *scr = WMWidgetScreen(panel->win);
745 file = getCurrentFileName(panel);
747 while ((s = strstr(file,"//"))) {
748 int i;
749 for (i = 2;s[i] == '/';i++);
750 strcpy(s, &s[i-1]);
752 if (strlen(file) > 1 && (s = strrchr(file, '/')) && !s[1]) s[0] = 0;
754 if (stat(file,&filestat)) {
755 switch (errno) {
756 case ENOENT:
757 showError(scr, panel->win, "'%s' does not exist.", file);
758 break;
759 case EACCES:
760 showError(scr, panel->win, "Permission denied.", NULL);
761 break;
762 case ENOMEM:
763 showError(scr, panel->win,
764 "Insufficient memory available.", NULL);
765 break;
766 case EROFS:
767 showError(scr, panel->win,
768 "'%s' is on a read-only filesystem.", file);
769 break;
770 default:
771 showError(scr, panel->win, "Can not delete '%s'.", file);
773 wfree(file);
774 return;
775 } else if (S_ISDIR(filestat.st_mode)) {
776 buffer = wmalloc(strlen(file)+20);
777 sprintf(buffer,"Delete directory %s ?",file);
778 } else {
779 buffer = wmalloc(strlen(file)+15);
780 sprintf(buffer,"Delete file %s ?",file);
783 if (!WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
784 "Warning", buffer, "OK", "Cancel", NULL)) {
785 if (S_ISDIR(filestat.st_mode)) {
786 if (rmdir(file) != 0) {
787 switch (errno) {
788 case EACCES:
789 showError(scr, panel->win, "Permission denied.", NULL);
790 break;
791 case ENOENT:
792 showError(scr, panel->win, "Directory '%s' does not exist.", file);
793 break;
794 case ENOTEMPTY:
795 showError(scr, panel->win, "Directory '%s' is not empty.", file);
796 break;
797 case EBUSY:
798 showError(scr, panel->win, "Directory '%s' is busy.", file);
799 break;
800 default:
801 showError(scr, panel->win, "Can not delete '%s'.", file);
803 } else {
804 char *s = strrchr(file,'/');
805 if (s) s[0] = 0;
806 WMSetFilePanelDirectory(panel, file);
808 } else if (remove(file) != 0) {
809 switch (errno) {
810 case EISDIR:
811 showError(scr, panel->win, "'%s' is a directory.", file);
812 break;
813 case ENOENT:
814 showError(scr, panel->win, "'%s' does not exist.", file);
815 break;
816 case EACCES:
817 showError(scr, panel->win, "Permission denied.", NULL);
818 break;
819 case ENOMEM:
820 showError(scr, panel->win,
821 "Insufficient memory available.", NULL);
822 break;
823 case EROFS:
824 showError(scr, panel->win,
825 "'%s' is on a read-only filesystem.", file);
826 break;
827 default:
828 showError(scr, panel->win, "Can not delete '%s'.", file);
830 } else {
831 char *s = strrchr(file,'/');
832 if (s) s[1] = 0;
833 WMSetFilePanelDirectory(panel, file);
836 wfree(buffer);
837 wfree(file);
840 static void
841 goUnmount(WMButton *bPtr, WMFilePanel *panel)
846 static void
847 goFloppy(WMButton *bPtr, WMFilePanel *panel)
849 char *file;
850 struct stat filestat;
851 WMScreen *scr = WMWidgetScreen(panel->win);
853 file = FLOPPY_PATH;
854 if (stat(FLOPPY_PATH,&filestat)) {
855 showError(scr, panel->win, "An error occured browsing '%s'.", file);
856 return;
857 } else if (!S_ISDIR(filestat.st_mode)) {
858 showError(scr, panel->win, "'%s' is not a directory.", file);
859 return;
862 WMSetFilePanelDirectory(panel, FLOPPY_PATH);
866 static void
867 goHome(WMButton *bPtr, WMFilePanel *panel)
869 char *home;
871 /* home is statically allocated. Don't free it! */
872 home = wgethomedir();
873 if (!home)
874 return;
876 WMSetFilePanelDirectory(panel, home);
880 static void
881 handleEvents(XEvent *event, void *data)
883 W_FilePanel *pPtr = (W_FilePanel*)data;
884 W_View *view = WMWidgetView(pPtr->win);
886 if (event->type == ConfigureNotify) {
887 if (event->xconfigure.width != view->size.width
888 || event->xconfigure.height != view->size.height) {
889 unsigned int newWidth = event->xconfigure.width;
890 unsigned int newHeight = event->xconfigure.height;
891 int newColumnCount;
893 W_ResizeView(view, newWidth, newHeight);
894 WMResizeWidget(pPtr->line, newWidth, 2);
895 WMResizeWidget(pPtr->browser, newWidth-14,
896 newHeight-(PHEIGHT-200));
897 WMResizeWidget(pPtr->fileField, newWidth-60-10, 24);
898 WMMoveWidget(pPtr->nameLabel, 7, newHeight-(PHEIGHT-282));
899 WMMoveWidget(pPtr->fileField, 60, newHeight-(PHEIGHT-278));
900 WMMoveWidget(pPtr->okButton, newWidth-(PWIDTH-245),
901 newHeight-(PHEIGHT-325));
902 WMMoveWidget(pPtr->cancelButton, newWidth-(PWIDTH-165),
903 newHeight-(PHEIGHT-325));
905 WMMoveWidget(pPtr->trashcanButton, 7, newHeight-(PHEIGHT-325));
906 WMMoveWidget(pPtr->createDirButton, 37, newHeight-(PHEIGHT-325));
907 WMMoveWidget(pPtr->homeButton, 67, newHeight-(PHEIGHT-325));
908 WMMoveWidget(pPtr->disketteButton, 97, newHeight-(PHEIGHT-325));
909 WMMoveWidget(pPtr->unmountButton, 127, newHeight-(PHEIGHT-325));
911 newColumnCount = (newWidth - 14) / 140;
912 WMSetBrowserMaxVisibleColumns(pPtr->browser, newColumnCount);
918 static char*
919 getCurrentFileName(WMFilePanel *panel)
921 char *path;
922 char *file;
923 char *tmp;
924 int len;
926 path = WMGetBrowserPath(panel->browser);
928 len = strlen(path);
929 if (path[len-1]=='/') {
930 file = WMGetTextFieldText(panel->fileField);
931 tmp = wmalloc(strlen(path)+strlen(file)+8);
932 if (file[0]!='/') {
933 strcpy(tmp, path);
934 strcat(tmp, file);
935 } else
936 strcpy(tmp, file);
938 wfree(file);
939 wfree(path);
940 return tmp;
941 } else {
942 return path;
948 static Bool
949 validOpenFile(WMFilePanel *panel)
951 WMListItem *item;
952 int col, haveFile = 0;
953 char *file = WMGetTextFieldText(panel->fileField);
955 if (file[0] != '\0')
956 haveFile = 1;
957 wfree(file);
959 col = WMGetBrowserSelectedColumn(panel->browser);
960 item = WMGetBrowserSelectedItemInColumn(panel->browser, col);
961 if (item) {
962 if (item->isBranch && !panel->flags.canChooseDirectories && !haveFile)
963 return False;
964 else if (!item->isBranch && !panel->flags.canChooseFiles)
965 return False;
966 else
967 return True;
968 } else {
969 /* we compute for / here */
970 if (!panel->flags.canChooseDirectories && !haveFile)
971 return False;
972 else
973 return True;
975 return True;
980 static void
981 buttonClick(WMButton *bPtr, WMFilePanel *panel)
983 WMRange range;
985 if (bPtr == panel->okButton) {
986 if (!validOpenFile(panel))
987 return;
988 if (panel->flags.fileMustExist) {
989 char *file;
991 file = getCurrentFileName(panel);
992 if (access(file, F_OK)!=0) {
993 WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
994 "Error", "File does not exist.",
995 "Ok", NULL, NULL);
996 wfree(file);
997 return;
999 wfree(file);
1001 panel->flags.canceled = 0;
1002 } else
1003 panel->flags.canceled = 1;
1005 range.count = range.position = 0;
1006 WMSelectTextFieldRange(panel->fileField, range);
1007 panel->flags.done = 1;