- Fixed some issues with WMBrowser and the file panel that were
[wmaker-crm.git] / WINGs / wfilepanel.c
blobc8974979c817c6287858e76efd6d16a6aa0a3cf3
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 done:1;
46 unsigned int filtered:1;
47 unsigned int canChooseFiles:1;
48 unsigned int canChooseDirectories:1;
49 unsigned int autoCompletion:1;
50 unsigned int showAllFiles:1;
51 unsigned int canFreeFileTypes:1;
52 unsigned int fileMustExist:1;
53 unsigned int panelType:1;
54 } flags;
55 } 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, char *path);
66 static void browserClick();
67 static void browserDClick();
69 static void fillColumn(WMBrowserDelegate *self, WMBrowser *bPtr, int column,
70 WMList *list);
72 static void deleteFile();
74 static void createDir();
76 static void goHome();
78 static void goFloppy();
80 static void goUnmount();
82 static void buttonClick();
84 static char *getCurrentFileName(WMFilePanel *panel);
86 static void handleEvents(XEvent *event, void *data);
90 static WMBrowserDelegate browserDelegate = {
91 NULL, /* data */
92 fillColumn, /* createRowsForColumn */
93 NULL, /* titleOfColumn */
94 NULL, /* didScroll */
95 NULL /* willScroll */
99 static int
100 closestListItem(WMList *list, char *text, Bool exact)
102 WMListItem *item;
103 WMArray *items = WMGetListItems(list);
104 int i, len = strlen(text);
106 if (len==0)
107 return -1;
109 for(i=0; i<WMGetArrayItemCount(items); i++) {
110 item = WMGetFromArray(items, i);
111 if (strlen(item->text) >= len &&
112 ((exact && strcmp(item->text, text)==0) ||
113 (!exact && strncmp(item->text, text, len)==0))) {
114 return i;
118 return -1;
122 static void
123 textChangedObserver(void *observerData, WMNotification *notification)
125 W_FilePanel *panel = (W_FilePanel*)observerData;
126 char *text;
127 WMList *list;
128 int col = WMGetBrowserNumberOfColumns(panel->browser) - 1;
129 int i, textEvent;
131 if (!(list = WMGetBrowserListInColumn(panel->browser, col)))
132 return;
134 text = WMGetTextFieldText(panel->fileField);
135 textEvent = (int)WMGetNotificationClientData(notification);
137 if (panel->flags.autoCompletion && textEvent!=WMDeleteTextEvent)
138 i = closestListItem(list, text, False);
139 else
140 i = closestListItem(list, text, True);
142 WMSelectListItem(list, i);
143 if (i>=0 && panel->flags.autoCompletion) {
144 WMListItem *item = WMGetListItem(list, i);
145 int textLen = strlen(text), itemTextLen = strlen(item->text);
146 int visibleItems = WMWidgetHeight(list)/WMGetListItemHeight(list);
148 WMSetListPosition(list, i - visibleItems/2);
150 if (textEvent!=WMDeleteTextEvent) {
151 WMRange range;
153 WMInsertTextFieldText(panel->fileField, &item->text[textLen],
154 textLen);
155 range.position = textLen;
156 range.count = itemTextLen - textLen;
157 WMSelectTextFieldRange(panel->fileField, range);
158 /*WMSetTextFieldCursorPosition(panel->fileField, itemTextLen);*/
162 wfree(text);
166 static void
167 textEditedObserver(void *observerData, WMNotification *notification)
169 W_FilePanel *panel = (W_FilePanel*)observerData;
171 if ((int)WMGetNotificationClientData(notification)==WMReturnTextMovement) {
172 WMPerformButtonClick(panel->okButton);
178 static WMFilePanel*
179 makeFilePanel(WMScreen *scrPtr, char *name, char *title)
181 WMFilePanel *fPtr;
182 WMFont *largeFont;
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 WMSetLabelImage(fPtr->iconLabel, scrPtr->applicationIcon);
203 fPtr->titleLabel = WMCreateLabel(fPtr->win);
204 WMResizeWidget(fPtr->titleLabel, PWIDTH-64, 64);
205 WMMoveWidget(fPtr->titleLabel, 64, 0);
206 largeFont = WMBoldSystemFontOfSize(scrPtr, 24);
207 WMSetLabelFont(fPtr->titleLabel, largeFont);
208 WMReleaseFont(largeFont);
209 WMSetLabelText(fPtr->titleLabel, title);
211 fPtr->line = WMCreateFrame(fPtr->win);
212 WMMoveWidget(fPtr->line, 0, 64);
213 WMResizeWidget(fPtr->line, PWIDTH, 2);
214 WMSetFrameRelief(fPtr->line, WRGroove);
216 fPtr->browser = WMCreateBrowser(fPtr->win);
217 WMSetBrowserAllowEmptySelection(fPtr->browser, True);
218 WMSetBrowserDelegate(fPtr->browser, &browserDelegate);
219 WMSetBrowserAction(fPtr->browser, browserClick, fPtr);
220 WMSetBrowserDoubleAction(fPtr->browser, browserDClick, fPtr);
221 WMMoveWidget(fPtr->browser, 7, 72);
222 WMResizeWidget(fPtr->browser, PWIDTH-14,200);
223 WMHangData(fPtr->browser, fPtr);
225 fPtr->nameLabel = WMCreateLabel(fPtr->win);
226 WMMoveWidget(fPtr->nameLabel, 7, 282);
227 WMResizeWidget(fPtr->nameLabel, 55, 14);
228 WMSetLabelText(fPtr->nameLabel, "Name:");
230 fPtr->fileField = WMCreateTextField(fPtr->win);
231 WMMoveWidget(fPtr->fileField, 60, 278);
232 WMResizeWidget(fPtr->fileField, PWIDTH-60-10, 24);
233 WMAddNotificationObserver(textEditedObserver, fPtr,
234 WMTextDidEndEditingNotification,
235 fPtr->fileField);
236 WMAddNotificationObserver(textChangedObserver, fPtr,
237 WMTextDidChangeNotification,
238 fPtr->fileField);
240 fPtr->okButton = WMCreateCommandButton(fPtr->win);
241 WMMoveWidget(fPtr->okButton, 245, 325);
242 WMResizeWidget(fPtr->okButton, 75, 28);
243 WMSetButtonText(fPtr->okButton, "OK");
244 WMSetButtonImage(fPtr->okButton, scrPtr->buttonArrow);
245 WMSetButtonAltImage(fPtr->okButton, scrPtr->pushedButtonArrow);
246 WMSetButtonImagePosition(fPtr->okButton, WIPRight);
247 WMSetButtonAction(fPtr->okButton, buttonClick, fPtr);
249 fPtr->cancelButton = WMCreateCommandButton(fPtr->win);
250 WMMoveWidget(fPtr->cancelButton, 165, 325);
251 WMResizeWidget(fPtr->cancelButton, 75, 28);
252 WMSetButtonText(fPtr->cancelButton, "Cancel");
253 WMSetButtonAction(fPtr->cancelButton, buttonClick, fPtr);
255 fPtr->trashcanButton = WMCreateCommandButton(fPtr->win);
256 WMMoveWidget(fPtr->trashcanButton, 7, 325);
257 WMResizeWidget(fPtr->trashcanButton, 28, 28);
258 WMSetButtonImagePosition(fPtr->trashcanButton, WIPImageOnly);
259 WMSetButtonImage(fPtr->trashcanButton, scrPtr->trashcanIcon);
260 WMSetButtonAltImage(fPtr->trashcanButton, scrPtr->altTrashcanIcon);
261 WMSetButtonAction(fPtr->trashcanButton, deleteFile, fPtr);
263 fPtr->createDirButton = WMCreateCommandButton(fPtr->win);
264 WMMoveWidget(fPtr->createDirButton, 37, 325);
265 WMResizeWidget(fPtr->createDirButton, 28, 28);
266 WMSetButtonImagePosition(fPtr->createDirButton, WIPImageOnly);
267 WMSetButtonImage(fPtr->createDirButton, scrPtr->createDirIcon);
268 WMSetButtonAltImage(fPtr->createDirButton, scrPtr->altCreateDirIcon);
269 WMSetButtonAction(fPtr->createDirButton, createDir, fPtr);
271 fPtr->homeButton = WMCreateCommandButton(fPtr->win);
272 WMMoveWidget(fPtr->homeButton, 67, 325);
273 WMResizeWidget(fPtr->homeButton, 28, 28);
274 WMSetButtonImagePosition(fPtr->homeButton, WIPImageOnly);
275 WMSetButtonImage(fPtr->homeButton, scrPtr->homeIcon);
276 WMSetButtonAltImage(fPtr->homeButton, scrPtr->altHomeIcon);
277 WMSetButtonAction(fPtr->homeButton, goHome, fPtr);
279 fPtr->disketteButton = WMCreateCommandButton(fPtr->win);
280 WMMoveWidget(fPtr->disketteButton, 97, 325);
281 WMResizeWidget(fPtr->disketteButton, 28, 28);
282 WMSetButtonImagePosition(fPtr->disketteButton, WIPImageOnly);
283 WMSetButtonImage(fPtr->disketteButton, scrPtr->disketteIcon);
284 WMSetButtonAltImage(fPtr->disketteButton, scrPtr->altDisketteIcon);
285 WMSetButtonAction(fPtr->disketteButton, goFloppy, fPtr);
287 fPtr->unmountButton = WMCreateCommandButton(fPtr->win);
288 WMMoveWidget(fPtr->unmountButton, 127, 325);
289 WMResizeWidget(fPtr->unmountButton, 28, 28);
290 WMSetButtonImagePosition(fPtr->unmountButton, WIPImageOnly);
291 WMSetButtonImage(fPtr->unmountButton, scrPtr->unmountIcon);
292 WMSetButtonAltImage(fPtr->unmountButton, scrPtr->altUnmountIcon);
293 WMSetButtonAction(fPtr->unmountButton, goUnmount, fPtr);
294 WMSetButtonEnabled(fPtr->unmountButton, False);
297 WMRealizeWidget(fPtr->win);
298 WMMapSubwidgets(fPtr->win);
300 WMSetFocusToWidget(fPtr->fileField);
301 WMSetTextFieldCursorPosition(fPtr->fileField, 0);
303 WMLoadBrowserColumnZero(fPtr->browser);
305 WMSetWindowInitialPosition(fPtr->win,
306 (scrPtr->rootView->size.width - WMWidgetWidth(fPtr->win))/2,
307 (scrPtr->rootView->size.height - WMWidgetHeight(fPtr->win))/2);
309 fPtr->flags.canChooseFiles = 1;
310 fPtr->flags.canChooseDirectories = 1;
311 fPtr->flags.autoCompletion = 1;
313 return fPtr;
317 WMOpenPanel*
318 WMGetOpenPanel(WMScreen *scrPtr)
320 WMFilePanel *panel;
322 if (scrPtr->sharedOpenPanel)
323 return scrPtr->sharedOpenPanel;
325 panel = makeFilePanel(scrPtr, "openFilePanel", "Open");
326 panel->flags.fileMustExist = 1;
327 panel->flags.panelType = WP_OPEN;
329 scrPtr->sharedOpenPanel = panel;
331 return panel;
335 WMSavePanel*
336 WMGetSavePanel(WMScreen *scrPtr)
338 WMFilePanel *panel;
340 if (scrPtr->sharedSavePanel)
341 return scrPtr->sharedSavePanel;
343 panel = makeFilePanel(scrPtr, "saveFilePanel", "Save");
344 panel->flags.fileMustExist = 0;
345 panel->flags.panelType = WP_SAVE;
347 scrPtr->sharedSavePanel = panel;
349 return panel;
353 void
354 WMFreeFilePanel(WMFilePanel *panel)
356 if (panel == WMWidgetScreen(panel->win)->sharedSavePanel) {
357 WMWidgetScreen(panel->win)->sharedSavePanel = NULL;
359 if (panel == WMWidgetScreen(panel->win)->sharedOpenPanel) {
360 WMWidgetScreen(panel->win)->sharedOpenPanel = NULL;
362 WMRemoveNotificationObserver(panel);
363 WMUnmapWidget(panel->win);
364 WMDestroyWidget(panel->win);
365 wfree(panel);
370 WMRunModalFilePanelForDirectory(WMFilePanel *panel, WMWindow *owner,
371 char *path, char *name, char **fileTypes)
373 WMScreen *scr = WMWidgetScreen(panel->win);
374 XEvent event;
376 if (name && !owner) {
377 WMSetWindowTitle(panel->win, name);
380 WMChangePanelOwner(panel->win, owner);
382 WMSetFilePanelDirectory(panel, path);
384 panel->flags.done = 0;
385 switch(panel->flags.panelType) {
386 case WP_OPEN:
387 if (fileTypes)
388 panel->flags.filtered = 1;
389 panel->fileTypes = fileTypes;
390 if (name == NULL)
391 name = "Open";
392 break;
393 case WP_SAVE:
394 panel->fileTypes = NULL;
395 panel->flags.filtered = 0;
396 if (name == NULL)
397 name = "Save";
398 break;
399 default:
400 break;
403 WMSetLabelText(panel->titleLabel, name);
405 scr->modalView = W_VIEW(panel->win);
406 WMMapWidget(panel->win);
408 scr->modal = 1;
409 while (!panel->flags.done) {
410 WMNextEvent(scr->display, &event);
411 WMHandleEvent(&event);
413 scr->modal = 0;
415 /* Must withdraw window because the next time we map
416 * it, it might have a different transient owner.
418 WMCloseWindow(panel->win);
420 return (panel->flags.canceled ? False : True);
426 void
427 WMSetFilePanelDirectory(WMFilePanel *panel, char *path)
429 WMList *list;
430 WMListItem *item;
431 int col;
432 char *rest;
434 rest = WMSetBrowserPath(panel->browser, path);
435 if (strcmp(path, "/")==0)
436 rest = NULL;
438 col = WMGetBrowserSelectedColumn(panel->browser);
439 list = WMGetBrowserListInColumn(panel->browser, col);
440 if (list && (item = WMGetListSelectedItem(list))) {
441 if (item->isBranch) {
442 WMSetTextFieldText(panel->fileField, rest);
443 } else {
444 WMSetTextFieldText(panel->fileField, item->text);
446 } else {
447 WMSetTextFieldText(panel->fileField, rest);
452 void
453 WMSetFilePanelCanChooseDirectories(WMFilePanel *panel, Bool flag)
455 panel->flags.canChooseDirectories = flag;
458 void
459 WMSetFilePanelCanChooseFiles(WMFilePanel *panel, Bool flag)
461 panel->flags.canChooseFiles = flag;
465 void
466 WMSetFilePanelAutoCompletion(WMFilePanel *panel, Bool flag)
468 panel->flags.autoCompletion = flag;
472 char*
473 WMGetFilePanelFileName(WMFilePanel *panel)
475 return getCurrentFileName(panel);
479 void
480 WMSetFilePanelAccessoryView(WMFilePanel *panel, WMView *view)
482 WMView *v;
484 panel->accessoryView = view;
486 v = WMWidgetView(panel->win);
488 W_ReparentView(view, v, 0, 0);
490 W_MoveView(view, (v->size.width - v->size.width)/2, 300);
494 WMView*
495 WMGetFilePanelAccessoryView(WMFilePanel *panel)
497 return panel->accessoryView;
501 static char*
502 get_name_from_path(char *path)
504 int size;
506 assert(path!=NULL);
508 size = strlen(path);
510 /* remove trailing / */
511 while (size > 0 && path[size-1]=='/')
512 size--;
513 /* directory was root */
514 if (size == 0)
515 return wstrdup("/");
517 while (size > 0 && path[size-1] != '/')
518 size--;
520 return wstrdup(&(path[size]));
524 static int
525 filterFileName(WMFilePanel *panel, char *file, Bool isDirectory)
527 return True;
531 #define CAST(item) (*((WMListItem**)item))
532 static int
533 comparer(const void *a, const void *b)
535 if (CAST(a)->isBranch == CAST(b)->isBranch)
536 return (strcmp(CAST(a)->text, CAST(b)->text));
537 if (CAST(a)->isBranch)
538 return (-1);
539 return (1);
541 #undef CAST
544 static void
545 listDirectoryOnColumn(WMFilePanel *panel, int column, char *path)
547 WMBrowser *bPtr = panel->browser;
548 struct dirent *dentry;
549 DIR *dir;
550 struct stat stat_buf;
551 char pbuf[PATH_MAX+16];
553 assert(column >= 0);
554 assert(path != NULL);
556 /* put directory name in the title */
557 WMSetBrowserColumnTitle(bPtr, column, get_name_from_path(path));
559 dir = opendir(path);
561 if (!dir) {
562 #ifdef VERBOSE
563 printf("WINGs: could not open directory %s\n", path);
564 #endif
565 return;
568 /* list contents in the column */
569 while ((dentry = readdir(dir))) {
570 if (strcmp(dentry->d_name, ".")==0 ||
571 strcmp(dentry->d_name, "..")==0)
572 continue;
574 strcpy(pbuf, path);
575 if (strcmp(path, "/")!=0)
576 strcat(pbuf, "/");
577 strcat(pbuf, dentry->d_name);
579 if (stat(pbuf, &stat_buf)!=0) {
580 #ifdef VERBOSE
581 printf("WINGs: could not stat %s\n", pbuf);
582 #endif
583 continue;
584 } else {
585 int isDirectory;
587 isDirectory = S_ISDIR(stat_buf.st_mode);
589 if (filterFileName(panel, dentry->d_name, isDirectory))
590 WMInsertBrowserItem(bPtr, column, -1, dentry->d_name, isDirectory);
593 WMSortBrowserColumnWithComparer(bPtr, column, comparer);
595 closedir(dir);
599 static void
600 fillColumn(WMBrowserDelegate *self, WMBrowser *bPtr, int column, WMList *list)
602 char *path;
603 WMFilePanel *panel;
605 if (column > 0) {
606 path = WMGetBrowserPathToColumn(bPtr, column-1);
607 } else {
608 path = wstrdup("/");
611 panel = WMGetHangedData(bPtr);
612 listDirectoryOnColumn(panel, column, path);
613 wfree(path);
617 static void
618 browserDClick(WMBrowser *bPtr, WMFilePanel *panel)
620 WMPerformButtonClick(panel->okButton);
623 static void
624 browserClick(WMBrowser *bPtr, WMFilePanel *panel)
626 int col = WMGetBrowserSelectedColumn(bPtr);
627 WMListItem *item = WMGetBrowserSelectedItemInColumn(bPtr, col);
629 if (!item || item->isBranch)
630 WMSetTextFieldText(panel->fileField, NULL);
631 else {
632 WMSetTextFieldText(panel->fileField, item->text);
637 static void
638 showError(WMScreen *scr, WMWindow *owner, char *s, char *file)
640 char *errStr;
642 if (file) {
643 errStr = wmalloc(strlen(file)+strlen(s));
644 sprintf(errStr, s, file);
645 } else {
646 errStr = wstrdup(s);
648 WMRunAlertPanel(scr, owner, "Error", errStr, "OK", NULL, NULL);
649 wfree(errStr);
653 static void
654 createDir(WMButton *bPre, WMFilePanel *panel)
656 char *directory_name;
657 char *directory;
658 char *file;
659 char *s;
660 WMScreen *scr = WMWidgetScreen(panel->win);
661 WMInputPanel *_panel;
663 _panel = WMCreateInputPanel(scr, panel->win,
664 "Create Directory", "Enter directory name", "", "OK", "Cancel");
665 scr->modalView = W_VIEW(_panel->win);
666 WMMapWidget(_panel->win);
667 scr->modal = 1;
668 while (!_panel->done || WMScreenPending(scr)) {
669 XEvent event;
670 WMNextEvent(scr->display, &event);
671 WMHandleEvent(&event);
673 scr->modal = 0;
675 if (_panel->result == WAPRDefault)
676 directory_name = WMGetTextFieldText(_panel->text);
677 else {
678 WMDestroyInputPanel(_panel);
679 return;
682 WMDestroyInputPanel(_panel);
684 directory = getCurrentFileName(panel);
686 char *s = strrchr(directory,'/');
687 if (s) s[1] = 0;
690 if (directory_name[0] == '/') {
691 directory[0] = 0;
692 } else {
693 while ((s = strstr(directory,"//"))) {
694 int i;
695 for (i = 2;s[i] == '/';i++);
696 strcpy(s, &s[i-1]);
698 if ((s = strrchr(directory, '/')) && !s[1]) s[0] = 0;
700 while ((s = strstr(directory_name,"//"))) {
701 int i;
702 for (i = 2;s[i] == '/';i++);
703 strcpy(s, &s[i-1]);
705 if ((s = strrchr(directory_name, '/')) && !s[1]) s[0] = 0;
707 file = wmalloc(strlen(directory_name)+strlen(directory)+1);
708 sprintf(file, "%s/%s", directory, directory_name);
709 while ((s = strstr(file,"//"))) {
710 int i;
711 for (i = 2;s[i] == '/';i++);
712 strcpy(s, &s[i-1]);
715 if (mkdir(file,0xfff) != 0) {
716 switch (errno) {
717 case EACCES:
718 showError(scr, panel->win, "Permission denied.", NULL);
719 break;
720 case EEXIST:
721 showError(scr, panel->win, "'%s' already existes.", file);
722 break;
723 case ENOENT:
724 showError(scr, panel->win, "Path does not exist.", NULL);
727 else WMSetFilePanelDirectory(panel, file);
729 wfree(directory_name);
730 wfree(directory);
731 wfree(file);
735 static void
736 deleteFile(WMButton *bPre, WMFilePanel *panel)
738 char *file;
739 char *buffer, *s;
740 struct stat filestat;
741 WMScreen *scr = WMWidgetScreen(panel->win);
743 file = getCurrentFileName(panel);
745 while ((s = strstr(file,"//"))) {
746 int i;
747 for (i = 2;s[i] == '/';i++);
748 strcpy(s, &s[i-1]);
750 if (strlen(file) > 1 && (s = strrchr(file, '/')) && !s[1]) s[0] = 0;
752 if (stat(file,&filestat)) {
753 switch (errno) {
754 case ENOENT:
755 showError(scr, panel->win, "'%s' does not exist.", file);
756 break;
757 case EACCES:
758 showError(scr, panel->win, "Permission denied.", NULL);
759 break;
760 case ENOMEM:
761 showError(scr, panel->win,
762 "Insufficient memory available.", NULL);
763 break;
764 case EROFS:
765 showError(scr, panel->win,
766 "'%s' is on a read-only filesystem.", file);
767 break;
768 default:
769 showError(scr, panel->win, "Can not delete '%s'.", file);
771 wfree(file);
772 return;
773 } else if (S_ISDIR(filestat.st_mode)) {
774 buffer = wmalloc(strlen(file)+20);
775 sprintf(buffer,"Delete directory %s ?",file);
776 } else {
777 buffer = wmalloc(strlen(file)+15);
778 sprintf(buffer,"Delete file %s ?",file);
781 if (!WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
782 "Warning", buffer, "OK", "Cancel", NULL)) {
783 if (S_ISDIR(filestat.st_mode)) {
784 if (rmdir(file) != 0) {
785 switch (errno) {
786 case EACCES:
787 showError(scr, panel->win, "Permission denied.", NULL);
788 break;
789 case ENOENT:
790 showError(scr, panel->win, "Directory '%s' does not exist.", file);
791 break;
792 case ENOTEMPTY:
793 showError(scr, panel->win, "Directory '%s' is not empty.", file);
794 break;
795 case EBUSY:
796 showError(scr, panel->win, "Directory '%s' is busy.", file);
797 break;
798 default:
799 showError(scr, panel->win, "Can not delete '%s'.", file);
801 } else {
802 char *s = strrchr(file,'/');
803 if (s) s[0] = 0;
804 WMSetFilePanelDirectory(panel, file);
806 } else if (remove(file) != 0) {
807 switch (errno) {
808 case EISDIR:
809 showError(scr, panel->win, "'%s' is a directory.", file);
810 break;
811 case ENOENT:
812 showError(scr, panel->win, "'%s' does not exist.", file);
813 break;
814 case EACCES:
815 showError(scr, panel->win, "Permission denied.", NULL);
816 break;
817 case ENOMEM:
818 showError(scr, panel->win,
819 "Insufficient memory available.", NULL);
820 break;
821 case EROFS:
822 showError(scr, panel->win,
823 "'%s' is on a read-only filesystem.", file);
824 break;
825 default:
826 showError(scr, panel->win, "Can not delete '%s'.", file);
828 } else {
829 char *s = strrchr(file,'/');
830 if (s) s[1] = 0;
831 WMSetFilePanelDirectory(panel, file);
834 wfree(buffer);
835 wfree(file);
838 static void
839 goUnmount(WMButton *bPtr, WMFilePanel *panel)
844 static void
845 goFloppy(WMButton *bPtr, WMFilePanel *panel)
847 struct stat filestat;
848 WMScreen *scr = WMWidgetScreen(panel->win);
850 if (stat(WINGsConfiguration.floppyPath, &filestat)) {
851 showError(scr, panel->win, "An error occured browsing '%s'.",
852 WINGsConfiguration.floppyPath);
853 return;
854 } else if (!S_ISDIR(filestat.st_mode)) {
855 showError(scr, panel->win, "'%s' is not a directory.",
856 WINGsConfiguration.floppyPath);
857 return;
860 WMSetFilePanelDirectory(panel, WINGsConfiguration.floppyPath);
864 static void
865 goHome(WMButton *bPtr, WMFilePanel *panel)
867 char *home;
869 /* home is statically allocated. Don't free it! */
870 home = wgethomedir();
871 if (!home)
872 return;
874 WMSetFilePanelDirectory(panel, home);
878 static void
879 handleEvents(XEvent *event, void *data)
881 W_FilePanel *pPtr = (W_FilePanel*)data;
882 W_View *view = WMWidgetView(pPtr->win);
884 if (event->type == ConfigureNotify) {
885 if (event->xconfigure.width != view->size.width
886 || event->xconfigure.height != view->size.height) {
887 unsigned int newWidth = event->xconfigure.width;
888 unsigned int newHeight = event->xconfigure.height;
889 int newColumnCount;
891 W_ResizeView(view, newWidth, newHeight);
892 WMResizeWidget(pPtr->line, newWidth, 2);
893 WMResizeWidget(pPtr->browser, newWidth-14,
894 newHeight-(PHEIGHT-200));
895 WMResizeWidget(pPtr->fileField, newWidth-60-10, 24);
896 WMMoveWidget(pPtr->nameLabel, 7, newHeight-(PHEIGHT-282));
897 WMMoveWidget(pPtr->fileField, 60, newHeight-(PHEIGHT-278));
898 WMMoveWidget(pPtr->okButton, newWidth-(PWIDTH-245),
899 newHeight-(PHEIGHT-325));
900 WMMoveWidget(pPtr->cancelButton, newWidth-(PWIDTH-165),
901 newHeight-(PHEIGHT-325));
903 WMMoveWidget(pPtr->trashcanButton, 7, newHeight-(PHEIGHT-325));
904 WMMoveWidget(pPtr->createDirButton, 37, newHeight-(PHEIGHT-325));
905 WMMoveWidget(pPtr->homeButton, 67, newHeight-(PHEIGHT-325));
906 WMMoveWidget(pPtr->disketteButton, 97, newHeight-(PHEIGHT-325));
907 WMMoveWidget(pPtr->unmountButton, 127, newHeight-(PHEIGHT-325));
909 newColumnCount = (newWidth - 14) / 140;
910 WMSetBrowserMaxVisibleColumns(pPtr->browser, newColumnCount);
916 static char*
917 getCurrentFileName(WMFilePanel *panel)
919 char *path;
920 char *file;
921 char *tmp;
922 int len;
924 path = WMGetBrowserPath(panel->browser);
926 len = strlen(path);
927 if (path[len-1]=='/') {
928 file = WMGetTextFieldText(panel->fileField);
929 tmp = wmalloc(strlen(path)+strlen(file)+8);
930 if (file[0]!='/') {
931 strcpy(tmp, path);
932 strcat(tmp, file);
933 } else
934 strcpy(tmp, file);
936 wfree(file);
937 wfree(path);
938 return tmp;
939 } else {
940 return path;
946 static Bool
947 validOpenFile(WMFilePanel *panel)
949 WMListItem *item;
950 int col, haveFile = 0;
951 char *file = WMGetTextFieldText(panel->fileField);
953 if (file[0] != '\0')
954 haveFile = 1;
955 wfree(file);
957 col = WMGetBrowserSelectedColumn(panel->browser);
958 item = WMGetBrowserSelectedItemInColumn(panel->browser, col);
959 if (item) {
960 if (item->isBranch && !panel->flags.canChooseDirectories && !haveFile)
961 return False;
962 else if (!item->isBranch && !panel->flags.canChooseFiles)
963 return False;
964 else
965 return True;
966 } else {
967 /* we compute for / here */
968 if (!panel->flags.canChooseDirectories && !haveFile)
969 return False;
970 else
971 return True;
973 return True;
978 static void
979 buttonClick(WMButton *bPtr, WMFilePanel *panel)
981 WMRange range;
983 if (bPtr == panel->okButton) {
984 if (!validOpenFile(panel))
985 return;
986 if (panel->flags.fileMustExist) {
987 char *file;
989 file = getCurrentFileName(panel);
990 if (access(file, F_OK)!=0) {
991 WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
992 "Error", "File does not exist.",
993 "Ok", NULL, NULL);
994 wfree(file);
995 return;
997 wfree(file);
999 panel->flags.canceled = 0;
1000 } else
1001 panel->flags.canceled = 1;
1003 range.count = range.position = 0;
1004 WMSelectTextFieldRange(panel->fileField, range);
1005 panel->flags.done = 1;