- put back wmksize(), wmkrange() and wmkpoint() as functions instead of macros
[wmaker-crm.git] / WINGs / wfilepanel.c
blob03ebd71439c28c97981b83646c560bb179b26749
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;
183 fPtr = wmalloc(sizeof(WMFilePanel));
184 memset(fPtr, 0, sizeof(WMFilePanel));
186 fPtr->win = WMCreateWindowWithStyle(scrPtr, name, WMTitledWindowMask
187 |WMResizableWindowMask);
188 WMResizeWidget(fPtr->win, PWIDTH, PHEIGHT);
189 WMSetWindowTitle(fPtr->win, "");
191 WMCreateEventHandler(WMWidgetView(fPtr->win), StructureNotifyMask,
192 handleEvents, fPtr);
193 WMSetWindowMinSize(fPtr->win, PWIDTH, PHEIGHT);
196 fPtr->iconLabel = WMCreateLabel(fPtr->win);
197 WMResizeWidget(fPtr->iconLabel, 64, 64);
198 WMMoveWidget(fPtr->iconLabel, 0, 0);
199 WMSetLabelImagePosition(fPtr->iconLabel, WIPImageOnly);
200 WMSetLabelImage(fPtr->iconLabel, scrPtr->applicationIcon);
202 fPtr->titleLabel = WMCreateLabel(fPtr->win);
203 WMResizeWidget(fPtr->titleLabel, PWIDTH-64, 64);
204 WMMoveWidget(fPtr->titleLabel, 64, 0);
205 largeFont = WMBoldSystemFontOfSize(scrPtr, 24);
206 WMSetLabelFont(fPtr->titleLabel, largeFont);
207 WMReleaseFont(largeFont);
208 WMSetLabelText(fPtr->titleLabel, title);
210 fPtr->line = WMCreateFrame(fPtr->win);
211 WMMoveWidget(fPtr->line, 0, 64);
212 WMResizeWidget(fPtr->line, PWIDTH, 2);
213 WMSetFrameRelief(fPtr->line, WRGroove);
215 fPtr->browser = WMCreateBrowser(fPtr->win);
216 WMSetBrowserAllowEmptySelection(fPtr->browser, True);
217 WMSetBrowserDelegate(fPtr->browser, &browserDelegate);
218 WMSetBrowserAction(fPtr->browser, browserClick, fPtr);
219 WMSetBrowserDoubleAction(fPtr->browser, browserDClick, fPtr);
220 WMMoveWidget(fPtr->browser, 7, 72);
221 WMResizeWidget(fPtr->browser, PWIDTH-14,200);
222 WMHangData(fPtr->browser, fPtr);
224 fPtr->nameLabel = WMCreateLabel(fPtr->win);
225 WMMoveWidget(fPtr->nameLabel, 7, 282);
226 WMResizeWidget(fPtr->nameLabel, 55, 14);
227 WMSetLabelText(fPtr->nameLabel, "Name:");
229 fPtr->fileField = WMCreateTextField(fPtr->win);
230 WMMoveWidget(fPtr->fileField, 60, 278);
231 WMResizeWidget(fPtr->fileField, PWIDTH-60-10, 24);
232 WMAddNotificationObserver(textEditedObserver, fPtr,
233 WMTextDidEndEditingNotification,
234 fPtr->fileField);
235 WMAddNotificationObserver(textChangedObserver, fPtr,
236 WMTextDidChangeNotification,
237 fPtr->fileField);
239 fPtr->okButton = WMCreateCommandButton(fPtr->win);
240 WMMoveWidget(fPtr->okButton, 245, 325);
241 WMResizeWidget(fPtr->okButton, 75, 28);
242 WMSetButtonText(fPtr->okButton, "OK");
243 WMSetButtonImage(fPtr->okButton, scrPtr->buttonArrow);
244 WMSetButtonAltImage(fPtr->okButton, scrPtr->pushedButtonArrow);
245 WMSetButtonImagePosition(fPtr->okButton, WIPRight);
246 WMSetButtonAction(fPtr->okButton, buttonClick, fPtr);
248 fPtr->cancelButton = WMCreateCommandButton(fPtr->win);
249 WMMoveWidget(fPtr->cancelButton, 165, 325);
250 WMResizeWidget(fPtr->cancelButton, 75, 28);
251 WMSetButtonText(fPtr->cancelButton, "Cancel");
252 WMSetButtonAction(fPtr->cancelButton, buttonClick, fPtr);
254 fPtr->trashcanButton = WMCreateCommandButton(fPtr->win);
255 WMMoveWidget(fPtr->trashcanButton, 7, 325);
256 WMResizeWidget(fPtr->trashcanButton, 28, 28);
257 WMSetButtonImagePosition(fPtr->trashcanButton, WIPImageOnly);
258 WMSetButtonImage(fPtr->trashcanButton, scrPtr->trashcanIcon);
259 WMSetButtonAltImage(fPtr->trashcanButton, scrPtr->altTrashcanIcon);
260 WMSetButtonAction(fPtr->trashcanButton, deleteFile, fPtr);
262 fPtr->createDirButton = WMCreateCommandButton(fPtr->win);
263 WMMoveWidget(fPtr->createDirButton, 37, 325);
264 WMResizeWidget(fPtr->createDirButton, 28, 28);
265 WMSetButtonImagePosition(fPtr->createDirButton, WIPImageOnly);
266 WMSetButtonImage(fPtr->createDirButton, scrPtr->createDirIcon);
267 WMSetButtonAltImage(fPtr->createDirButton, scrPtr->altCreateDirIcon);
268 WMSetButtonAction(fPtr->createDirButton, createDir, fPtr);
270 fPtr->homeButton = WMCreateCommandButton(fPtr->win);
271 WMMoveWidget(fPtr->homeButton, 67, 325);
272 WMResizeWidget(fPtr->homeButton, 28, 28);
273 WMSetButtonImagePosition(fPtr->homeButton, WIPImageOnly);
274 WMSetButtonImage(fPtr->homeButton, scrPtr->homeIcon);
275 WMSetButtonAltImage(fPtr->homeButton, scrPtr->altHomeIcon);
276 WMSetButtonAction(fPtr->homeButton, goHome, fPtr);
278 fPtr->disketteButton = WMCreateCommandButton(fPtr->win);
279 WMMoveWidget(fPtr->disketteButton, 97, 325);
280 WMResizeWidget(fPtr->disketteButton, 28, 28);
281 WMSetButtonImagePosition(fPtr->disketteButton, WIPImageOnly);
282 WMSetButtonImage(fPtr->disketteButton, scrPtr->disketteIcon);
283 WMSetButtonAltImage(fPtr->disketteButton, scrPtr->altDisketteIcon);
284 WMSetButtonAction(fPtr->disketteButton, goFloppy, fPtr);
286 fPtr->unmountButton = WMCreateCommandButton(fPtr->win);
287 WMMoveWidget(fPtr->unmountButton, 127, 325);
288 WMResizeWidget(fPtr->unmountButton, 28, 28);
289 WMSetButtonImagePosition(fPtr->unmountButton, WIPImageOnly);
290 WMSetButtonImage(fPtr->unmountButton, scrPtr->unmountIcon);
291 WMSetButtonAltImage(fPtr->unmountButton, scrPtr->altUnmountIcon);
292 WMSetButtonAction(fPtr->unmountButton, goUnmount, fPtr);
293 WMSetButtonEnabled(fPtr->unmountButton, False);
296 WMRealizeWidget(fPtr->win);
297 WMMapSubwidgets(fPtr->win);
299 WMSetFocusToWidget(fPtr->fileField);
300 WMSetTextFieldCursorPosition(fPtr->fileField, 0);
302 WMLoadBrowserColumnZero(fPtr->browser);
304 WMSetWindowInitialPosition(fPtr->win,
305 (scrPtr->rootView->size.width - WMWidgetWidth(fPtr->win))/2,
306 (scrPtr->rootView->size.height - WMWidgetHeight(fPtr->win))/2);
308 fPtr->flags.canChooseFiles = 1;
309 fPtr->flags.canChooseDirectories = 1;
310 fPtr->flags.autoCompletion = 1;
312 return fPtr;
316 WMOpenPanel*
317 WMGetOpenPanel(WMScreen *scrPtr)
319 WMFilePanel *panel;
321 if (scrPtr->sharedOpenPanel)
322 return scrPtr->sharedOpenPanel;
324 panel = makeFilePanel(scrPtr, "openFilePanel", "Open");
325 panel->flags.fileMustExist = 1;
326 panel->flags.panelType = WP_OPEN;
328 scrPtr->sharedOpenPanel = panel;
330 return panel;
334 WMSavePanel*
335 WMGetSavePanel(WMScreen *scrPtr)
337 WMFilePanel *panel;
339 if (scrPtr->sharedSavePanel)
340 return scrPtr->sharedSavePanel;
342 panel = makeFilePanel(scrPtr, "saveFilePanel", "Save");
343 panel->flags.fileMustExist = 0;
344 panel->flags.panelType = WP_SAVE;
346 scrPtr->sharedSavePanel = panel;
348 return panel;
352 void
353 WMFreeFilePanel(WMFilePanel *panel)
355 if (panel == WMWidgetScreen(panel->win)->sharedSavePanel) {
356 WMWidgetScreen(panel->win)->sharedSavePanel = NULL;
358 if (panel == WMWidgetScreen(panel->win)->sharedOpenPanel) {
359 WMWidgetScreen(panel->win)->sharedOpenPanel = NULL;
361 WMRemoveNotificationObserver(panel);
362 WMUnmapWidget(panel->win);
363 WMDestroyWidget(panel->win);
364 wfree(panel);
369 WMRunModalFilePanelForDirectory(WMFilePanel *panel, WMWindow *owner,
370 char *path, char *name, char **fileTypes)
372 WMScreen *scr = WMWidgetScreen(panel->win);
374 if (name && !owner) {
375 WMSetWindowTitle(panel->win, name);
378 WMChangePanelOwner(panel->win, owner);
380 WMSetFilePanelDirectory(panel, path);
382 switch(panel->flags.panelType) {
383 case WP_OPEN:
384 if (fileTypes)
385 panel->flags.filtered = 1;
386 panel->fileTypes = fileTypes;
387 if (name == NULL)
388 name = "Open";
389 break;
390 case WP_SAVE:
391 panel->fileTypes = NULL;
392 panel->flags.filtered = 0;
393 if (name == NULL)
394 name = "Save";
395 break;
396 default:
397 break;
400 WMSetLabelText(panel->titleLabel, name);
402 WMMapWidget(panel->win);
404 WMRunModalLoop(scr, W_VIEW(panel->win));
406 /* Must withdraw window because the next time we map
407 * it, it might have a different transient owner.
409 WMCloseWindow(panel->win);
411 return (panel->flags.canceled ? False : True);
417 void
418 WMSetFilePanelDirectory(WMFilePanel *panel, char *path)
420 WMList *list;
421 WMListItem *item;
422 int col;
423 char *rest;
425 rest = WMSetBrowserPath(panel->browser, path);
426 if (strcmp(path, "/")==0)
427 rest = NULL;
429 col = WMGetBrowserSelectedColumn(panel->browser);
430 list = WMGetBrowserListInColumn(panel->browser, col);
431 if (list && (item = WMGetListSelectedItem(list))) {
432 if (item->isBranch) {
433 WMSetTextFieldText(panel->fileField, rest);
434 } else {
435 WMSetTextFieldText(panel->fileField, item->text);
437 } else {
438 WMSetTextFieldText(panel->fileField, rest);
443 void
444 WMSetFilePanelCanChooseDirectories(WMFilePanel *panel, Bool flag)
446 panel->flags.canChooseDirectories = flag;
449 void
450 WMSetFilePanelCanChooseFiles(WMFilePanel *panel, Bool flag)
452 panel->flags.canChooseFiles = flag;
456 void
457 WMSetFilePanelAutoCompletion(WMFilePanel *panel, Bool flag)
459 panel->flags.autoCompletion = flag;
463 char*
464 WMGetFilePanelFileName(WMFilePanel *panel)
466 return getCurrentFileName(panel);
470 void
471 WMSetFilePanelAccessoryView(WMFilePanel *panel, WMView *view)
473 WMView *v;
475 panel->accessoryView = view;
477 v = WMWidgetView(panel->win);
479 W_ReparentView(view, v, 0, 0);
481 W_MoveView(view, (v->size.width - v->size.width)/2, 300);
485 WMView*
486 WMGetFilePanelAccessoryView(WMFilePanel *panel)
488 return panel->accessoryView;
492 static char*
493 get_name_from_path(char *path)
495 int size;
497 assert(path!=NULL);
499 size = strlen(path);
501 /* remove trailing / */
502 while (size > 0 && path[size-1]=='/')
503 size--;
504 /* directory was root */
505 if (size == 0)
506 return wstrdup("/");
508 while (size > 0 && path[size-1] != '/')
509 size--;
511 return wstrdup(&(path[size]));
515 static int
516 filterFileName(WMFilePanel *panel, char *file, Bool isDirectory)
518 return True;
522 #define CAST(item) (*((WMListItem**)item))
523 static int
524 comparer(const void *a, const void *b)
526 if (CAST(a)->isBranch == CAST(b)->isBranch)
527 return (strcmp(CAST(a)->text, CAST(b)->text));
528 if (CAST(a)->isBranch)
529 return (-1);
530 return (1);
532 #undef CAST
535 static void
536 listDirectoryOnColumn(WMFilePanel *panel, int column, char *path)
538 WMBrowser *bPtr = panel->browser;
539 struct dirent *dentry;
540 DIR *dir;
541 struct stat stat_buf;
542 char pbuf[PATH_MAX+16];
544 assert(column >= 0);
545 assert(path != NULL);
547 /* put directory name in the title */
548 WMSetBrowserColumnTitle(bPtr, column, get_name_from_path(path));
550 dir = opendir(path);
552 if (!dir) {
553 #ifdef VERBOSE
554 printf("WINGs: could not open directory %s\n", path);
555 #endif
556 return;
559 /* list contents in the column */
560 while ((dentry = readdir(dir))) {
561 if (strcmp(dentry->d_name, ".")==0 ||
562 strcmp(dentry->d_name, "..")==0)
563 continue;
565 strcpy(pbuf, path);
566 if (strcmp(path, "/")!=0)
567 strcat(pbuf, "/");
568 strcat(pbuf, dentry->d_name);
570 if (stat(pbuf, &stat_buf)!=0) {
571 #ifdef VERBOSE
572 printf("WINGs: could not stat %s\n", pbuf);
573 #endif
574 continue;
575 } else {
576 int isDirectory;
578 isDirectory = S_ISDIR(stat_buf.st_mode);
580 if (filterFileName(panel, dentry->d_name, isDirectory))
581 WMInsertBrowserItem(bPtr, column, -1, dentry->d_name, isDirectory);
584 WMSortBrowserColumnWithComparer(bPtr, column, comparer);
586 closedir(dir);
590 static void
591 fillColumn(WMBrowserDelegate *self, WMBrowser *bPtr, int column, WMList *list)
593 char *path;
594 WMFilePanel *panel;
596 if (column > 0) {
597 path = WMGetBrowserPathToColumn(bPtr, column-1);
598 } else {
599 path = wstrdup("/");
602 panel = WMGetHangedData(bPtr);
603 listDirectoryOnColumn(panel, column, path);
604 wfree(path);
608 static void
609 browserDClick(WMBrowser *bPtr, WMFilePanel *panel)
611 WMPerformButtonClick(panel->okButton);
614 static void
615 browserClick(WMBrowser *bPtr, WMFilePanel *panel)
617 int col = WMGetBrowserSelectedColumn(bPtr);
618 WMListItem *item = WMGetBrowserSelectedItemInColumn(bPtr, col);
620 if (!item || item->isBranch)
621 WMSetTextFieldText(panel->fileField, NULL);
622 else {
623 WMSetTextFieldText(panel->fileField, item->text);
628 static void
629 showError(WMScreen *scr, WMWindow *owner, char *s, char *file)
631 char *errStr;
633 if (file) {
634 errStr = wmalloc(strlen(file)+strlen(s));
635 sprintf(errStr, s, file);
636 } else {
637 errStr = wstrdup(s);
639 WMRunAlertPanel(scr, owner, "Error", errStr, "OK", NULL, NULL);
640 wfree(errStr);
644 static void
645 createDir(WMButton *bPre, WMFilePanel *panel)
647 char *dirName, *directory, *file, *s;
648 WMScreen *scr = WMWidgetScreen(panel->win);
650 dirName = WMRunInputPanel(scr, panel->win, "Create Directory",
651 "Enter directory name", "", "OK", "Cancel");
652 if (!dirName)
653 return;
655 directory = getCurrentFileName(panel);
656 s = strrchr(directory,'/');
657 if (s) s[1] = 0;
659 if (dirName[0] == '/') {
660 directory[0] = 0;
661 } else {
662 while ((s = strstr(directory,"//"))) {
663 int i;
664 for (i = 2;s[i] == '/';i++);
665 strcpy(s, &s[i-1]);
667 if ((s = strrchr(directory, '/')) && !s[1]) s[0] = 0;
669 while ((s = strstr(dirName,"//"))) {
670 int i;
671 for (i = 2;s[i] == '/';i++);
672 strcpy(s, &s[i-1]);
674 if ((s = strrchr(dirName, '/')) && !s[1]) s[0] = 0;
676 file = wmalloc(strlen(dirName)+strlen(directory)+1);
677 sprintf(file, "%s/%s", directory, dirName);
678 while ((s = strstr(file,"//"))) {
679 int i;
680 for (i = 2;s[i] == '/';i++);
681 strcpy(s, &s[i-1]);
684 if (mkdir(file,0xfff) != 0) {
685 switch (errno) {
686 case EACCES:
687 showError(scr, panel->win, "Permission denied.", NULL);
688 break;
689 case EEXIST:
690 showError(scr, panel->win, "'%s' already existes.", file);
691 break;
692 case ENOENT:
693 showError(scr, panel->win, "Path does not exist.", NULL);
696 else WMSetFilePanelDirectory(panel, file);
698 wfree(dirName);
699 wfree(directory);
700 wfree(file);
703 static void
704 deleteFile(WMButton *bPre, WMFilePanel *panel)
706 char *file;
707 char *buffer, *s;
708 struct stat filestat;
709 WMScreen *scr = WMWidgetScreen(panel->win);
711 file = getCurrentFileName(panel);
713 while ((s = strstr(file,"//"))) {
714 int i;
715 for (i = 2;s[i] == '/';i++);
716 strcpy(s, &s[i-1]);
718 if (strlen(file) > 1 && (s = strrchr(file, '/')) && !s[1]) s[0] = 0;
720 if (stat(file,&filestat)) {
721 switch (errno) {
722 case ENOENT:
723 showError(scr, panel->win, "'%s' does not exist.", file);
724 break;
725 case EACCES:
726 showError(scr, panel->win, "Permission denied.", NULL);
727 break;
728 case ENOMEM:
729 showError(scr, panel->win,
730 "Insufficient memory available.", NULL);
731 break;
732 case EROFS:
733 showError(scr, panel->win,
734 "'%s' is on a read-only filesystem.", file);
735 break;
736 default:
737 showError(scr, panel->win, "Can not delete '%s'.", file);
739 wfree(file);
740 return;
741 } else if (S_ISDIR(filestat.st_mode)) {
742 buffer = wmalloc(strlen(file)+20);
743 sprintf(buffer,"Delete directory %s ?",file);
744 } else {
745 buffer = wmalloc(strlen(file)+15);
746 sprintf(buffer,"Delete file %s ?",file);
749 if (!WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
750 "Warning", buffer, "OK", "Cancel", NULL)) {
751 if (S_ISDIR(filestat.st_mode)) {
752 if (rmdir(file) != 0) {
753 switch (errno) {
754 case EACCES:
755 showError(scr, panel->win, "Permission denied.", NULL);
756 break;
757 case ENOENT:
758 showError(scr, panel->win, "Directory '%s' does not exist.", file);
759 break;
760 case ENOTEMPTY:
761 showError(scr, panel->win, "Directory '%s' is not empty.", file);
762 break;
763 case EBUSY:
764 showError(scr, panel->win, "Directory '%s' is busy.", file);
765 break;
766 default:
767 showError(scr, panel->win, "Can not delete '%s'.", file);
769 } else {
770 char *s = strrchr(file,'/');
771 if (s) s[0] = 0;
772 WMSetFilePanelDirectory(panel, file);
774 } else if (remove(file) != 0) {
775 switch (errno) {
776 case EISDIR:
777 showError(scr, panel->win, "'%s' is a directory.", file);
778 break;
779 case ENOENT:
780 showError(scr, panel->win, "'%s' does not exist.", file);
781 break;
782 case EACCES:
783 showError(scr, panel->win, "Permission denied.", NULL);
784 break;
785 case ENOMEM:
786 showError(scr, panel->win,
787 "Insufficient memory available.", NULL);
788 break;
789 case EROFS:
790 showError(scr, panel->win,
791 "'%s' is on a read-only filesystem.", file);
792 break;
793 default:
794 showError(scr, panel->win, "Can not delete '%s'.", file);
796 } else {
797 char *s = strrchr(file,'/');
798 if (s) s[1] = 0;
799 WMSetFilePanelDirectory(panel, file);
802 wfree(buffer);
803 wfree(file);
806 static void
807 goUnmount(WMButton *bPtr, WMFilePanel *panel)
812 static void
813 goFloppy(WMButton *bPtr, WMFilePanel *panel)
815 struct stat filestat;
816 WMScreen *scr = WMWidgetScreen(panel->win);
818 if (stat(WINGsConfiguration.floppyPath, &filestat)) {
819 showError(scr, panel->win, "An error occured browsing '%s'.",
820 WINGsConfiguration.floppyPath);
821 return;
822 } else if (!S_ISDIR(filestat.st_mode)) {
823 showError(scr, panel->win, "'%s' is not a directory.",
824 WINGsConfiguration.floppyPath);
825 return;
828 WMSetFilePanelDirectory(panel, WINGsConfiguration.floppyPath);
832 static void
833 goHome(WMButton *bPtr, WMFilePanel *panel)
835 char *home;
837 /* home is statically allocated. Don't free it! */
838 home = wgethomedir();
839 if (!home)
840 return;
842 WMSetFilePanelDirectory(panel, home);
846 static void
847 handleEvents(XEvent *event, void *data)
849 W_FilePanel *pPtr = (W_FilePanel*)data;
850 W_View *view = WMWidgetView(pPtr->win);
852 if (event->type == ConfigureNotify) {
853 if (event->xconfigure.width != view->size.width
854 || event->xconfigure.height != view->size.height) {
855 unsigned int newWidth = event->xconfigure.width;
856 unsigned int newHeight = event->xconfigure.height;
857 int newColumnCount;
859 W_ResizeView(view, newWidth, newHeight);
860 WMResizeWidget(pPtr->line, newWidth, 2);
861 WMResizeWidget(pPtr->browser, newWidth-14,
862 newHeight-(PHEIGHT-200));
863 WMResizeWidget(pPtr->fileField, newWidth-60-10, 24);
864 WMMoveWidget(pPtr->nameLabel, 7, newHeight-(PHEIGHT-282));
865 WMMoveWidget(pPtr->fileField, 60, newHeight-(PHEIGHT-278));
866 WMMoveWidget(pPtr->okButton, newWidth-(PWIDTH-245),
867 newHeight-(PHEIGHT-325));
868 WMMoveWidget(pPtr->cancelButton, newWidth-(PWIDTH-165),
869 newHeight-(PHEIGHT-325));
871 WMMoveWidget(pPtr->trashcanButton, 7, newHeight-(PHEIGHT-325));
872 WMMoveWidget(pPtr->createDirButton, 37, newHeight-(PHEIGHT-325));
873 WMMoveWidget(pPtr->homeButton, 67, newHeight-(PHEIGHT-325));
874 WMMoveWidget(pPtr->disketteButton, 97, newHeight-(PHEIGHT-325));
875 WMMoveWidget(pPtr->unmountButton, 127, newHeight-(PHEIGHT-325));
877 newColumnCount = (newWidth - 14) / 140;
878 WMSetBrowserMaxVisibleColumns(pPtr->browser, newColumnCount);
884 static char*
885 getCurrentFileName(WMFilePanel *panel)
887 char *path;
888 char *file;
889 char *tmp;
890 int len;
892 path = WMGetBrowserPath(panel->browser);
894 len = strlen(path);
895 if (path[len-1]=='/') {
896 file = WMGetTextFieldText(panel->fileField);
897 tmp = wmalloc(strlen(path)+strlen(file)+8);
898 if (file[0]!='/') {
899 strcpy(tmp, path);
900 strcat(tmp, file);
901 } else
902 strcpy(tmp, file);
904 wfree(file);
905 wfree(path);
906 return tmp;
907 } else {
908 return path;
914 static Bool
915 validOpenFile(WMFilePanel *panel)
917 WMListItem *item;
918 int col, haveFile = 0;
919 char *file = WMGetTextFieldText(panel->fileField);
921 if (file[0] != '\0')
922 haveFile = 1;
923 wfree(file);
925 col = WMGetBrowserSelectedColumn(panel->browser);
926 item = WMGetBrowserSelectedItemInColumn(panel->browser, col);
927 if (item) {
928 if (item->isBranch && !panel->flags.canChooseDirectories && !haveFile)
929 return False;
930 else if (!item->isBranch && !panel->flags.canChooseFiles)
931 return False;
932 else
933 return True;
934 } else {
935 /* we compute for / here */
936 if (!panel->flags.canChooseDirectories && !haveFile)
937 return False;
938 else
939 return True;
941 return True;
946 static void
947 buttonClick(WMButton *bPtr, WMFilePanel *panel)
949 WMRange range;
951 if (bPtr == panel->okButton) {
952 if (!validOpenFile(panel))
953 return;
954 if (panel->flags.fileMustExist) {
955 char *file;
957 file = getCurrentFileName(panel);
958 if (access(file, F_OK)!=0) {
959 WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
960 "Error", "File does not exist.",
961 "Ok", NULL, NULL);
962 wfree(file);
963 return;
965 wfree(file);
967 panel->flags.canceled = 0;
968 } else
969 panel->flags.canceled = 1;
971 range.count = range.position = 0;
972 WMSelectTextFieldRange(panel->fileField, range);
973 WMBreakModalLoop(WMWidgetScreen(bPtr));