For libwraster:
[wmaker-crm.git] / WINGs / wfilepanel.c
blob1bde060a2b9c1453c42da85d38df86402e43b505
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
16 typedef struct W_FilePanel {
17 WMWindow *win;
19 WMLabel *iconLabel;
20 WMLabel *titleLabel;
22 WMFrame *line;
24 WMLabel *nameLabel;
25 WMBrowser *browser;
27 WMButton *okButton;
28 WMButton *cancelButton;
30 WMButton *homeButton;
31 WMButton *trashcanButton;
32 WMButton *createDirButton;
33 WMButton *disketteButton;
34 WMButton *unmountButton;
36 WMView *accessoryView;
38 WMTextField *fileField;
40 char **fileTypes;
42 struct {
43 unsigned int canExit:1;
44 unsigned int canceled:1; /* clicked on cancel */
45 unsigned int filtered:1;
46 unsigned int canChooseFiles:1;
47 unsigned int canChooseDirectories:1;
48 unsigned int autoCompletion:1;
49 unsigned int showAllFiles:1;
50 unsigned int canFreeFileTypes:1;
51 unsigned int fileMustExist:1;
52 unsigned int panelType:1;
53 } flags;
54 } W_FilePanel;
57 /* Type of panel */
58 #define WP_OPEN 0
59 #define WP_SAVE 1
61 #define PWIDTH 330
62 #define PHEIGHT 360
64 static void listDirectoryOnColumn(WMFilePanel *panel, int column, char *path);
65 static void browserClick();
66 static void browserDClick();
68 static void fillColumn(WMBrowserDelegate *self, WMBrowser *bPtr, int column,
69 WMList *list);
71 static void deleteFile();
73 static void createDir();
75 static void goHome();
77 static void goFloppy();
79 static void goUnmount();
81 static void buttonClick();
83 static char *getCurrentFileName(WMFilePanel *panel);
85 static void handleEvents(XEvent *event, void *data);
89 static WMBrowserDelegate browserDelegate = {
90 NULL, /* data */
91 fillColumn, /* createRowsForColumn */
92 NULL, /* titleOfColumn */
93 NULL, /* didScroll */
94 NULL /* willScroll */
98 static int
99 closestListItem(WMList *list, char *text, Bool exact)
101 WMListItem *item;
102 WMArray *items = WMGetListItems(list);
103 int i, len = strlen(text);
105 if (len==0)
106 return -1;
108 for(i=0; i<WMGetArrayItemCount(items); i++) {
109 item = WMGetFromArray(items, i);
110 if (strlen(item->text) >= len &&
111 ((exact && strcmp(item->text, text)==0) ||
112 (!exact && strncmp(item->text, text, len)==0))) {
113 return i;
117 return -1;
121 static void
122 textChangedObserver(void *observerData, WMNotification *notification)
124 W_FilePanel *panel = (W_FilePanel*)observerData;
125 char *text;
126 WMList *list;
127 int col = WMGetBrowserNumberOfColumns(panel->browser) - 1;
128 int i, textEvent;
130 if (!(list = WMGetBrowserListInColumn(panel->browser, col)))
131 return;
133 text = WMGetTextFieldText(panel->fileField);
134 textEvent = (int)WMGetNotificationClientData(notification);
136 if (panel->flags.autoCompletion && textEvent!=WMDeleteTextEvent)
137 i = closestListItem(list, text, False);
138 else
139 i = closestListItem(list, text, True);
141 WMSelectListItem(list, i);
142 if (i>=0 && panel->flags.autoCompletion) {
143 WMListItem *item = WMGetListItem(list, i);
144 int textLen = strlen(text), itemTextLen = strlen(item->text);
145 int visibleItems = WMWidgetHeight(list)/WMGetListItemHeight(list);
147 WMSetListPosition(list, i - visibleItems/2);
149 if (textEvent!=WMDeleteTextEvent) {
150 WMRange range;
152 WMInsertTextFieldText(panel->fileField, &item->text[textLen],
153 textLen);
154 range.position = textLen;
155 range.count = itemTextLen - textLen;
156 WMSelectTextFieldRange(panel->fileField, range);
157 /*WMSetTextFieldCursorPosition(panel->fileField, itemTextLen);*/
161 wfree(text);
165 static void
166 textEditedObserver(void *observerData, WMNotification *notification)
168 W_FilePanel *panel = (W_FilePanel*)observerData;
170 if ((int)WMGetNotificationClientData(notification)==WMReturnTextMovement) {
171 WMPerformButtonClick(panel->okButton);
177 static WMFilePanel*
178 makeFilePanel(WMScreen *scrPtr, char *name, char *title)
180 WMFilePanel *fPtr;
181 WMFont *largeFont;
182 WMPixmap *icon;
184 fPtr = wmalloc(sizeof(WMFilePanel));
185 memset(fPtr, 0, sizeof(WMFilePanel));
187 fPtr->win = WMCreateWindowWithStyle(scrPtr, name, WMTitledWindowMask
188 |WMResizableWindowMask);
189 WMResizeWidget(fPtr->win, PWIDTH, PHEIGHT);
190 WMSetWindowTitle(fPtr->win, "");
192 WMCreateEventHandler(WMWidgetView(fPtr->win), StructureNotifyMask,
193 handleEvents, fPtr);
194 WMSetWindowMinSize(fPtr->win, PWIDTH, PHEIGHT);
197 fPtr->iconLabel = WMCreateLabel(fPtr->win);
198 WMResizeWidget(fPtr->iconLabel, 64, 64);
199 WMMoveWidget(fPtr->iconLabel, 0, 0);
200 WMSetLabelImagePosition(fPtr->iconLabel, WIPImageOnly);
201 icon = WMGetApplicationIconBlendedPixmap(scrPtr, (RColor*)NULL);
202 if (icon) {
203 WMSetLabelImage(fPtr->iconLabel, icon);
204 WMReleasePixmap(icon);
205 } else {
206 WMSetLabelImage(fPtr->iconLabel, scrPtr->applicationIconPixmap);
209 fPtr->titleLabel = WMCreateLabel(fPtr->win);
210 WMResizeWidget(fPtr->titleLabel, PWIDTH-64, 64);
211 WMMoveWidget(fPtr->titleLabel, 64, 0);
212 largeFont = WMBoldSystemFontOfSize(scrPtr, 24);
213 WMSetLabelFont(fPtr->titleLabel, largeFont);
214 WMReleaseFont(largeFont);
215 WMSetLabelText(fPtr->titleLabel, title);
217 fPtr->line = WMCreateFrame(fPtr->win);
218 WMMoveWidget(fPtr->line, 0, 64);
219 WMResizeWidget(fPtr->line, PWIDTH, 2);
220 WMSetFrameRelief(fPtr->line, WRGroove);
222 fPtr->browser = WMCreateBrowser(fPtr->win);
223 WMSetBrowserAllowEmptySelection(fPtr->browser, True);
224 WMSetBrowserDelegate(fPtr->browser, &browserDelegate);
225 WMSetBrowserAction(fPtr->browser, browserClick, fPtr);
226 WMSetBrowserDoubleAction(fPtr->browser, browserDClick, fPtr);
227 WMMoveWidget(fPtr->browser, 7, 72);
228 WMResizeWidget(fPtr->browser, PWIDTH-14,200);
229 WMHangData(fPtr->browser, fPtr);
231 fPtr->nameLabel = WMCreateLabel(fPtr->win);
232 WMMoveWidget(fPtr->nameLabel, 7, 282);
233 WMResizeWidget(fPtr->nameLabel, 55, 14);
234 WMSetLabelText(fPtr->nameLabel, "Name:");
236 fPtr->fileField = WMCreateTextField(fPtr->win);
237 WMMoveWidget(fPtr->fileField, 60, 278);
238 WMResizeWidget(fPtr->fileField, PWIDTH-60-10, 24);
239 WMAddNotificationObserver(textEditedObserver, fPtr,
240 WMTextDidEndEditingNotification,
241 fPtr->fileField);
242 WMAddNotificationObserver(textChangedObserver, fPtr,
243 WMTextDidChangeNotification,
244 fPtr->fileField);
246 fPtr->okButton = WMCreateCommandButton(fPtr->win);
247 WMMoveWidget(fPtr->okButton, 245, 325);
248 WMResizeWidget(fPtr->okButton, 75, 28);
249 WMSetButtonText(fPtr->okButton, "OK");
250 WMSetButtonImage(fPtr->okButton, scrPtr->buttonArrow);
251 WMSetButtonAltImage(fPtr->okButton, scrPtr->pushedButtonArrow);
252 WMSetButtonImagePosition(fPtr->okButton, WIPRight);
253 WMSetButtonAction(fPtr->okButton, buttonClick, fPtr);
255 fPtr->cancelButton = WMCreateCommandButton(fPtr->win);
256 WMMoveWidget(fPtr->cancelButton, 165, 325);
257 WMResizeWidget(fPtr->cancelButton, 75, 28);
258 WMSetButtonText(fPtr->cancelButton, "Cancel");
259 WMSetButtonAction(fPtr->cancelButton, buttonClick, fPtr);
261 fPtr->trashcanButton = WMCreateCommandButton(fPtr->win);
262 WMMoveWidget(fPtr->trashcanButton, 7, 325);
263 WMResizeWidget(fPtr->trashcanButton, 28, 28);
264 WMSetButtonImagePosition(fPtr->trashcanButton, WIPImageOnly);
265 WMSetButtonImage(fPtr->trashcanButton, scrPtr->trashcanIcon);
266 WMSetButtonAltImage(fPtr->trashcanButton, scrPtr->altTrashcanIcon);
267 WMSetButtonAction(fPtr->trashcanButton, deleteFile, fPtr);
269 fPtr->createDirButton = WMCreateCommandButton(fPtr->win);
270 WMMoveWidget(fPtr->createDirButton, 37, 325);
271 WMResizeWidget(fPtr->createDirButton, 28, 28);
272 WMSetButtonImagePosition(fPtr->createDirButton, WIPImageOnly);
273 WMSetButtonImage(fPtr->createDirButton, scrPtr->createDirIcon);
274 WMSetButtonAltImage(fPtr->createDirButton, scrPtr->altCreateDirIcon);
275 WMSetButtonAction(fPtr->createDirButton, createDir, fPtr);
277 fPtr->homeButton = WMCreateCommandButton(fPtr->win);
278 WMMoveWidget(fPtr->homeButton, 67, 325);
279 WMResizeWidget(fPtr->homeButton, 28, 28);
280 WMSetButtonImagePosition(fPtr->homeButton, WIPImageOnly);
281 WMSetButtonImage(fPtr->homeButton, scrPtr->homeIcon);
282 WMSetButtonAltImage(fPtr->homeButton, scrPtr->altHomeIcon);
283 WMSetButtonAction(fPtr->homeButton, goHome, fPtr);
285 fPtr->disketteButton = WMCreateCommandButton(fPtr->win);
286 WMMoveWidget(fPtr->disketteButton, 97, 325);
287 WMResizeWidget(fPtr->disketteButton, 28, 28);
288 WMSetButtonImagePosition(fPtr->disketteButton, WIPImageOnly);
289 WMSetButtonImage(fPtr->disketteButton, scrPtr->disketteIcon);
290 WMSetButtonAltImage(fPtr->disketteButton, scrPtr->altDisketteIcon);
291 WMSetButtonAction(fPtr->disketteButton, goFloppy, fPtr);
293 fPtr->unmountButton = WMCreateCommandButton(fPtr->win);
294 WMMoveWidget(fPtr->unmountButton, 127, 325);
295 WMResizeWidget(fPtr->unmountButton, 28, 28);
296 WMSetButtonImagePosition(fPtr->unmountButton, WIPImageOnly);
297 WMSetButtonImage(fPtr->unmountButton, scrPtr->unmountIcon);
298 WMSetButtonAltImage(fPtr->unmountButton, scrPtr->altUnmountIcon);
299 WMSetButtonAction(fPtr->unmountButton, goUnmount, fPtr);
300 WMSetButtonEnabled(fPtr->unmountButton, False);
303 WMRealizeWidget(fPtr->win);
304 WMMapSubwidgets(fPtr->win);
306 WMSetFocusToWidget(fPtr->fileField);
307 WMSetTextFieldCursorPosition(fPtr->fileField, 0);
309 WMLoadBrowserColumnZero(fPtr->browser);
311 WMSetWindowInitialPosition(fPtr->win,
312 (scrPtr->rootView->size.width - WMWidgetWidth(fPtr->win))/2,
313 (scrPtr->rootView->size.height - WMWidgetHeight(fPtr->win))/2);
315 fPtr->flags.canChooseFiles = 1;
316 fPtr->flags.canChooseDirectories = 1;
317 fPtr->flags.autoCompletion = 1;
319 return fPtr;
323 WMOpenPanel*
324 WMGetOpenPanel(WMScreen *scrPtr)
326 WMFilePanel *panel;
328 if (scrPtr->sharedOpenPanel)
329 return scrPtr->sharedOpenPanel;
331 panel = makeFilePanel(scrPtr, "openFilePanel", "Open");
332 panel->flags.fileMustExist = 1;
333 panel->flags.panelType = WP_OPEN;
335 scrPtr->sharedOpenPanel = panel;
337 return panel;
341 WMSavePanel*
342 WMGetSavePanel(WMScreen *scrPtr)
344 WMFilePanel *panel;
346 if (scrPtr->sharedSavePanel)
347 return scrPtr->sharedSavePanel;
349 panel = makeFilePanel(scrPtr, "saveFilePanel", "Save");
350 panel->flags.fileMustExist = 0;
351 panel->flags.panelType = WP_SAVE;
353 scrPtr->sharedSavePanel = panel;
355 return panel;
359 void
360 WMFreeFilePanel(WMFilePanel *panel)
362 if (panel == WMWidgetScreen(panel->win)->sharedSavePanel) {
363 WMWidgetScreen(panel->win)->sharedSavePanel = NULL;
365 if (panel == WMWidgetScreen(panel->win)->sharedOpenPanel) {
366 WMWidgetScreen(panel->win)->sharedOpenPanel = NULL;
368 WMRemoveNotificationObserver(panel);
369 WMUnmapWidget(panel->win);
370 WMDestroyWidget(panel->win);
371 wfree(panel);
376 WMRunModalFilePanelForDirectory(WMFilePanel *panel, WMWindow *owner,
377 char *path, char *name, char **fileTypes)
379 WMScreen *scr = WMWidgetScreen(panel->win);
381 if (name && !owner) {
382 WMSetWindowTitle(panel->win, name);
385 WMChangePanelOwner(panel->win, owner);
387 WMSetFilePanelDirectory(panel, path);
389 switch(panel->flags.panelType) {
390 case WP_OPEN:
391 if (fileTypes)
392 panel->flags.filtered = 1;
393 panel->fileTypes = fileTypes;
394 if (name == NULL)
395 name = "Open";
396 break;
397 case WP_SAVE:
398 panel->fileTypes = NULL;
399 panel->flags.filtered = 0;
400 if (name == NULL)
401 name = "Save";
402 break;
403 default:
404 break;
407 WMSetLabelText(panel->titleLabel, name);
409 WMMapWidget(panel->win);
411 WMRunModalLoop(scr, W_VIEW(panel->win));
413 /* Must withdraw window because the next time we map
414 * it, it might have a different transient owner.
416 WMCloseWindow(panel->win);
418 return (panel->flags.canceled ? False : True);
424 void
425 WMSetFilePanelDirectory(WMFilePanel *panel, char *path)
427 WMList *list;
428 WMListItem *item;
429 int col;
430 char *rest;
432 rest = WMSetBrowserPath(panel->browser, path);
433 if (strcmp(path, "/")==0)
434 rest = NULL;
436 col = WMGetBrowserSelectedColumn(panel->browser);
437 list = WMGetBrowserListInColumn(panel->browser, col);
438 if (list && (item = WMGetListSelectedItem(list))) {
439 if (item->isBranch) {
440 WMSetTextFieldText(panel->fileField, rest);
441 } else {
442 WMSetTextFieldText(panel->fileField, item->text);
444 } else {
445 WMSetTextFieldText(panel->fileField, rest);
450 void
451 WMSetFilePanelCanChooseDirectories(WMFilePanel *panel, Bool flag)
453 panel->flags.canChooseDirectories = flag;
456 void
457 WMSetFilePanelCanChooseFiles(WMFilePanel *panel, Bool flag)
459 panel->flags.canChooseFiles = flag;
463 void
464 WMSetFilePanelAutoCompletion(WMFilePanel *panel, Bool flag)
466 panel->flags.autoCompletion = flag;
470 char*
471 WMGetFilePanelFileName(WMFilePanel *panel)
473 return getCurrentFileName(panel);
477 void
478 WMSetFilePanelAccessoryView(WMFilePanel *panel, WMView *view)
480 WMView *v;
482 panel->accessoryView = view;
484 v = WMWidgetView(panel->win);
486 W_ReparentView(view, v, 0, 0);
488 W_MoveView(view, (v->size.width - v->size.width)/2, 300);
492 WMView*
493 WMGetFilePanelAccessoryView(WMFilePanel *panel)
495 return panel->accessoryView;
499 static char*
500 get_name_from_path(char *path)
502 int size;
504 assert(path!=NULL);
506 size = strlen(path);
508 /* remove trailing / */
509 while (size > 0 && path[size-1]=='/')
510 size--;
511 /* directory was root */
512 if (size == 0)
513 return wstrdup("/");
515 while (size > 0 && path[size-1] != '/')
516 size--;
518 return wstrdup(&(path[size]));
522 static int
523 filterFileName(WMFilePanel *panel, char *file, Bool isDirectory)
525 return True;
529 #define CAST(item) (*((WMListItem**)item))
530 static int
531 comparer(const void *a, const void *b)
533 if (CAST(a)->isBranch == CAST(b)->isBranch)
534 return (strcmp(CAST(a)->text, CAST(b)->text));
535 if (CAST(a)->isBranch)
536 return (-1);
537 return (1);
539 #undef CAST
542 static void
543 listDirectoryOnColumn(WMFilePanel *panel, int column, char *path)
545 WMBrowser *bPtr = panel->browser;
546 struct dirent *dentry;
547 DIR *dir;
548 struct stat stat_buf;
549 char pbuf[PATH_MAX+16];
551 assert(column >= 0);
552 assert(path != NULL);
554 /* put directory name in the title */
555 WMSetBrowserColumnTitle(bPtr, column, get_name_from_path(path));
557 dir = opendir(path);
559 if (!dir) {
560 #ifdef VERBOSE
561 printf("WINGs: could not open directory %s\n", path);
562 #endif
563 return;
566 /* list contents in the column */
567 while ((dentry = readdir(dir))) {
568 if (strcmp(dentry->d_name, ".")==0 ||
569 strcmp(dentry->d_name, "..")==0)
570 continue;
572 strcpy(pbuf, path);
573 if (strcmp(path, "/")!=0)
574 strcat(pbuf, "/");
575 strcat(pbuf, dentry->d_name);
577 if (stat(pbuf, &stat_buf)!=0) {
578 #ifdef VERBOSE
579 printf("WINGs: could not stat %s\n", pbuf);
580 #endif
581 continue;
582 } else {
583 int isDirectory;
585 isDirectory = S_ISDIR(stat_buf.st_mode);
587 if (filterFileName(panel, dentry->d_name, isDirectory))
588 WMInsertBrowserItem(bPtr, column, -1, dentry->d_name, isDirectory);
591 WMSortBrowserColumnWithComparer(bPtr, column, comparer);
593 closedir(dir);
597 static void
598 fillColumn(WMBrowserDelegate *self, WMBrowser *bPtr, int column, WMList *list)
600 char *path;
601 WMFilePanel *panel;
603 if (column > 0) {
604 path = WMGetBrowserPathToColumn(bPtr, column-1);
605 } else {
606 path = wstrdup("/");
609 panel = WMGetHangedData(bPtr);
610 listDirectoryOnColumn(panel, column, path);
611 wfree(path);
615 static void
616 browserDClick(WMBrowser *bPtr, WMFilePanel *panel)
618 WMPerformButtonClick(panel->okButton);
621 static void
622 browserClick(WMBrowser *bPtr, WMFilePanel *panel)
624 int col = WMGetBrowserSelectedColumn(bPtr);
625 WMListItem *item = WMGetBrowserSelectedItemInColumn(bPtr, col);
627 if (!item || item->isBranch)
628 WMSetTextFieldText(panel->fileField, NULL);
629 else {
630 WMSetTextFieldText(panel->fileField, item->text);
635 static void
636 showError(WMScreen *scr, WMWindow *owner, char *s, char *file)
638 char *errStr;
640 if (file) {
641 errStr = wmalloc(strlen(file)+strlen(s));
642 sprintf(errStr, s, file);
643 } else {
644 errStr = wstrdup(s);
646 WMRunAlertPanel(scr, owner, "Error", errStr, "OK", NULL, NULL);
647 wfree(errStr);
651 static void
652 createDir(WMButton *bPre, WMFilePanel *panel)
654 char *dirName, *directory, *file, *s;
655 WMScreen *scr = WMWidgetScreen(panel->win);
657 dirName = WMRunInputPanel(scr, panel->win, "Create Directory",
658 "Enter directory name", "", "OK", "Cancel");
659 if (!dirName)
660 return;
662 directory = getCurrentFileName(panel);
663 s = strrchr(directory,'/');
664 if (s) s[1] = 0;
666 if (dirName[0] == '/') {
667 directory[0] = 0;
668 } else {
669 while ((s = strstr(directory,"//"))) {
670 int i;
671 for (i = 2;s[i] == '/';i++);
672 strcpy(s, &s[i-1]);
674 if ((s = strrchr(directory, '/')) && !s[1]) s[0] = 0;
676 while ((s = strstr(dirName,"//"))) {
677 int i;
678 for (i = 2;s[i] == '/';i++);
679 strcpy(s, &s[i-1]);
681 if ((s = strrchr(dirName, '/')) && !s[1]) s[0] = 0;
683 file = wmalloc(strlen(dirName)+strlen(directory)+1);
684 sprintf(file, "%s/%s", directory, dirName);
685 while ((s = strstr(file,"//"))) {
686 int i;
687 for (i = 2;s[i] == '/';i++);
688 strcpy(s, &s[i-1]);
691 if (mkdir(file,0xfff) != 0) {
692 switch (errno) {
693 case EACCES:
694 showError(scr, panel->win, "Permission denied.", NULL);
695 break;
696 case EEXIST:
697 showError(scr, panel->win, "'%s' already existes.", file);
698 break;
699 case ENOENT:
700 showError(scr, panel->win, "Path does not exist.", NULL);
703 else WMSetFilePanelDirectory(panel, file);
705 wfree(dirName);
706 wfree(directory);
707 wfree(file);
710 static void
711 deleteFile(WMButton *bPre, WMFilePanel *panel)
713 char *file;
714 char *buffer, *s;
715 struct stat filestat;
716 WMScreen *scr = WMWidgetScreen(panel->win);
718 file = getCurrentFileName(panel);
720 while ((s = strstr(file,"//"))) {
721 int i;
722 for (i = 2;s[i] == '/';i++);
723 strcpy(s, &s[i-1]);
725 if (strlen(file) > 1 && (s = strrchr(file, '/')) && !s[1]) s[0] = 0;
727 if (stat(file,&filestat)) {
728 switch (errno) {
729 case ENOENT:
730 showError(scr, panel->win, "'%s' does not exist.", file);
731 break;
732 case EACCES:
733 showError(scr, panel->win, "Permission denied.", NULL);
734 break;
735 case ENOMEM:
736 showError(scr, panel->win,
737 "Insufficient memory available.", NULL);
738 break;
739 case EROFS:
740 showError(scr, panel->win,
741 "'%s' is on a read-only filesystem.", file);
742 break;
743 default:
744 showError(scr, panel->win, "Can not delete '%s'.", file);
746 wfree(file);
747 return;
748 } else if (S_ISDIR(filestat.st_mode)) {
749 buffer = wmalloc(strlen(file)+20);
750 sprintf(buffer,"Delete directory %s ?",file);
751 } else {
752 buffer = wmalloc(strlen(file)+15);
753 sprintf(buffer,"Delete file %s ?",file);
756 if (!WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
757 "Warning", buffer, "OK", "Cancel", NULL)) {
758 if (S_ISDIR(filestat.st_mode)) {
759 if (rmdir(file) != 0) {
760 switch (errno) {
761 case EACCES:
762 showError(scr, panel->win, "Permission denied.", NULL);
763 break;
764 case ENOENT:
765 showError(scr, panel->win, "Directory '%s' does not exist.", file);
766 break;
767 case ENOTEMPTY:
768 showError(scr, panel->win, "Directory '%s' is not empty.", file);
769 break;
770 case EBUSY:
771 showError(scr, panel->win, "Directory '%s' is busy.", file);
772 break;
773 default:
774 showError(scr, panel->win, "Can not delete '%s'.", file);
776 } else {
777 char *s = strrchr(file,'/');
778 if (s) s[0] = 0;
779 WMSetFilePanelDirectory(panel, file);
781 } else if (remove(file) != 0) {
782 switch (errno) {
783 case EISDIR:
784 showError(scr, panel->win, "'%s' is a directory.", file);
785 break;
786 case ENOENT:
787 showError(scr, panel->win, "'%s' does not exist.", file);
788 break;
789 case EACCES:
790 showError(scr, panel->win, "Permission denied.", NULL);
791 break;
792 case ENOMEM:
793 showError(scr, panel->win,
794 "Insufficient memory available.", NULL);
795 break;
796 case EROFS:
797 showError(scr, panel->win,
798 "'%s' is on a read-only filesystem.", 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[1] = 0;
806 WMSetFilePanelDirectory(panel, file);
809 wfree(buffer);
810 wfree(file);
813 static void
814 goUnmount(WMButton *bPtr, WMFilePanel *panel)
819 static void
820 goFloppy(WMButton *bPtr, WMFilePanel *panel)
822 struct stat filestat;
823 WMScreen *scr = WMWidgetScreen(panel->win);
825 if (stat(WINGsConfiguration.floppyPath, &filestat)) {
826 showError(scr, panel->win, "An error occured browsing '%s'.",
827 WINGsConfiguration.floppyPath);
828 return;
829 } else if (!S_ISDIR(filestat.st_mode)) {
830 showError(scr, panel->win, "'%s' is not a directory.",
831 WINGsConfiguration.floppyPath);
832 return;
835 WMSetFilePanelDirectory(panel, WINGsConfiguration.floppyPath);
839 static void
840 goHome(WMButton *bPtr, WMFilePanel *panel)
842 char *home;
844 /* home is statically allocated. Don't free it! */
845 home = wgethomedir();
846 if (!home)
847 return;
849 WMSetFilePanelDirectory(panel, home);
853 static void
854 handleEvents(XEvent *event, void *data)
856 W_FilePanel *pPtr = (W_FilePanel*)data;
857 W_View *view = WMWidgetView(pPtr->win);
859 if (event->type == ConfigureNotify) {
860 if (event->xconfigure.width != view->size.width
861 || event->xconfigure.height != view->size.height) {
862 unsigned int newWidth = event->xconfigure.width;
863 unsigned int newHeight = event->xconfigure.height;
864 int newColumnCount;
866 W_ResizeView(view, newWidth, newHeight);
867 WMResizeWidget(pPtr->line, newWidth, 2);
868 WMResizeWidget(pPtr->browser, newWidth-14,
869 newHeight-(PHEIGHT-200));
870 WMResizeWidget(pPtr->fileField, newWidth-60-10, 24);
871 WMMoveWidget(pPtr->nameLabel, 7, newHeight-(PHEIGHT-282));
872 WMMoveWidget(pPtr->fileField, 60, newHeight-(PHEIGHT-278));
873 WMMoveWidget(pPtr->okButton, newWidth-(PWIDTH-245),
874 newHeight-(PHEIGHT-325));
875 WMMoveWidget(pPtr->cancelButton, newWidth-(PWIDTH-165),
876 newHeight-(PHEIGHT-325));
878 WMMoveWidget(pPtr->trashcanButton, 7, newHeight-(PHEIGHT-325));
879 WMMoveWidget(pPtr->createDirButton, 37, newHeight-(PHEIGHT-325));
880 WMMoveWidget(pPtr->homeButton, 67, newHeight-(PHEIGHT-325));
881 WMMoveWidget(pPtr->disketteButton, 97, newHeight-(PHEIGHT-325));
882 WMMoveWidget(pPtr->unmountButton, 127, newHeight-(PHEIGHT-325));
884 newColumnCount = (newWidth - 14) / 140;
885 WMSetBrowserMaxVisibleColumns(pPtr->browser, newColumnCount);
891 static char*
892 getCurrentFileName(WMFilePanel *panel)
894 char *path;
895 char *file;
896 char *tmp;
897 int len;
899 path = WMGetBrowserPath(panel->browser);
901 len = strlen(path);
902 if (path[len-1]=='/') {
903 file = WMGetTextFieldText(panel->fileField);
904 tmp = wmalloc(strlen(path)+strlen(file)+8);
905 if (file[0]!='/') {
906 strcpy(tmp, path);
907 strcat(tmp, file);
908 } else
909 strcpy(tmp, file);
911 wfree(file);
912 wfree(path);
913 return tmp;
914 } else {
915 return path;
921 static Bool
922 validOpenFile(WMFilePanel *panel)
924 WMListItem *item;
925 int col, haveFile = 0;
926 char *file = WMGetTextFieldText(panel->fileField);
928 if (file[0] != '\0')
929 haveFile = 1;
930 wfree(file);
932 col = WMGetBrowserSelectedColumn(panel->browser);
933 item = WMGetBrowserSelectedItemInColumn(panel->browser, col);
934 if (item) {
935 if (item->isBranch && !panel->flags.canChooseDirectories && !haveFile)
936 return False;
937 else if (!item->isBranch && !panel->flags.canChooseFiles)
938 return False;
939 else
940 return True;
941 } else {
942 /* we compute for / here */
943 if (!panel->flags.canChooseDirectories && !haveFile)
944 return False;
945 else
946 return True;
948 return True;
953 static void
954 buttonClick(WMButton *bPtr, WMFilePanel *panel)
956 WMRange range;
958 if (bPtr == panel->okButton) {
959 if (!validOpenFile(panel))
960 return;
961 if (panel->flags.fileMustExist) {
962 char *file;
964 file = getCurrentFileName(panel);
965 if (access(file, F_OK)!=0) {
966 WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
967 "Error", "File does not exist.",
968 "Ok", NULL, NULL);
969 wfree(file);
970 return;
972 wfree(file);
974 panel->flags.canceled = 0;
975 } else
976 panel->flags.canceled = 1;
978 range.count = range.position = 0;
979 WMSelectTextFieldRange(panel->fileField, range);
980 WMBreakModalLoop(WMWidgetScreen(bPtr));