Updating to version 0.20.2
[wmaker-crm.git] / WINGs / wfilepanel.c
blob6608f6e8805464a884f8873b784020e1d9b70155
5 #include "WINGsP.h"
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <unistd.h>
10 #include <dirent.h>
11 #include <limits.h>
13 #ifndef PATH_MAX
14 #define PATH_MAX 1024
15 #endif
17 typedef struct W_FilePanel {
18 WMWindow *win;
20 WMLabel *iconLabel;
21 WMLabel *titleLabel;
23 WMFrame *line;
25 WMLabel *nameLabel;
26 WMBrowser *browser;
28 WMButton *okButton;
29 WMButton *cancelButton;
31 WMButton *homeButton;
33 WMTextField *fileField;
35 char **fileTypes;
37 struct {
38 unsigned int canExit:1;
39 unsigned int canceled:1; /* clicked on cancel */
40 unsigned int done:1;
41 unsigned int filtered:1;
42 unsigned int canChooseFiles:1;
43 unsigned int canChooseDirectories:1;
44 unsigned int showAllFiles:1;
45 unsigned int canFreeFileTypes:1;
46 unsigned int fileMustExist:1;
47 } flags;
48 } W_FilePanel;
51 #define PWIDTH 320
52 #define PHEIGHT 360
54 static void listDirectoryOnColumn(WMFilePanel *panel, int column, char *path);
55 static void browserClick();
57 static void fillColumn(WMBrowser *bPtr, int column);
59 static void goHome();
61 static void buttonClick();
63 static char *getCurrentFileName(WMFilePanel *panel);
65 static int
66 closestListItem(WMList *list, char *text)
68 WMListItem *item = WMGetListItem(list, 0);
69 int i = 0;
70 int len = strlen(text);
72 if (len==0)
73 return -1;
75 while (item) {
76 if (strlen(item->text) >= len && strncmp(item->text, text, len)==0) {
77 return i;
79 item = item->nextPtr;
80 i++;
82 return -1;
86 static void
87 textChangedObserver(void *observerData, WMNotification *notification)
89 W_FilePanel *panel = (W_FilePanel*)observerData;
90 char *text;
91 WMList *list;
92 int col = WMGetBrowserNumberOfColumns(panel->browser) - 1;
93 int i;
95 list = WMGetBrowserListInColumn(panel->browser, col);
96 if (!list)
97 return;
98 text = WMGetTextFieldText(panel->fileField);
100 i = closestListItem(list, text);
101 WMSelectListItem(list, i);
102 if (i>=0)
103 WMSetListPosition(list, i);
105 free(text);
109 static void
110 textEditedObserver(void *observerData, WMNotification *notification)
112 W_FilePanel *panel = (W_FilePanel*)observerData;
114 if ((int)WMGetNotificationClientData(notification)==WMReturnTextMovement) {
115 WMPerformButtonClick(panel->okButton);
121 static WMFilePanel*
122 makeFilePanel(WMScreen *scrPtr, char *name, char *title)
124 WMFilePanel *fPtr;
125 WMFont *largeFont;
127 fPtr = wmalloc(sizeof(WMFilePanel));
128 memset(fPtr, 0, sizeof(WMFilePanel));
130 fPtr->win = WMCreateWindowWithStyle(scrPtr, name, WMTitledWindowMask
131 |WMResizableWindowMask);
132 WMResizeWidget(fPtr->win, PWIDTH, PHEIGHT);
133 WMSetWindowTitle(fPtr->win, "");
135 fPtr->iconLabel = WMCreateLabel(fPtr->win);
136 WMResizeWidget(fPtr->iconLabel, 64, 64);
137 WMMoveWidget(fPtr->iconLabel, 0, 0);
138 WMSetLabelImagePosition(fPtr->iconLabel, WIPImageOnly);
139 WMSetLabelImage(fPtr->iconLabel, scrPtr->applicationIcon);
141 fPtr->titleLabel = WMCreateLabel(fPtr->win);
142 WMResizeWidget(fPtr->titleLabel, PWIDTH-64, 64);
143 WMMoveWidget(fPtr->titleLabel, 64, 0);
144 largeFont = WMBoldSystemFontOfSize(scrPtr, 24);
145 WMSetLabelFont(fPtr->titleLabel, largeFont);
146 WMReleaseFont(largeFont);
147 WMSetLabelText(fPtr->titleLabel, title);
149 fPtr->line = WMCreateFrame(fPtr->win);
150 WMMoveWidget(fPtr->line, 0, 64);
151 WMResizeWidget(fPtr->line, PWIDTH, 2);
152 WMSetFrameRelief(fPtr->line, WRGroove);
154 fPtr->browser = WMCreateBrowser(fPtr->win);
155 WMSetBrowserFillColumnProc(fPtr->browser, fillColumn);
156 WMSetBrowserAction(fPtr->browser, browserClick, fPtr);
157 WMMoveWidget(fPtr->browser, 7, 72);
158 WMHangData(fPtr->browser, fPtr);
160 fPtr->nameLabel = WMCreateLabel(fPtr->win);
161 WMMoveWidget(fPtr->nameLabel, 7, 282);
162 WMResizeWidget(fPtr->nameLabel, 55, 14);
163 WMSetLabelText(fPtr->nameLabel, "Name:");
165 fPtr->fileField = WMCreateTextField(fPtr->win);
166 WMMoveWidget(fPtr->fileField, 60, 278);
167 WMResizeWidget(fPtr->fileField, PWIDTH-60-10, 24);
168 WMAddNotificationObserver(textEditedObserver, fPtr,
169 WMTextDidEndEditingNotification,
170 fPtr->fileField);
171 WMAddNotificationObserver(textChangedObserver, fPtr,
172 WMTextDidChangeNotification,
173 fPtr->fileField);
175 fPtr->okButton = WMCreateCommandButton(fPtr->win);
176 WMMoveWidget(fPtr->okButton, 230, 325);
177 WMResizeWidget(fPtr->okButton, 80, 28);
178 WMSetButtonText(fPtr->okButton, "OK");
179 WMSetButtonImage(fPtr->okButton, scrPtr->buttonArrow);
180 WMSetButtonAltImage(fPtr->okButton, scrPtr->pushedButtonArrow);
181 WMSetButtonImagePosition(fPtr->okButton, WIPRight);
182 WMSetButtonAction(fPtr->okButton, buttonClick, fPtr);
184 fPtr->cancelButton = WMCreateCommandButton(fPtr->win);
185 WMMoveWidget(fPtr->cancelButton, 140, 325);
186 WMResizeWidget(fPtr->cancelButton, 80, 28);
187 WMSetButtonText(fPtr->cancelButton, "Cancel");
188 WMSetButtonAction(fPtr->cancelButton, buttonClick, fPtr);
190 fPtr->homeButton = WMCreateCommandButton(fPtr->win);
191 WMMoveWidget(fPtr->homeButton, 55, 325);
192 WMResizeWidget(fPtr->homeButton, 28, 28);
193 WMSetButtonImagePosition(fPtr->homeButton, WIPImageOnly);
194 WMSetButtonImage(fPtr->homeButton, scrPtr->homeIcon);
195 WMSetButtonAction(fPtr->homeButton, goHome, fPtr);
197 WMRealizeWidget(fPtr->win);
198 WMMapSubwidgets(fPtr->win);
200 WMLoadBrowserColumnZero(fPtr->browser);
202 fPtr->flags.canChooseFiles = 1;
203 fPtr->flags.canChooseDirectories = 1;
205 return fPtr;
209 WMOpenPanel*
210 WMGetOpenPanel(WMScreen *scrPtr)
212 WMFilePanel *panel;
214 if (scrPtr->sharedOpenPanel)
215 return scrPtr->sharedOpenPanel;
217 panel = makeFilePanel(scrPtr, "openFilePanel", "Open");
218 panel->flags.fileMustExist = 1;
220 scrPtr->sharedOpenPanel = panel;
222 return panel;
226 WMSavePanel*
227 WMGetSavePanel(WMScreen *scrPtr)
229 WMFilePanel *panel;
231 if (scrPtr->sharedSavePanel)
232 return scrPtr->sharedSavePanel;
234 panel = makeFilePanel(scrPtr, "saveFilePanel", "Save");
235 panel->flags.fileMustExist = 0;
237 scrPtr->sharedSavePanel = panel;
239 return panel;
243 void
244 WMFreeFilePanel(WMFilePanel *panel)
246 if (panel == WMWidgetScreen(panel->win)->sharedSavePanel) {
247 WMWidgetScreen(panel->win)->sharedSavePanel = NULL;
249 if (panel == WMWidgetScreen(panel->win)->sharedOpenPanel) {
250 WMWidgetScreen(panel->win)->sharedOpenPanel = NULL;
252 WMRemoveNotificationObserver(panel);
253 WMUnmapWidget(panel->win);
254 WMDestroyWidget(panel->win);
255 free(panel);
260 WMRunModalSavePanelForDirectory(WMFilePanel *panel, WMWindow *owner,
261 char *path, char *name)
263 WMScreen *scr = WMWidgetScreen(panel->win);
264 XEvent event;
266 WMChangePanelOwner(panel->win, owner);
268 WMSetFilePanelDirectory(panel, path);
270 panel->flags.done = 0;
271 panel->fileTypes = NULL;
273 panel->flags.filtered = 0;
275 WMMapWidget(panel->win);
277 while (!panel->flags.done) {
278 WMNextEvent(scr->display, &event);
279 WMHandleEvent(&event);
282 WMCloseWindow(panel->win);
284 return (panel->flags.canceled ? False : True);
290 WMRunModalOpenPanelForDirectory(WMFilePanel *panel, WMWindow *owner,
291 char *path, char *name, char **fileTypes)
293 WMScreen *scr = WMWidgetScreen(panel->win);
294 XEvent event;
296 WMChangePanelOwner(panel->win, owner);
298 WMSetFilePanelDirectory(panel, path);
300 panel->flags.done = 0;
302 if (fileTypes)
303 panel->flags.filtered = 1;
304 panel->fileTypes = fileTypes;
306 WMMapWidget(panel->win);
308 while (!panel->flags.done) {
309 WMNextEvent(scr->display, &event);
310 WMHandleEvent(&event);
313 WMCloseWindow(panel->win);
315 return (panel->flags.canceled ? False : True);
319 void
320 WMSetFilePanelDirectory(WMFilePanel *panel, char *path)
322 WMList *list;
323 WMListItem *item;
324 int col;
326 WMSetBrowserPath(panel->browser, path);
327 col = WMGetBrowserNumberOfColumns(panel->browser) - 1;
328 list = WMGetBrowserListInColumn(panel->browser, col);
329 if (list && (item = WMGetListSelectedItem(list))) {
330 if (item->isBranch) {
331 WMSetTextFieldText(panel->fileField, NULL);
332 } else {
333 WMSetTextFieldText(panel->fileField, item->text);
335 } else {
336 WMSetTextFieldText(panel->fileField, path);
341 void
342 WMSetFilePanelCanChooseDirectories(WMFilePanel *panel, int flag)
344 panel->flags.canChooseDirectories = flag;
347 void
348 WMSetFilePanelCanChooseFiles(WMFilePanel *panel, int flag)
350 panel->flags.canChooseFiles = flag;
354 char*
355 WMGetFilePanelFileName(WMFilePanel *panel)
357 return getCurrentFileName(panel);
361 static char*
362 get_name_from_path(char *path)
364 int size;
366 assert(path!=NULL);
368 size = strlen(path);
370 /* remove trailing / */
371 while (size > 0 && path[size-1]=='/')
372 size--;
373 /* directory was root */
374 if (size == 0)
375 return wstrdup("/");
377 while (size > 0 && path[size-1] != '/')
378 size--;
380 return wstrdup(&(path[size]));
384 static int
385 filterFileName(WMFilePanel *panel, char *file, Bool isDirectory)
387 return True;
391 static void
392 listDirectoryOnColumn(WMFilePanel *panel, int column, char *path)
394 WMBrowser *bPtr = panel->browser;
395 struct dirent *dentry;
396 DIR *dir;
397 struct stat stat_buf;
398 char pbuf[PATH_MAX+16];
400 assert(column >= 0);
401 assert(path != NULL);
403 /* put directory name in the title */
404 WMSetBrowserColumnTitle(bPtr, column, get_name_from_path(path));
406 dir = opendir(path);
408 if (!dir) {
409 #ifdef VERBOSE
410 printf("WINGs: could not open directory %s\n", path);
411 #endif
412 return;
415 /* list contents in the column */
416 while ((dentry = readdir(dir))) {
417 if (strcmp(dentry->d_name, ".")==0 ||
418 strcmp(dentry->d_name, "..")==0)
419 continue;
421 strcpy(pbuf, path);
422 if (strcmp(path, "/")!=0)
423 strcat(pbuf, "/");
424 strcat(pbuf, dentry->d_name);
426 if (stat(pbuf, &stat_buf)!=0) {
427 #ifdef VERBOSE
428 printf("WINGs: could not stat %s\n", pbuf);
429 #endif
430 continue;
431 } else {
432 int isDirectory;
434 isDirectory = S_ISDIR(stat_buf.st_mode);
436 if (filterFileName(panel, dentry->d_name, isDirectory))
437 WMAddSortedBrowserItem(bPtr, column, dentry->d_name,
438 isDirectory);
442 closedir(dir);
446 static void
447 fillColumn(WMBrowser *bPtr, int column)
449 char *path;
450 WMFilePanel *panel;
452 if (column > 0) {
453 path = WMGetBrowserPathToColumn(bPtr, column-1);
454 } else {
455 path = wstrdup("/");
458 panel = WMGetHangedData(bPtr);
459 listDirectoryOnColumn(panel, column, path);
460 free(path);
465 static void
466 browserClick(WMBrowser *bPtr, WMFilePanel *panel)
468 int col = WMGetBrowserSelectedColumn(bPtr);
469 WMListItem *item = WMGetBrowserSelectedItemInColumn(bPtr, col);
471 if (!item || item->isBranch)
472 WMSetTextFieldText(panel->fileField, NULL);
473 else {
474 WMSetTextFieldText(panel->fileField, item->text);
479 static void
480 goHome(WMButton *bPtr, WMFilePanel *panel)
482 char *home;
484 /* home is statically allocated. Don't free it! */
485 home = wgethomedir();
486 if (!home)
487 return;
489 WMSetFilePanelDirectory(panel, home);
493 static char*
494 getCurrentFileName(WMFilePanel *panel)
496 char *path;
497 char *file;
498 char *tmp;
499 int len;
501 path = WMGetBrowserPath(panel->browser);
503 len = strlen(path);
504 if (path[len-1]=='/') {
505 file = WMGetTextFieldText(panel->fileField);
506 tmp = wmalloc(strlen(path)+strlen(file)+8);
507 if (file[0]!='/') {
508 strcpy(tmp, path);
509 strcat(tmp, file);
510 } else
511 strcpy(tmp, file);
513 free(file);
514 free(path);
515 return tmp;
516 } else {
517 return path;
523 static Bool
524 validOpenFile(WMFilePanel *panel)
526 WMListItem *item;
527 int col;
529 col = WMGetBrowserSelectedColumn(panel->browser);
530 item = WMGetBrowserSelectedItemInColumn(panel->browser, col);
531 if (item) {
532 if (item->isBranch && !panel->flags.canChooseDirectories)
533 return False;
534 else if (!item->isBranch && !panel->flags.canChooseFiles)
535 return False;
537 return True;
542 static void
543 buttonClick(WMButton *bPtr, WMFilePanel *panel)
545 if (bPtr == panel->okButton) {
546 if (panel->flags.fileMustExist) {
547 char *file;
548 if (!validOpenFile(panel))
549 return;
551 file = getCurrentFileName(panel);
552 if (access(file, F_OK)!=0) {
553 WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
554 "Error", "File does not exist.",
555 "Ok", NULL, NULL);
556 free(file);
557 return;
559 free(file);
561 panel->flags.canceled = 0;
562 } else
563 panel->flags.canceled = 1;
565 panel->flags.done = 1;