Describe relaunching in the NEWS file.
[wmaker-crm.git] / WINGs / wfilepanel.c
blob660ce34d5c48e2ce72f9df2698532cdd06d9d97d
2 #include <sys/types.h>
3 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <dirent.h>
7 #include <limits.h>
8 #include <errno.h>
9 #include <stdint.h>
11 #include "WINGsP.h"
12 #include "wconfig.h"
14 #ifndef PATH_MAX
15 #define PATH_MAX 1024
16 #endif
18 typedef struct W_FilePanel {
19 WMWindow *win;
21 WMLabel *iconLabel;
22 WMLabel *titleLabel;
24 WMFrame *line;
26 WMLabel *nameLabel;
27 WMBrowser *browser;
29 WMButton *okButton;
30 WMButton *cancelButton;
32 WMButton *homeButton;
33 WMButton *trashcanButton;
34 WMButton *createDirButton;
35 WMButton *disketteButton;
36 WMButton *unmountButton;
38 WMView *accessoryView;
40 WMTextField *fileField;
42 char **fileTypes;
44 struct {
45 unsigned int canExit:1;
46 unsigned int canceled:1; /* clicked on cancel */
47 unsigned int filtered:1;
48 unsigned int canChooseFiles:1;
49 unsigned int canChooseDirectories:1;
50 unsigned int autoCompletion:1;
51 unsigned int showAllFiles:1;
52 unsigned int canFreeFileTypes:1;
53 unsigned int fileMustExist:1;
54 unsigned int panelType:1;
55 } flags;
56 } W_FilePanel;
58 /* Type of panel */
59 #define WP_OPEN 0
60 #define WP_SAVE 1
62 #define PWIDTH 330
63 #define PHEIGHT 360
65 static void listDirectoryOnColumn(WMFilePanel * panel, int column, char *path);
66 static void browserClick();
67 static void browserDClick();
69 static void fillColumn(WMBrowserDelegate * self, WMBrowser * bPtr, int column, WMList * list);
71 static void normalizePath(char *s);
73 static void deleteFile();
75 static void createDir();
77 static void goHome();
79 static void goFloppy();
81 static void goUnmount();
83 static void buttonClick();
85 static char *getCurrentFileName(WMFilePanel * panel);
87 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 */
97 static int closestListItem(WMList * list, char *text, Bool exact)
99 WMListItem *item;
100 WMArray *items = WMGetListItems(list);
101 int i, len = strlen(text);
103 if (len == 0)
104 return -1;
106 for (i = 0; i < WMGetArrayItemCount(items); i++) {
107 item = WMGetFromArray(items, i);
108 if (strlen(item->text) >= len &&
109 ((exact && strcmp(item->text, text) == 0) ||
110 (!exact && strncmp(item->text, text, len) == 0))) {
111 return i;
115 return -1;
118 static void textChangedObserver(void *observerData, WMNotification * notification)
120 W_FilePanel *panel = (W_FilePanel *) observerData;
121 char *text;
122 WMList *list;
123 int col = WMGetBrowserNumberOfColumns(panel->browser) - 1;
124 int i;
125 uintptr_t textEvent;
127 if (!(list = WMGetBrowserListInColumn(panel->browser, col)))
128 return;
130 text = WMGetTextFieldText(panel->fileField);
131 textEvent = (uintptr_t)WMGetNotificationClientData(notification);
133 if (panel->flags.autoCompletion && textEvent != WMDeleteTextEvent)
134 i = closestListItem(list, text, False);
135 else
136 i = closestListItem(list, text, True);
138 WMSelectListItem(list, i);
139 if (i >= 0 && panel->flags.autoCompletion) {
140 WMListItem *item = WMGetListItem(list, i);
141 int textLen = strlen(text), itemTextLen = strlen(item->text);
142 int visibleItems = WMWidgetHeight(list) / WMGetListItemHeight(list);
144 WMSetListPosition(list, i - visibleItems / 2);
146 if (textEvent != WMDeleteTextEvent) {
147 WMRange range;
149 WMInsertTextFieldText(panel->fileField, &item->text[textLen], textLen);
150 range.position = textLen;
151 range.count = itemTextLen - textLen;
152 WMSelectTextFieldRange(panel->fileField, range);
153 /*WMSetTextFieldCursorPosition(panel->fileField, itemTextLen); */
157 wfree(text);
160 static void textEditedObserver(void *observerData, WMNotification * notification)
162 W_FilePanel *panel = (W_FilePanel *) observerData;
164 if ((uintptr_t)WMGetNotificationClientData(notification) == WMReturnTextMovement) {
165 WMPerformButtonClick(panel->okButton);
169 static WMFilePanel *makeFilePanel(WMScreen * scrPtr, char *name, char *title)
171 WMFilePanel *fPtr;
172 WMFont *largeFont;
173 WMPixmap *icon;
175 fPtr = wmalloc(sizeof(WMFilePanel));
177 fPtr->win = WMCreateWindowWithStyle(scrPtr, name, WMTitledWindowMask | WMResizableWindowMask);
178 WMResizeWidget(fPtr->win, PWIDTH, PHEIGHT);
179 WMSetWindowTitle(fPtr->win, "");
181 WMCreateEventHandler(WMWidgetView(fPtr->win), StructureNotifyMask, handleEvents, fPtr);
182 WMSetWindowMinSize(fPtr->win, PWIDTH, PHEIGHT);
184 fPtr->iconLabel = WMCreateLabel(fPtr->win);
185 WMResizeWidget(fPtr->iconLabel, 64, 64);
186 WMMoveWidget(fPtr->iconLabel, 0, 0);
187 WMSetLabelImagePosition(fPtr->iconLabel, WIPImageOnly);
188 icon = WMCreateApplicationIconBlendedPixmap(scrPtr, (RColor *) NULL);
189 if (icon) {
190 WMSetLabelImage(fPtr->iconLabel, icon);
191 WMReleasePixmap(icon);
192 } else {
193 WMSetLabelImage(fPtr->iconLabel, scrPtr->applicationIconPixmap);
196 fPtr->titleLabel = WMCreateLabel(fPtr->win);
197 WMResizeWidget(fPtr->titleLabel, PWIDTH - 64, 64);
198 WMMoveWidget(fPtr->titleLabel, 64, 0);
199 largeFont = WMBoldSystemFontOfSize(scrPtr, 24);
200 WMSetLabelFont(fPtr->titleLabel, largeFont);
201 WMReleaseFont(largeFont);
202 WMSetLabelText(fPtr->titleLabel, title);
204 fPtr->line = WMCreateFrame(fPtr->win);
205 WMMoveWidget(fPtr->line, 0, 64);
206 WMResizeWidget(fPtr->line, PWIDTH, 2);
207 WMSetFrameRelief(fPtr->line, WRGroove);
209 fPtr->browser = WMCreateBrowser(fPtr->win);
210 WMSetBrowserAllowEmptySelection(fPtr->browser, True);
211 WMSetBrowserDelegate(fPtr->browser, &browserDelegate);
212 WMSetBrowserAction(fPtr->browser, browserClick, fPtr);
213 WMSetBrowserDoubleAction(fPtr->browser, browserDClick, fPtr);
214 WMMoveWidget(fPtr->browser, 7, 72);
215 WMResizeWidget(fPtr->browser, PWIDTH - 14, 200);
216 WMHangData(fPtr->browser, fPtr);
218 fPtr->nameLabel = WMCreateLabel(fPtr->win);
219 WMMoveWidget(fPtr->nameLabel, 7, 282);
220 WMResizeWidget(fPtr->nameLabel, 55, 14);
221 WMSetLabelText(fPtr->nameLabel, _("Name:"));
223 fPtr->fileField = WMCreateTextField(fPtr->win);
224 WMMoveWidget(fPtr->fileField, 60, 278);
225 WMResizeWidget(fPtr->fileField, PWIDTH - 60 - 10, 24);
226 WMAddNotificationObserver(textEditedObserver, fPtr, WMTextDidEndEditingNotification, fPtr->fileField);
227 WMAddNotificationObserver(textChangedObserver, fPtr, WMTextDidChangeNotification, fPtr->fileField);
229 fPtr->okButton = WMCreateCommandButton(fPtr->win);
230 WMMoveWidget(fPtr->okButton, 245, 325);
231 WMResizeWidget(fPtr->okButton, 75, 28);
232 WMSetButtonText(fPtr->okButton, _("OK"));
233 WMSetButtonImage(fPtr->okButton, scrPtr->buttonArrow);
234 WMSetButtonAltImage(fPtr->okButton, scrPtr->pushedButtonArrow);
235 WMSetButtonImagePosition(fPtr->okButton, WIPRight);
236 WMSetButtonAction(fPtr->okButton, buttonClick, fPtr);
238 fPtr->cancelButton = WMCreateCommandButton(fPtr->win);
239 WMMoveWidget(fPtr->cancelButton, 165, 325);
240 WMResizeWidget(fPtr->cancelButton, 75, 28);
241 WMSetButtonText(fPtr->cancelButton, _("Cancel"));
242 WMSetButtonAction(fPtr->cancelButton, buttonClick, fPtr);
244 fPtr->trashcanButton = WMCreateCommandButton(fPtr->win);
245 WMMoveWidget(fPtr->trashcanButton, 7, 325);
246 WMResizeWidget(fPtr->trashcanButton, 28, 28);
247 WMSetButtonImagePosition(fPtr->trashcanButton, WIPImageOnly);
248 WMSetButtonImage(fPtr->trashcanButton, scrPtr->trashcanIcon);
249 WMSetButtonAltImage(fPtr->trashcanButton, scrPtr->altTrashcanIcon);
250 WMSetButtonAction(fPtr->trashcanButton, deleteFile, fPtr);
252 fPtr->createDirButton = WMCreateCommandButton(fPtr->win);
253 WMMoveWidget(fPtr->createDirButton, 37, 325);
254 WMResizeWidget(fPtr->createDirButton, 28, 28);
255 WMSetButtonImagePosition(fPtr->createDirButton, WIPImageOnly);
256 WMSetButtonImage(fPtr->createDirButton, scrPtr->createDirIcon);
257 WMSetButtonAltImage(fPtr->createDirButton, scrPtr->altCreateDirIcon);
258 WMSetButtonAction(fPtr->createDirButton, createDir, fPtr);
260 fPtr->homeButton = WMCreateCommandButton(fPtr->win);
261 WMMoveWidget(fPtr->homeButton, 67, 325);
262 WMResizeWidget(fPtr->homeButton, 28, 28);
263 WMSetButtonImagePosition(fPtr->homeButton, WIPImageOnly);
264 WMSetButtonImage(fPtr->homeButton, scrPtr->homeIcon);
265 WMSetButtonAltImage(fPtr->homeButton, scrPtr->altHomeIcon);
266 WMSetButtonAction(fPtr->homeButton, goHome, fPtr);
268 fPtr->disketteButton = WMCreateCommandButton(fPtr->win);
269 WMMoveWidget(fPtr->disketteButton, 97, 325);
270 WMResizeWidget(fPtr->disketteButton, 28, 28);
271 WMSetButtonImagePosition(fPtr->disketteButton, WIPImageOnly);
272 WMSetButtonImage(fPtr->disketteButton, scrPtr->disketteIcon);
273 WMSetButtonAltImage(fPtr->disketteButton, scrPtr->altDisketteIcon);
274 WMSetButtonAction(fPtr->disketteButton, goFloppy, fPtr);
276 fPtr->unmountButton = WMCreateCommandButton(fPtr->win);
277 WMMoveWidget(fPtr->unmountButton, 127, 325);
278 WMResizeWidget(fPtr->unmountButton, 28, 28);
279 WMSetButtonImagePosition(fPtr->unmountButton, WIPImageOnly);
280 WMSetButtonImage(fPtr->unmountButton, scrPtr->unmountIcon);
281 WMSetButtonAltImage(fPtr->unmountButton, scrPtr->altUnmountIcon);
282 WMSetButtonAction(fPtr->unmountButton, goUnmount, fPtr);
283 WMSetButtonEnabled(fPtr->unmountButton, False);
285 WMRealizeWidget(fPtr->win);
286 WMMapSubwidgets(fPtr->win);
288 WMSetFocusToWidget(fPtr->fileField);
289 WMSetTextFieldCursorPosition(fPtr->fileField, 0);
291 WMLoadBrowserColumnZero(fPtr->browser);
293 WMSetWindowInitialPosition(fPtr->win,
294 (scrPtr->rootView->size.width - WMWidgetWidth(fPtr->win)) / 2,
295 (scrPtr->rootView->size.height - WMWidgetHeight(fPtr->win)) / 2);
297 fPtr->flags.canChooseFiles = 1;
298 fPtr->flags.canChooseDirectories = 1;
299 fPtr->flags.autoCompletion = 1;
301 return fPtr;
304 WMOpenPanel *WMGetOpenPanel(WMScreen * scrPtr)
306 WMFilePanel *panel;
308 if (scrPtr->sharedOpenPanel)
309 return scrPtr->sharedOpenPanel;
311 panel = makeFilePanel(scrPtr, "openFilePanel", _("Open"));
312 panel->flags.fileMustExist = 1;
313 panel->flags.panelType = WP_OPEN;
315 scrPtr->sharedOpenPanel = panel;
317 return panel;
320 WMSavePanel *WMGetSavePanel(WMScreen * scrPtr)
322 WMFilePanel *panel;
324 if (scrPtr->sharedSavePanel)
325 return scrPtr->sharedSavePanel;
327 panel = makeFilePanel(scrPtr, "saveFilePanel", _("Save"));
328 panel->flags.fileMustExist = 0;
329 panel->flags.panelType = WP_SAVE;
331 scrPtr->sharedSavePanel = panel;
333 return panel;
336 void WMFreeFilePanel(WMFilePanel * panel)
338 if (panel == WMWidgetScreen(panel->win)->sharedSavePanel) {
339 WMWidgetScreen(panel->win)->sharedSavePanel = NULL;
341 if (panel == WMWidgetScreen(panel->win)->sharedOpenPanel) {
342 WMWidgetScreen(panel->win)->sharedOpenPanel = NULL;
344 WMRemoveNotificationObserver(panel);
345 WMUnmapWidget(panel->win);
346 WMDestroyWidget(panel->win);
347 wfree(panel);
351 WMRunModalFilePanelForDirectory(WMFilePanel * panel, WMWindow * owner, char *path, char *name, char **fileTypes)
353 WMScreen *scr = WMWidgetScreen(panel->win);
355 if (name && !owner) {
356 WMSetWindowTitle(panel->win, name);
359 WMChangePanelOwner(panel->win, owner);
361 WMSetFilePanelDirectory(panel, path);
363 switch (panel->flags.panelType) {
364 case WP_OPEN:
365 if (fileTypes)
366 panel->flags.filtered = 1;
367 panel->fileTypes = fileTypes;
368 if (name == NULL)
369 name = _("Open");
370 break;
371 case WP_SAVE:
372 panel->fileTypes = NULL;
373 panel->flags.filtered = 0;
374 if (name == NULL)
375 name = _("Save");
376 break;
377 default:
378 break;
381 WMSetLabelText(panel->titleLabel, name);
383 WMMapWidget(panel->win);
385 WMRunModalLoop(scr, W_VIEW(panel->win));
387 /* Must withdraw window because the next time we map
388 * it, it might have a different transient owner.
390 WMCloseWindow(panel->win);
392 return (panel->flags.canceled ? False : True);
395 void WMSetFilePanelDirectory(WMFilePanel * panel, char *path)
397 WMList *list;
398 WMListItem *item;
399 int col;
400 char *rest;
402 rest = WMSetBrowserPath(panel->browser, path);
403 if (strcmp(path, "/") == 0)
404 rest = NULL;
406 col = WMGetBrowserSelectedColumn(panel->browser);
407 list = WMGetBrowserListInColumn(panel->browser, col);
408 if (list && (item = WMGetListSelectedItem(list))) {
409 if (item->isBranch) {
410 WMSetTextFieldText(panel->fileField, rest);
411 } else {
412 WMSetTextFieldText(panel->fileField, item->text);
414 } else {
415 WMSetTextFieldText(panel->fileField, rest);
419 void WMSetFilePanelCanChooseDirectories(WMFilePanel * panel, Bool flag)
421 panel->flags.canChooseDirectories = ((flag == 0) ? 0 : 1);
424 void WMSetFilePanelCanChooseFiles(WMFilePanel * panel, Bool flag)
426 panel->flags.canChooseFiles = ((flag == 0) ? 0 : 1);
429 void WMSetFilePanelAutoCompletion(WMFilePanel * panel, Bool flag)
431 panel->flags.autoCompletion = ((flag == 0) ? 0 : 1);
434 char *WMGetFilePanelFileName(WMFilePanel * panel)
436 return getCurrentFileName(panel);
439 void WMSetFilePanelAccessoryView(WMFilePanel * panel, WMView * view)
441 WMView *v;
443 panel->accessoryView = view;
445 v = WMWidgetView(panel->win);
447 W_ReparentView(view, v, 0, 0);
449 W_MoveView(view, (v->size.width - v->size.width) / 2, 300);
452 WMView *WMGetFilePanelAccessoryView(WMFilePanel * panel)
454 return panel->accessoryView;
457 static char *get_name_from_path(char *path)
459 int size;
461 assert(path != NULL);
463 size = strlen(path);
465 /* remove trailing / */
466 while (size > 0 && path[size - 1] == '/')
467 size--;
468 /* directory was root */
469 if (size == 0)
470 return wstrdup("/");
472 while (size > 0 && path[size - 1] != '/')
473 size--;
475 return wstrdup(&(path[size]));
478 static int filterFileName(WMFilePanel * panel, char *file, Bool isDirectory)
480 return True;
483 #define CAST(item) (*((WMListItem**)item))
484 static int comparer(const void *a, const void *b)
486 if (CAST(a)->isBranch == CAST(b)->isBranch)
487 return (strcmp(CAST(a)->text, CAST(b)->text));
488 if (CAST(a)->isBranch)
489 return (-1);
490 return (1);
493 #undef CAST
495 static void listDirectoryOnColumn(WMFilePanel * panel, int column, char *path)
497 WMBrowser *bPtr = panel->browser;
498 struct dirent *dentry;
499 DIR *dir;
500 struct stat stat_buf;
501 char pbuf[PATH_MAX + 16];
502 char *name;
504 assert(column >= 0);
505 assert(path != NULL);
507 /* put directory name in the title */
508 name = get_name_from_path(path);
509 WMSetBrowserColumnTitle(bPtr, column, name);
510 wfree(name);
512 dir = opendir(path);
514 if (!dir) {
515 #ifdef VERBOSE
516 printf(_("WINGs: could not open directory %s\n"), path);
517 #endif
518 return;
521 /* list contents in the column */
522 while ((dentry = readdir(dir))) {
523 if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
524 continue;
526 if (wstrlcpy(pbuf, path, sizeof(pbuf)) >= sizeof(pbuf))
527 goto out;
528 if (strcmp(path, "/") != 0 &&
529 wstrlcat(pbuf, "/", sizeof(pbuf)) >= sizeof(pbuf))
530 goto out;
531 if (wstrlcat(pbuf, dentry->d_name, sizeof(pbuf)) >= sizeof(pbuf))
532 goto out;
534 if (stat(pbuf, &stat_buf) != 0) {
535 #ifdef VERBOSE
536 printf(_("WINGs: could not stat %s\n"), pbuf);
537 #endif
538 continue;
539 } else {
540 int isDirectory;
542 isDirectory = S_ISDIR(stat_buf.st_mode);
544 if (filterFileName(panel, dentry->d_name, isDirectory))
545 WMInsertBrowserItem(bPtr, column, -1, dentry->d_name, isDirectory);
548 WMSortBrowserColumnWithComparer(bPtr, column, comparer);
550 out:
551 closedir(dir);
554 static void fillColumn(WMBrowserDelegate * self, WMBrowser * bPtr, int column, WMList * list)
556 char *path;
557 WMFilePanel *panel;
559 if (column > 0) {
560 path = WMGetBrowserPathToColumn(bPtr, column - 1);
561 } else {
562 path = wstrdup("/");
565 panel = WMGetHangedData(bPtr);
566 listDirectoryOnColumn(panel, column, path);
567 wfree(path);
570 static void browserDClick(WMBrowser * bPtr, WMFilePanel * panel)
572 WMPerformButtonClick(panel->okButton);
575 static void browserClick(WMBrowser * bPtr, WMFilePanel * panel)
577 int col = WMGetBrowserSelectedColumn(bPtr);
578 WMListItem *item = WMGetBrowserSelectedItemInColumn(bPtr, col);
580 if (!item || item->isBranch)
581 WMSetTextFieldText(panel->fileField, NULL);
582 else {
583 WMSetTextFieldText(panel->fileField, item->text);
587 static void showError(WMScreen * scr, WMWindow * owner, char *s, char *file)
589 char *errStr;
591 if (file) {
592 errStr = wmalloc(strlen(file) + strlen(s));
593 sprintf(errStr, s, file);
594 } else {
595 errStr = wstrdup(s);
597 WMRunAlertPanel(scr, owner, _("Error"), errStr, _("OK"), NULL, NULL);
598 wfree(errStr);
601 static void createDir(WMButton * bPre, WMFilePanel * panel)
603 char *dirName, *directory, *file;
604 size_t slen;
605 WMScreen *scr = WMWidgetScreen(panel->win);
607 dirName = WMRunInputPanel(scr, panel->win, _("Create Directory"),
608 _("Enter directory name"), "", _("OK"), _("Cancel"));
609 if (!dirName)
610 return;
612 /* if `dirName' is an absolute path, don't mind `directory'.
613 * normalize as needed (possibly not needed at all?) */
614 normalizePath(dirName);
615 if (*dirName != '/') {
616 directory = getCurrentFileName(panel);
617 normalizePath(directory);
618 } else {
619 directory = NULL;
622 slen = strlen(dirName) + (directory ? strlen(directory) + 1 /* "/" */ : 0) + 1 /* NULL */;
623 file = wmalloc(slen);
625 if (directory &&
626 (wstrlcat(file, directory, slen) >= slen ||
627 wstrlcat(file, "/", slen) >= slen))
628 goto out;
630 if (wstrlcat(file, dirName, slen) >= slen)
631 goto out;
633 if (mkdir(file, 00777) != 0) {
634 #define __msgbufsize__ 512
635 char *buffer = wmalloc(__msgbufsize__);
636 snprintf(buffer, __msgbufsize__, _("Can not create %s: %s"), file, strerror(errno));
637 showError(scr, panel->win, buffer, NULL);
638 wfree(buffer);
639 #undef __msgbufsize__
640 } else {
641 WMSetFilePanelDirectory(panel, file);
644 out:
645 if (dirName)
646 wfree(dirName);
647 if (directory)
648 wfree(directory);
649 if (file)
650 wfree(file);
654 *----------------------------------------------------------------------
655 * normalizePath--
656 * Remove multiple consecutive and any trailing slashes from
657 * a path.
658 *----------------------------------------------------------------------
660 static void normalizePath(char *s)
662 int i, j, found;
664 found = 0;
665 for (i = 0; s[i]; (void)(!found && i++)) {
666 found = 0;
667 if (s[i] == '/' && s[i+1] == '/') {
668 int nslash = 1;
669 found = 1;
670 i++;
671 while (s[i+nslash] == '/')
672 nslash++;
673 for (j = 0; s[i+j+nslash]; j++)
674 s[i+j] = s[i+j+nslash];
675 s[i+j] = '\0';
678 if (i > 1 && s[--i] == '/')
679 s[i] = '\0';
683 static void deleteFile(WMButton * bPre, WMFilePanel * panel)
685 char *file, *buffer;
686 struct stat filestat;
687 WMScreen *scr = WMWidgetScreen(panel->win);
688 #define __msgbufsize__ 512
690 buffer = wmalloc(__msgbufsize__);
691 file = getCurrentFileName(panel);
692 normalizePath(file);
694 if (stat(file, &filestat) == -1) {
695 snprintf(buffer, __msgbufsize__, _("Can not find %s: %s"), file, strerror(errno));
696 showError(scr, panel->win, buffer, NULL);
697 goto out;
700 snprintf(buffer, __msgbufsize__, _("Delete %s %s?"),
701 S_ISDIR(filestat.st_mode) ? _("directory") : _("file"), file);
703 if (!WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
704 _("Warning"), buffer, _("OK"), _("Cancel"), NULL)) {
706 if (remove(file) == -1) {
707 snprintf(buffer, __msgbufsize__, _("Removing %s failed: %s"), file, strerror(errno));
708 showError(scr, panel->win, buffer, NULL);
709 } else {
710 char *s = strrchr(file, '/');
711 if (s)
712 s[0] = 0;
713 WMSetFilePanelDirectory(panel, file);
717 out:
718 if (buffer)
719 wfree(buffer);
720 if (file)
721 wfree(file);
722 #undef __msgbufsize__
725 static void goUnmount(WMButton * bPtr, WMFilePanel * panel)
729 static void goFloppy(WMButton * bPtr, WMFilePanel * panel)
731 struct stat filestat;
732 WMScreen *scr = WMWidgetScreen(panel->win);
734 if (stat(WINGsConfiguration.floppyPath, &filestat)) {
735 showError(scr, panel->win, _("An error occured browsing '%s'."), WINGsConfiguration.floppyPath);
736 return;
737 } else if (!S_ISDIR(filestat.st_mode)) {
738 showError(scr, panel->win, _("'%s' is not a directory."), WINGsConfiguration.floppyPath);
739 return;
742 WMSetFilePanelDirectory(panel, WINGsConfiguration.floppyPath);
745 static void goHome(WMButton * bPtr, WMFilePanel * panel)
747 char *home;
749 /* home is statically allocated. Don't free it! */
750 home = wgethomedir();
751 if (!home)
752 return;
754 WMSetFilePanelDirectory(panel, home);
757 static void handleEvents(XEvent * event, void *data)
759 W_FilePanel *pPtr = (W_FilePanel *) data;
760 W_View *view = WMWidgetView(pPtr->win);
762 if (event->type == ConfigureNotify) {
763 if (event->xconfigure.width != view->size.width || event->xconfigure.height != view->size.height) {
764 unsigned int newWidth = event->xconfigure.width;
765 unsigned int newHeight = event->xconfigure.height;
766 int newColumnCount;
768 W_ResizeView(view, newWidth, newHeight);
769 WMResizeWidget(pPtr->line, newWidth, 2);
770 WMResizeWidget(pPtr->browser, newWidth - 14, newHeight - (PHEIGHT - 200));
771 WMResizeWidget(pPtr->fileField, newWidth - 60 - 10, 24);
772 WMMoveWidget(pPtr->nameLabel, 7, newHeight - (PHEIGHT - 282));
773 WMMoveWidget(pPtr->fileField, 60, newHeight - (PHEIGHT - 278));
774 WMMoveWidget(pPtr->okButton, newWidth - (PWIDTH - 245), newHeight - (PHEIGHT - 325));
775 WMMoveWidget(pPtr->cancelButton, newWidth - (PWIDTH - 165), newHeight - (PHEIGHT - 325));
777 WMMoveWidget(pPtr->trashcanButton, 7, newHeight - (PHEIGHT - 325));
778 WMMoveWidget(pPtr->createDirButton, 37, newHeight - (PHEIGHT - 325));
779 WMMoveWidget(pPtr->homeButton, 67, newHeight - (PHEIGHT - 325));
780 WMMoveWidget(pPtr->disketteButton, 97, newHeight - (PHEIGHT - 325));
781 WMMoveWidget(pPtr->unmountButton, 127, newHeight - (PHEIGHT - 325));
783 newColumnCount = (newWidth - 14) / 140;
784 WMSetBrowserMaxVisibleColumns(pPtr->browser, newColumnCount);
789 static char *getCurrentFileName(WMFilePanel * panel)
791 char *path;
792 char *file;
793 char *ret;
794 size_t slen;
796 path = WMGetBrowserPath(panel->browser);
798 if (!path)
799 return NULL;
801 if (path[strlen(path) -1] != '/')
802 return path;
804 file = WMGetTextFieldText(panel->fileField);
805 slen = strlen(path) + strlen(file) + 1;
806 ret = wmalloc(slen);
808 if (*file != '/' &&
809 wstrlcat(ret, path, slen) >= slen)
810 goto error;
812 if (wstrlcat(ret, file, slen) >= slen)
813 goto error;
815 wfree(file);
816 wfree(path);
817 return ret;
819 error:
820 wfree(file);
821 wfree(path);
822 wfree(ret);
824 return NULL;
828 static Bool validOpenFile(WMFilePanel * panel)
830 WMListItem *item;
831 int col, haveFile = 0;
832 char *file = WMGetTextFieldText(panel->fileField);
834 if (file[0] != '\0')
835 haveFile = 1;
836 wfree(file);
838 col = WMGetBrowserSelectedColumn(panel->browser);
839 item = WMGetBrowserSelectedItemInColumn(panel->browser, col);
840 if (item) {
841 if (item->isBranch && !panel->flags.canChooseDirectories && !haveFile)
842 return False;
843 else if (!item->isBranch && !panel->flags.canChooseFiles)
844 return False;
845 else
846 return True;
847 } else {
848 /* we compute for / here */
849 if (!panel->flags.canChooseDirectories && !haveFile)
850 return False;
851 else
852 return True;
854 return True;
857 static void buttonClick(WMButton * bPtr, WMFilePanel * panel)
859 WMRange range;
861 if (bPtr == panel->okButton) {
862 if (!validOpenFile(panel))
863 return;
864 if (panel->flags.fileMustExist) {
865 char *file;
867 file = getCurrentFileName(panel);
868 if (access(file, F_OK) != 0) {
869 WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
870 _("Error"), _("File does not exist."), _("OK"), NULL, NULL);
871 wfree(file);
872 return;
874 wfree(file);
876 panel->flags.canceled = 0;
877 } else
878 panel->flags.canceled = 1;
880 range.count = range.position = 0;
881 WMSelectTextFieldRange(panel->fileField, range);
882 WMBreakModalLoop(WMWidgetScreen(bPtr));