Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wfilepanel.c
Commit [+]AuthorDateLineData
9d2e6ef9 scottc1998-09-29 22:36:29 +00001
9d2e6ef9 scottc1998-09-29 22:36:29 +00002#include "WINGsP.h"
882b9a8e kojima2001-07-23 20:31:32 +00003#include "wconfig.h"
9d2e6ef9 scottc1998-09-29 22:36:29 +00004
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <unistd.h>
8#include <dirent.h>
9#include <limits.h>
2958e72f id1999-06-03 00:49:16 +000010#include <errno.h>
06f59b99 Carlos R. Mafra2008-11-06 01:37:44 +010011#include <stdint.h>
9d2e6ef9 scottc1998-09-29 22:36:29 +000012
13#ifndef PATH_MAX
14#define PATH_MAX 1024
15#endif
16
17typedef struct W_FilePanel {
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020018 WMWindow *win;
6830b057 dan2004-10-12 21:28:27 +000019
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020020 WMLabel *iconLabel;
21 WMLabel *titleLabel;
6830b057 dan2004-10-12 21:28:27 +000022
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020023 WMFrame *line;
9d2e6ef9 scottc1998-09-29 22:36:29 +000024
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020025 WMLabel *nameLabel;
26 WMBrowser *browser;
6830b057 dan2004-10-12 21:28:27 +000027
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020028 WMButton *okButton;
29 WMButton *cancelButton;
6830b057 dan2004-10-12 21:28:27 +000030
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020031 WMButton *homeButton;
32 WMButton *trashcanButton;
33 WMButton *createDirButton;
34 WMButton *disketteButton;
35 WMButton *unmountButton;
9d2e6ef9 scottc1998-09-29 22:36:29 +000036
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020037 WMView *accessoryView;
0261c326 dan1999-01-06 15:22:33 +000038
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020039 WMTextField *fileField;
6830b057 dan2004-10-12 21:28:27 +000040
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020041 char **fileTypes;
9d2e6ef9 scottc1998-09-29 22:36:29 +000042
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020043 struct {
44 unsigned int canExit:1;
45 unsigned int canceled:1; /* clicked on cancel */
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;
9d2e6ef9 scottc1998-09-29 22:36:29 +000055} W_FilePanel;
56
e7495baf dan1999-02-17 11:06:40 +000057/* Type of panel */
58#define WP_OPEN 0
59#define WP_SAVE 1
60
f1fff318 id1999-06-06 13:53:19 +000061#define PWIDTH 330
9d2e6ef9 scottc1998-09-29 22:36:29 +000062#define PHEIGHT 360
63
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020064static void listDirectoryOnColumn(WMFilePanel * panel, int column, char *path);
9d2e6ef9 scottc1998-09-29 22:36:29 +000065static void browserClick();
e7495baf dan1999-02-17 11:06:40 +000066static void browserDClick();
9d2e6ef9 scottc1998-09-29 22:36:29 +000067
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020068static void fillColumn(WMBrowserDelegate * self, WMBrowser * bPtr, int column, WMList * list);
9d2e6ef9 scottc1998-09-29 22:36:29 +000069
ba527927 id1999-06-03 00:24:03 +000070static void deleteFile();
71
f1fff318 id1999-06-06 13:53:19 +000072static void createDir();
73
9d2e6ef9 scottc1998-09-29 22:36:29 +000074static void goHome();
75
3c503eac id1999-06-03 10:48:13 +000076static void goFloppy();
77
7cc53d51 id1999-06-09 20:22:44 +000078static void goUnmount();
f1fff318 id1999-06-06 13:53:19 +000079
9d2e6ef9 scottc1998-09-29 22:36:29 +000080static void buttonClick();
81
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020082static char *getCurrentFileName(WMFilePanel * panel);
931a37b1 dan1999-01-29 08:11:17 +000083
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020084static void handleEvents(XEvent * event, void *data);
dd2d71fc kojima1999-05-15 17:38:05 +000085
86static WMBrowserDelegate browserDelegate = {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020087 NULL, /* data */
88 fillColumn, /* createRowsForColumn */
89 NULL, /* titleOfColumn */
90 NULL, /* didScroll */
91 NULL /* willScroll */
dd2d71fc kojima1999-05-15 17:38:05 +000092};
93
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020094static int closestListItem(WMList * list, char *text, Bool exact)
9d2e6ef9 scottc1998-09-29 22:36:29 +000095{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020096 WMListItem *item;
97 WMArray *items = WMGetListItems(list);
98 int i, len = strlen(text);
9d2e6ef9 scottc1998-09-29 22:36:29 +000099
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200100 if (len == 0)
101 return -1;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000102
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200103 for (i = 0; i < WMGetArrayItemCount(items); i++) {
104 item = WMGetFromArray(items, i);
105 if (strlen(item->text) >= len &&
106 ((exact && strcmp(item->text, text) == 0) ||
107 (!exact && strncmp(item->text, text, len) == 0))) {
108 return i;
109 }
110 }
e82c30b2 kojima1999-10-03 03:47:21 +0000111
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200112 return -1;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000113}
114
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200115static void textChangedObserver(void *observerData, WMNotification * notification)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000116{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200117 W_FilePanel *panel = (W_FilePanel *) observerData;
118 char *text;
119 WMList *list;
120 int col = WMGetBrowserNumberOfColumns(panel->browser) - 1;
121 int i, textEvent;
931a37b1 dan1999-01-29 08:11:17 +0000122
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200123 if (!(list = WMGetBrowserListInColumn(panel->browser, col)))
124 return;
6830b057 dan2004-10-12 21:28:27 +0000125
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200126 text = WMGetTextFieldText(panel->fileField);
127 textEvent = (int)(uintptr_t) WMGetNotificationClientData(notification);
128
129 if (panel->flags.autoCompletion && textEvent != WMDeleteTextEvent)
130 i = closestListItem(list, text, False);
131 else
132 i = closestListItem(list, text, True);
133
134 WMSelectListItem(list, i);
135 if (i >= 0 && panel->flags.autoCompletion) {
136 WMListItem *item = WMGetListItem(list, i);
137 int textLen = strlen(text), itemTextLen = strlen(item->text);
138 int visibleItems = WMWidgetHeight(list) / WMGetListItemHeight(list);
139
140 WMSetListPosition(list, i - visibleItems / 2);
141
142 if (textEvent != WMDeleteTextEvent) {
143 WMRange range;
144
145 WMInsertTextFieldText(panel->fileField, &item->text[textLen], textLen);
146 range.position = textLen;
147 range.count = itemTextLen - textLen;
148 WMSelectTextFieldRange(panel->fileField, range);
149 /*WMSetTextFieldCursorPosition(panel->fileField, itemTextLen); */
150 }
151 }
152
153 wfree(text);
154}
155
156static void textEditedObserver(void *observerData, WMNotification * notification)
157{
158 W_FilePanel *panel = (W_FilePanel *) observerData;
159
160 if ((int)(uintptr_t) WMGetNotificationClientData(notification) == WMReturnTextMovement) {
161 WMPerformButtonClick(panel->okButton);
162 }
163}
164
165static WMFilePanel *makeFilePanel(WMScreen * scrPtr, char *name, char *title)
166{
167 WMFilePanel *fPtr;
168 WMFont *largeFont;
169 WMPixmap *icon;
170
171 fPtr = wmalloc(sizeof(WMFilePanel));
172 memset(fPtr, 0, sizeof(WMFilePanel));
173
174 fPtr->win = WMCreateWindowWithStyle(scrPtr, name, WMTitledWindowMask | WMResizableWindowMask);
175 WMResizeWidget(fPtr->win, PWIDTH, PHEIGHT);
176 WMSetWindowTitle(fPtr->win, "");
177
178 WMCreateEventHandler(WMWidgetView(fPtr->win), StructureNotifyMask, handleEvents, fPtr);
179 WMSetWindowMinSize(fPtr->win, PWIDTH, PHEIGHT);
180
181 fPtr->iconLabel = WMCreateLabel(fPtr->win);
182 WMResizeWidget(fPtr->iconLabel, 64, 64);
183 WMMoveWidget(fPtr->iconLabel, 0, 0);
184 WMSetLabelImagePosition(fPtr->iconLabel, WIPImageOnly);
185 icon = WMCreateApplicationIconBlendedPixmap(scrPtr, (RColor *) NULL);
186 if (icon) {
187 WMSetLabelImage(fPtr->iconLabel, icon);
188 WMReleasePixmap(icon);
189 } else {
190 WMSetLabelImage(fPtr->iconLabel, scrPtr->applicationIconPixmap);
191 }
192
193 fPtr->titleLabel = WMCreateLabel(fPtr->win);
194 WMResizeWidget(fPtr->titleLabel, PWIDTH - 64, 64);
195 WMMoveWidget(fPtr->titleLabel, 64, 0);
196 largeFont = WMBoldSystemFontOfSize(scrPtr, 24);
197 WMSetLabelFont(fPtr->titleLabel, largeFont);
198 WMReleaseFont(largeFont);
199 WMSetLabelText(fPtr->titleLabel, title);
200
201 fPtr->line = WMCreateFrame(fPtr->win);
202 WMMoveWidget(fPtr->line, 0, 64);
203 WMResizeWidget(fPtr->line, PWIDTH, 2);
204 WMSetFrameRelief(fPtr->line, WRGroove);
205
206 fPtr->browser = WMCreateBrowser(fPtr->win);
207 WMSetBrowserAllowEmptySelection(fPtr->browser, True);
208 WMSetBrowserDelegate(fPtr->browser, &browserDelegate);
209 WMSetBrowserAction(fPtr->browser, browserClick, fPtr);
210 WMSetBrowserDoubleAction(fPtr->browser, browserDClick, fPtr);
211 WMMoveWidget(fPtr->browser, 7, 72);
212 WMResizeWidget(fPtr->browser, PWIDTH - 14, 200);
213 WMHangData(fPtr->browser, fPtr);
214
215 fPtr->nameLabel = WMCreateLabel(fPtr->win);
216 WMMoveWidget(fPtr->nameLabel, 7, 282);
217 WMResizeWidget(fPtr->nameLabel, 55, 14);
218 WMSetLabelText(fPtr->nameLabel, _("Name:"));
219
220 fPtr->fileField = WMCreateTextField(fPtr->win);
221 WMMoveWidget(fPtr->fileField, 60, 278);
222 WMResizeWidget(fPtr->fileField, PWIDTH - 60 - 10, 24);
223 WMAddNotificationObserver(textEditedObserver, fPtr, WMTextDidEndEditingNotification, fPtr->fileField);
224 WMAddNotificationObserver(textChangedObserver, fPtr, WMTextDidChangeNotification, fPtr->fileField);
225
226 fPtr->okButton = WMCreateCommandButton(fPtr->win);
227 WMMoveWidget(fPtr->okButton, 245, 325);
228 WMResizeWidget(fPtr->okButton, 75, 28);
229 WMSetButtonText(fPtr->okButton, _("OK"));
230 WMSetButtonImage(fPtr->okButton, scrPtr->buttonArrow);
231 WMSetButtonAltImage(fPtr->okButton, scrPtr->pushedButtonArrow);
232 WMSetButtonImagePosition(fPtr->okButton, WIPRight);
233 WMSetButtonAction(fPtr->okButton, buttonClick, fPtr);
6830b057 dan2004-10-12 21:28:27 +0000234
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200235 fPtr->cancelButton = WMCreateCommandButton(fPtr->win);
236 WMMoveWidget(fPtr->cancelButton, 165, 325);
237 WMResizeWidget(fPtr->cancelButton, 75, 28);
238 WMSetButtonText(fPtr->cancelButton, _("Cancel"));
239 WMSetButtonAction(fPtr->cancelButton, buttonClick, fPtr);
240
241 fPtr->trashcanButton = WMCreateCommandButton(fPtr->win);
242 WMMoveWidget(fPtr->trashcanButton, 7, 325);
243 WMResizeWidget(fPtr->trashcanButton, 28, 28);
244 WMSetButtonImagePosition(fPtr->trashcanButton, WIPImageOnly);
245 WMSetButtonImage(fPtr->trashcanButton, scrPtr->trashcanIcon);
246 WMSetButtonAltImage(fPtr->trashcanButton, scrPtr->altTrashcanIcon);
247 WMSetButtonAction(fPtr->trashcanButton, deleteFile, fPtr);
ea5d3bcd dan1999-03-10 15:47:10 +0000248
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200249 fPtr->createDirButton = WMCreateCommandButton(fPtr->win);
250 WMMoveWidget(fPtr->createDirButton, 37, 325);
251 WMResizeWidget(fPtr->createDirButton, 28, 28);
252 WMSetButtonImagePosition(fPtr->createDirButton, WIPImageOnly);
253 WMSetButtonImage(fPtr->createDirButton, scrPtr->createDirIcon);
254 WMSetButtonAltImage(fPtr->createDirButton, scrPtr->altCreateDirIcon);
255 WMSetButtonAction(fPtr->createDirButton, createDir, fPtr);
256
257 fPtr->homeButton = WMCreateCommandButton(fPtr->win);
258 WMMoveWidget(fPtr->homeButton, 67, 325);
259 WMResizeWidget(fPtr->homeButton, 28, 28);
260 WMSetButtonImagePosition(fPtr->homeButton, WIPImageOnly);
261 WMSetButtonImage(fPtr->homeButton, scrPtr->homeIcon);
262 WMSetButtonAltImage(fPtr->homeButton, scrPtr->altHomeIcon);
263 WMSetButtonAction(fPtr->homeButton, goHome, fPtr);
264
265 fPtr->disketteButton = WMCreateCommandButton(fPtr->win);
266 WMMoveWidget(fPtr->disketteButton, 97, 325);
267 WMResizeWidget(fPtr->disketteButton, 28, 28);
268 WMSetButtonImagePosition(fPtr->disketteButton, WIPImageOnly);
269 WMSetButtonImage(fPtr->disketteButton, scrPtr->disketteIcon);
270 WMSetButtonAltImage(fPtr->disketteButton, scrPtr->altDisketteIcon);
271 WMSetButtonAction(fPtr->disketteButton, goFloppy, fPtr);
272
273 fPtr->unmountButton = WMCreateCommandButton(fPtr->win);
274 WMMoveWidget(fPtr->unmountButton, 127, 325);
275 WMResizeWidget(fPtr->unmountButton, 28, 28);
276 WMSetButtonImagePosition(fPtr->unmountButton, WIPImageOnly);
277 WMSetButtonImage(fPtr->unmountButton, scrPtr->unmountIcon);
278 WMSetButtonAltImage(fPtr->unmountButton, scrPtr->altUnmountIcon);
279 WMSetButtonAction(fPtr->unmountButton, goUnmount, fPtr);
280 WMSetButtonEnabled(fPtr->unmountButton, False);
281
282 WMRealizeWidget(fPtr->win);
283 WMMapSubwidgets(fPtr->win);
284
285 WMSetFocusToWidget(fPtr->fileField);
286 WMSetTextFieldCursorPosition(fPtr->fileField, 0);
287
288 WMLoadBrowserColumnZero(fPtr->browser);
289
290 WMSetWindowInitialPosition(fPtr->win,
291 (scrPtr->rootView->size.width - WMWidgetWidth(fPtr->win)) / 2,
292 (scrPtr->rootView->size.height - WMWidgetHeight(fPtr->win)) / 2);
293
294 fPtr->flags.canChooseFiles = 1;
295 fPtr->flags.canChooseDirectories = 1;
296 fPtr->flags.autoCompletion = 1;
297
298 return fPtr;
299}
9d2e6ef9 scottc1998-09-29 22:36:29 +0000300
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200301WMOpenPanel *WMGetOpenPanel(WMScreen * scrPtr)
302{
303 WMFilePanel *panel;
f1fff318 id1999-06-06 13:53:19 +0000304
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200305 if (scrPtr->sharedOpenPanel)
306 return scrPtr->sharedOpenPanel;
307
308 panel = makeFilePanel(scrPtr, "openFilePanel", _("Open"));
309 panel->flags.fileMustExist = 1;
310 panel->flags.panelType = WP_OPEN;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000311
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200312 scrPtr->sharedOpenPanel = panel;
e7495baf dan1999-02-17 11:06:40 +0000313
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200314 return panel;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000315}
316
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200317WMSavePanel *WMGetSavePanel(WMScreen * scrPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000318{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200319 WMFilePanel *panel;
6830b057 dan2004-10-12 21:28:27 +0000320
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200321 if (scrPtr->sharedSavePanel)
322 return scrPtr->sharedSavePanel;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000323
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200324 panel = makeFilePanel(scrPtr, "saveFilePanel", _("Save"));
325 panel->flags.fileMustExist = 0;
326 panel->flags.panelType = WP_SAVE;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000327
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200328 scrPtr->sharedSavePanel = panel;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000329
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200330 return panel;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000331}
332
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200333void WMFreeFilePanel(WMFilePanel * panel)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000334{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200335 if (panel == WMWidgetScreen(panel->win)->sharedSavePanel) {
336 WMWidgetScreen(panel->win)->sharedSavePanel = NULL;
337 }
338 if (panel == WMWidgetScreen(panel->win)->sharedOpenPanel) {
339 WMWidgetScreen(panel->win)->sharedOpenPanel = NULL;
340 }
341 WMRemoveNotificationObserver(panel);
342 WMUnmapWidget(panel->win);
343 WMDestroyWidget(panel->win);
344 wfree(panel);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000345}
346
9d2e6ef9 scottc1998-09-29 22:36:29 +0000347int
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200348WMRunModalFilePanelForDirectory(WMFilePanel * panel, WMWindow * owner, char *path, char *name, char **fileTypes)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000349{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200350 WMScreen *scr = WMWidgetScreen(panel->win);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000351
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200352 if (name && !owner) {
353 WMSetWindowTitle(panel->win, name);
354 }
e7495baf dan1999-02-17 11:06:40 +0000355
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200356 WMChangePanelOwner(panel->win, owner);
088c0ac2 dan1999-03-09 14:58:01 +0000357
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200358 WMSetFilePanelDirectory(panel, path);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000359
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200360 switch (panel->flags.panelType) {
361 case WP_OPEN:
362 if (fileTypes)
363 panel->flags.filtered = 1;
364 panel->fileTypes = fileTypes;
365 if (name == NULL)
366 name = _("Open");
367 break;
368 case WP_SAVE:
369 panel->fileTypes = NULL;
370 panel->flags.filtered = 0;
371 if (name == NULL)
372 name = _("Save");
373 break;
374 default:
375 break;
376 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000377
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200378 WMSetLabelText(panel->titleLabel, name);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000379
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200380 WMMapWidget(panel->win);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000381
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200382 WMRunModalLoop(scr, W_VIEW(panel->win));
9d2e6ef9 scottc1998-09-29 22:36:29 +0000383
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200384 /* Must withdraw window because the next time we map
385 * it, it might have a different transient owner.
386 */
387 WMCloseWindow(panel->win);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000388
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200389 return (panel->flags.canceled ? False : True);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000390}
391
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200392void WMSetFilePanelDirectory(WMFilePanel * panel, char *path)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000393{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200394 WMList *list;
395 WMListItem *item;
396 int col;
397 char *rest;
e7495baf dan1999-02-17 11:06:40 +0000398
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200399 rest = WMSetBrowserPath(panel->browser, path);
400 if (strcmp(path, "/") == 0)
401 rest = NULL;
e7495baf dan1999-02-17 11:06:40 +0000402
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200403 col = WMGetBrowserSelectedColumn(panel->browser);
404 list = WMGetBrowserListInColumn(panel->browser, col);
405 if (list && (item = WMGetListSelectedItem(list))) {
406 if (item->isBranch) {
407 WMSetTextFieldText(panel->fileField, rest);
408 } else {
409 WMSetTextFieldText(panel->fileField, item->text);
410 }
411 } else {
412 WMSetTextFieldText(panel->fileField, rest);
413 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000414}
415
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200416void WMSetFilePanelCanChooseDirectories(WMFilePanel * panel, Bool flag)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000417{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200418 panel->flags.canChooseDirectories = ((flag == 0) ? 0 : 1);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000419}
420
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200421void WMSetFilePanelCanChooseFiles(WMFilePanel * panel, Bool flag)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000422{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200423 panel->flags.canChooseFiles = ((flag == 0) ? 0 : 1);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000424}
425
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200426void WMSetFilePanelAutoCompletion(WMFilePanel * panel, Bool flag)
931a37b1 dan1999-01-29 08:11:17 +0000427{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200428 panel->flags.autoCompletion = ((flag == 0) ? 0 : 1);
931a37b1 dan1999-01-29 08:11:17 +0000429}
430
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200431char *WMGetFilePanelFileName(WMFilePanel * panel)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000432{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200433 return getCurrentFileName(panel);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000434}
435
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200436void WMSetFilePanelAccessoryView(WMFilePanel * panel, WMView * view)
0261c326 dan1999-01-06 15:22:33 +0000437{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200438 WMView *v;
0261c326 dan1999-01-06 15:22:33 +0000439
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200440 panel->accessoryView = view;
0261c326 dan1999-01-06 15:22:33 +0000441
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200442 v = WMWidgetView(panel->win);
0261c326 dan1999-01-06 15:22:33 +0000443
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200444 W_ReparentView(view, v, 0, 0);
0261c326 dan1999-01-06 15:22:33 +0000445
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200446 W_MoveView(view, (v->size.width - v->size.width) / 2, 300);
0261c326 dan1999-01-06 15:22:33 +0000447}
448
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200449WMView *WMGetFilePanelAccessoryView(WMFilePanel * panel)
0261c326 dan1999-01-06 15:22:33 +0000450{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200451 return panel->accessoryView;
0261c326 dan1999-01-06 15:22:33 +0000452}
453
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200454static char *get_name_from_path(char *path)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000455{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200456 int size;
6830b057 dan2004-10-12 21:28:27 +0000457
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200458 assert(path != NULL);
6830b057 dan2004-10-12 21:28:27 +0000459
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200460 size = strlen(path);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000461
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200462 /* remove trailing / */
463 while (size > 0 && path[size - 1] == '/')
464 size--;
465 /* directory was root */
466 if (size == 0)
467 return wstrdup("/");
9d2e6ef9 scottc1998-09-29 22:36:29 +0000468
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200469 while (size > 0 && path[size - 1] != '/')
470 size--;
6830b057 dan2004-10-12 21:28:27 +0000471
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200472 return wstrdup(&(path[size]));
9d2e6ef9 scottc1998-09-29 22:36:29 +0000473}
474
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200475static int filterFileName(WMFilePanel * panel, char *file, Bool isDirectory)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000476{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200477 return True;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000478}
479
94f4483d kojima1999-10-27 22:32:12 +0000480#define CAST(item) (*((WMListItem**)item))
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200481static int comparer(const void *a, const void *b)
94f4483d kojima1999-10-27 22:32:12 +0000482{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200483 if (CAST(a)->isBranch == CAST(b)->isBranch)
484 return (strcmp(CAST(a)->text, CAST(b)->text));
485 if (CAST(a)->isBranch)
486 return (-1);
487 return (1);
94f4483d kojima1999-10-27 22:32:12 +0000488}
94f4483d kojima1999-10-27 22:32:12 +0000489
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200490#undef CAST
94f4483d kojima1999-10-27 22:32:12 +0000491
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200492static void listDirectoryOnColumn(WMFilePanel * panel, int column, char *path)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000493{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200494 WMBrowser *bPtr = panel->browser;
495 struct dirent *dentry;
496 DIR *dir;
497 struct stat stat_buf;
498 char pbuf[PATH_MAX + 16];
499 char *name;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000500
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200501 assert(column >= 0);
502 assert(path != NULL);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000503
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200504 /* put directory name in the title */
505 name = get_name_from_path(path);
506 WMSetBrowserColumnTitle(bPtr, column, name);
507 wfree(name);
6830b057 dan2004-10-12 21:28:27 +0000508
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200509 dir = opendir(path);
6830b057 dan2004-10-12 21:28:27 +0000510
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200511 if (!dir) {
9d2e6ef9 scottc1998-09-29 22:36:29 +0000512#ifdef VERBOSE
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200513 printf(_("WINGs: could not open directory %s\n"), path);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000514#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200515 return;
516 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000517
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200518 /* list contents in the column */
519 while ((dentry = readdir(dir))) {
520 if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
521 continue;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000522
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200523 strcpy(pbuf, path);
524 if (strcmp(path, "/") != 0)
525 strcat(pbuf, "/");
526 strcat(pbuf, dentry->d_name);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000527
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200528 if (stat(pbuf, &stat_buf) != 0) {
9d2e6ef9 scottc1998-09-29 22:36:29 +0000529#ifdef VERBOSE
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200530 printf(_("WINGs: could not stat %s\n"), pbuf);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000531#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200532 continue;
533 } else {
534 int isDirectory;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000535
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200536 isDirectory = S_ISDIR(stat_buf.st_mode);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000537
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200538 if (filterFileName(panel, dentry->d_name, isDirectory))
539 WMInsertBrowserItem(bPtr, column, -1, dentry->d_name, isDirectory);
540 }
541 }
542 WMSortBrowserColumnWithComparer(bPtr, column, comparer);
543
544 closedir(dir);
545}
546
547static void fillColumn(WMBrowserDelegate * self, WMBrowser * bPtr, int column, WMList * list)
548{
549 char *path;
550 WMFilePanel *panel;
551
552 if (column > 0) {
553 path = WMGetBrowserPathToColumn(bPtr, column - 1);
554 } else {
555 path = wstrdup("/");
556 }
e7495baf dan1999-02-17 11:06:40 +0000557
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200558 panel = WMGetHangedData(bPtr);
559 listDirectoryOnColumn(panel, column, path);
560 wfree(path);
e7495baf dan1999-02-17 11:06:40 +0000561}
562
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200563static void browserDClick(WMBrowser * bPtr, WMFilePanel * panel)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000564{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200565 WMPerformButtonClick(panel->okButton);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000566}
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200567
568static void browserClick(WMBrowser * bPtr, WMFilePanel * panel)
569{
570 int col = WMGetBrowserSelectedColumn(bPtr);
571 WMListItem *item = WMGetBrowserSelectedItemInColumn(bPtr, col);
572
573 if (!item || item->isBranch)
574 WMSetTextFieldText(panel->fileField, NULL);
575 else {
576 WMSetTextFieldText(panel->fileField, item->text);
577 }
578}
579
580static void showError(WMScreen * scr, WMWindow * owner, char *s, char *file)
581{
582 char *errStr;
583
584 if (file) {
585 errStr = wmalloc(strlen(file) + strlen(s));
586 sprintf(errStr, s, file);
587 } else {
588 errStr = wstrdup(s);
589 }
590 WMRunAlertPanel(scr, owner, _("Error"), errStr, _("OK"), NULL, NULL);
591 wfree(errStr);
592}
593
594static void createDir(WMButton * bPre, WMFilePanel * panel)
595{
596 char *dirName, *directory, *file, *s;
597 WMScreen *scr = WMWidgetScreen(panel->win);
598
599 dirName = WMRunInputPanel(scr, panel->win, _("Create Directory"),
600 _("Enter directory name"), "", _("OK"), _("Cancel"));
601 if (!dirName)
602 return;
603
604 directory = getCurrentFileName(panel);
605 s = strrchr(directory, '/');
606 if (s)
607 s[1] = 0;
608
609 if (dirName[0] == '/') {
610 directory[0] = 0;
611 } else {
612 while ((s = strstr(directory, "//"))) {
613 int i;
614 for (i = 2; s[i] == '/'; i++) ;
615 strcpy(s, &s[i - 1]);
616 }
617 if ((s = strrchr(directory, '/')) && !s[1])
618 s[0] = 0;
619 }
620 while ((s = strstr(dirName, "//"))) {
621 int i;
622 for (i = 2; s[i] == '/'; i++) ;
623 strcpy(s, &s[i - 1]);
624 }
625 if ((s = strrchr(dirName, '/')) && !s[1])
626 s[0] = 0;
627
628 file = wmalloc(strlen(dirName) + strlen(directory) + 4);
629 sprintf(file, "%s/%s", directory, dirName);
630 while ((s = strstr(file, "//"))) {
631 int i;
632 for (i = 2; s[i] == '/'; i++) ;
633 strcpy(s, &s[i - 1]);
634 }
635
636 if (mkdir(file, 0xfff) != 0) {
637 switch (errno) {
638 case EACCES:
639 showError(scr, panel->win, _("Permission denied."), NULL);
640 break;
641 case EEXIST:
642 showError(scr, panel->win, _("'%s' already exists."), file);
643 break;
644 case ENOENT:
645 showError(scr, panel->win, _("Path does not exist."), NULL);
646 }
647 } else
648 WMSetFilePanelDirectory(panel, file);
649
650 wfree(dirName);
651 wfree(directory);
652 wfree(file);
653}
654
655static void deleteFile(WMButton * bPre, WMFilePanel * panel)
656{
657 char *file;
658 char *buffer, *s;
659 struct stat filestat;
660 WMScreen *scr = WMWidgetScreen(panel->win);
661
662 file = getCurrentFileName(panel);
663
664 while ((s = strstr(file, "//"))) {
665 int i;
666 for (i = 2; s[i] == '/'; i++) ;
667 strcpy(s, &s[i - 1]);
668 }
669 if (strlen(file) > 1 && (s = strrchr(file, '/')) && !s[1])
670 s[0] = 0;
671
672 if (stat(file, &filestat)) {
673 switch (errno) {
674 case ENOENT:
675 showError(scr, panel->win, _("'%s' does not exist."), file);
676 break;
677 case EACCES:
678 showError(scr, panel->win, _("Permission denied."), NULL);
679 break;
680 case ENOMEM:
681 showError(scr, panel->win, _("Insufficient memory available."), NULL);
682 break;
683 case EROFS:
684 showError(scr, panel->win, _("'%s' is on a read-only filesystem."), file);
685 break;
686 default:
687 showError(scr, panel->win, _("Can not delete '%s'."), file);
688 }
689 wfree(file);
690 return;
691 } else if (S_ISDIR(filestat.st_mode)) {
692 int len = strlen(file) + 20;
693 buffer = wmalloc(len);
694 snprintf(buffer, len, _("Delete directory %s ?"), file);
695 } else {
696 int len = strlen(file) + 15;
697 buffer = wmalloc(len);
698 snprintf(buffer, len, _("Delete file %s ?"), file);
699 }
700
701 if (!WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
702 _("Warning"), buffer, _("OK"), _("Cancel"), NULL)) {
703 if (S_ISDIR(filestat.st_mode)) {
704 if (rmdir(file) != 0) {
705 switch (errno) {
706 case EACCES:
707 showError(scr, panel->win, _("Permission denied."), NULL);
708 break;
709 case ENOENT:
710 showError(scr, panel->win, _("Directory '%s' does not exist."), file);
711 break;
712 case ENOTEMPTY:
713 showError(scr, panel->win, _("Directory '%s' is not empty."), file);
714 break;
715 case EBUSY:
716 showError(scr, panel->win, _("Directory '%s' is busy."), file);
717 break;
718 default:
719 showError(scr, panel->win, _("Can not delete '%s'."), file);
720 }
721 } else {
722 char *s = strrchr(file, '/');
723 if (s)
724 s[0] = 0;
725 WMSetFilePanelDirectory(panel, file);
726 }
727 } else if (remove(file) != 0) {
728 switch (errno) {
729 case EISDIR:
730 showError(scr, panel->win, _("'%s' is a directory."), file);
731 break;
732 case ENOENT:
733 showError(scr, panel->win, _("'%s' does not exist."), file);
734 break;
735 case EACCES:
736 showError(scr, panel->win, _("Permission denied."), NULL);
737 break;
738 case ENOMEM:
739 showError(scr, panel->win, _("Insufficient memory available."), NULL);
740 break;
741 case EROFS:
742 showError(scr, panel->win, _("'%s' is on a read-only filesystem."), file);
743 break;
744 default:
745 showError(scr, panel->win, _("Can not delete '%s'."), file);
746 }
747 } else {
748 char *s = strrchr(file, '/');
749 if (s)
750 s[1] = 0;
751 WMSetFilePanelDirectory(panel, file);
752 }
753 }
754 wfree(buffer);
755 wfree(file);
756}
757
758static void goUnmount(WMButton * bPtr, WMFilePanel * panel)
759{
760}
761
762static void goFloppy(WMButton * bPtr, WMFilePanel * panel)
763{
764 struct stat filestat;
765 WMScreen *scr = WMWidgetScreen(panel->win);
766
767 if (stat(WINGsConfiguration.floppyPath, &filestat)) {
768 showError(scr, panel->win, _("An error occured browsing '%s'."), WINGsConfiguration.floppyPath);
769 return;
770 } else if (!S_ISDIR(filestat.st_mode)) {
771 showError(scr, panel->win, _("'%s' is not a directory."), WINGsConfiguration.floppyPath);
772 return;
773 }
774
775 WMSetFilePanelDirectory(panel, WINGsConfiguration.floppyPath);
776}
777
778static void goHome(WMButton * bPtr, WMFilePanel * panel)
779{
780 char *home;
781
782 /* home is statically allocated. Don't free it! */
783 home = wgethomedir();
784 if (!home)
785 return;
786
787 WMSetFilePanelDirectory(panel, home);
788}
789
790static void handleEvents(XEvent * event, void *data)
791{
792 W_FilePanel *pPtr = (W_FilePanel *) data;
793 W_View *view = WMWidgetView(pPtr->win);
794
795 if (event->type == ConfigureNotify) {
796 if (event->xconfigure.width != view->size.width || event->xconfigure.height != view->size.height) {
797 unsigned int newWidth = event->xconfigure.width;
798 unsigned int newHeight = event->xconfigure.height;
799 int newColumnCount;
800
801 W_ResizeView(view, newWidth, newHeight);
802 WMResizeWidget(pPtr->line, newWidth, 2);
803 WMResizeWidget(pPtr->browser, newWidth - 14, newHeight - (PHEIGHT - 200));
804 WMResizeWidget(pPtr->fileField, newWidth - 60 - 10, 24);
805 WMMoveWidget(pPtr->nameLabel, 7, newHeight - (PHEIGHT - 282));
806 WMMoveWidget(pPtr->fileField, 60, newHeight - (PHEIGHT - 278));
807 WMMoveWidget(pPtr->okButton, newWidth - (PWIDTH - 245), newHeight - (PHEIGHT - 325));
808 WMMoveWidget(pPtr->cancelButton, newWidth - (PWIDTH - 165), newHeight - (PHEIGHT - 325));
809
810 WMMoveWidget(pPtr->trashcanButton, 7, newHeight - (PHEIGHT - 325));
811 WMMoveWidget(pPtr->createDirButton, 37, newHeight - (PHEIGHT - 325));
812 WMMoveWidget(pPtr->homeButton, 67, newHeight - (PHEIGHT - 325));
813 WMMoveWidget(pPtr->disketteButton, 97, newHeight - (PHEIGHT - 325));
814 WMMoveWidget(pPtr->unmountButton, 127, newHeight - (PHEIGHT - 325));
815
816 newColumnCount = (newWidth - 14) / 140;
817 WMSetBrowserMaxVisibleColumns(pPtr->browser, newColumnCount);
818 }
819 }
820}
821
822static char *getCurrentFileName(WMFilePanel * panel)
823{
824 char *path;
825 char *file;
826 char *tmp;
827 int len;
828
829 path = WMGetBrowserPath(panel->browser);
830
831 len = strlen(path);
832 if (path[len - 1] == '/') {
833 file = WMGetTextFieldText(panel->fileField);
834 tmp = wmalloc(strlen(path) + strlen(file) + 8);
835 if (file[0] != '/') {
836 strcpy(tmp, path);
837 strcat(tmp, file);
838 } else
839 strcpy(tmp, file);
840
841 wfree(file);
842 wfree(path);
843 return tmp;
844 } else {
845 return path;
846 }
847}
848
849static Bool validOpenFile(WMFilePanel * panel)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000850{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200851 WMListItem *item;
852 int col, haveFile = 0;
853 char *file = WMGetTextFieldText(panel->fileField);
e7495baf dan1999-02-17 11:06:40 +0000854
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200855 if (file[0] != '\0')
856 haveFile = 1;
857 wfree(file);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000858
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200859 col = WMGetBrowserSelectedColumn(panel->browser);
860 item = WMGetBrowserSelectedItemInColumn(panel->browser, col);
861 if (item) {
862 if (item->isBranch && !panel->flags.canChooseDirectories && !haveFile)
863 return False;
864 else if (!item->isBranch && !panel->flags.canChooseFiles)
865 return False;
866 else
867 return True;
868 } else {
869 /* we compute for / here */
870 if (!panel->flags.canChooseDirectories && !haveFile)
871 return False;
872 else
873 return True;
874 }
875 return True;
876}
877
878static void buttonClick(WMButton * bPtr, WMFilePanel * panel)
879{
880 WMRange range;
881
882 if (bPtr == panel->okButton) {
883 if (!validOpenFile(panel))
884 return;
885 if (panel->flags.fileMustExist) {
886 char *file;
887
888 file = getCurrentFileName(panel);
889 if (access(file, F_OK) != 0) {
890 WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
891 _("Error"), _("File does not exist."), _("OK"), NULL, NULL);
892 wfree(file);
893 return;
894 }
895 wfree(file);
896 }
897 panel->flags.canceled = 0;
898 } else
899 panel->flags.canceled = 1;
900
901 range.count = range.position = 0;
902 WMSelectTextFieldRange(panel->fileField, range);
903 WMBreakModalLoop(WMWidgetScreen(bPtr));
9d2e6ef9 scottc1998-09-29 22:36:29 +0000904}