1 |
/* |
2 |
* CnvPath - file selector |
3 |
* Copyright (C) 1993 Petri Heinila |
4 |
* |
5 |
* This program is free software; you can redistribute it and/or modify |
6 |
* it under the terms of the GNU General Public License as published by |
7 |
* the Free Software Foundation; either version 2 of the License, or |
8 |
* (at your option) any later version. |
9 |
* |
10 |
* This program is distributed in the hope that it will be useful, |
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
* GNU General Public License for more details. |
14 |
* |
15 |
* You should have received a copy of the GNU General Public License |
16 |
* along with this program; if not, write to the Free Software |
17 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
18 |
* |
19 |
* Author can be connected by email from hevi@lut.fi |
20 |
*/ |
21 |
|
22 |
#include <Cnv.h> |
23 |
#include <debug.h> |
24 |
#include <assert.h> |
25 |
|
26 |
/********************************************************************** |
27 |
* declarations |
28 |
**********************************************************************/ |
29 |
|
30 |
static void CnvPathListInit(CnvPath p); |
31 |
static void CnvPathListGet(CnvPath p,String path); |
32 |
static void CnvPathEnter(CnvPath self); |
33 |
static Boolean hasActions = False; |
34 |
static CnvPath tmpCnvPath = NULL; |
35 |
|
36 |
/********************************************************************** |
37 |
* actions |
38 |
**********************************************************************/ |
39 |
|
40 |
static void CnvPathReturn(Widget w,XEvent *e,String *argv, Cardinal *argc); |
41 |
|
42 |
static XtActionsRec actions[] = { |
43 |
{"CnvPathReturn", CnvPathReturn} /* when user accept */ |
44 |
}; |
45 |
|
46 |
static void CnvPathReturn(Widget w,XEvent *e,String *argv, Cardinal *argc) |
47 |
{ |
48 |
CnvPath self = (CnvPath)tmpCnvPath; |
49 |
assert(self); |
50 |
CnvPathEnter(self); |
51 |
} |
52 |
|
53 |
/********************************************************************** |
54 |
* widgets |
55 |
**********************************************************************/ |
56 |
|
57 |
static void CnvPathCancelCb(Widget w,XtPointer client,XtPointer call) |
58 |
{ |
59 |
CnvPath p = (CnvPath)client; |
60 |
p->hold = CnvPathCancel; |
61 |
} |
62 |
|
63 |
static void CnvPathEnterCb(Widget w,XtPointer client,XtPointer call) |
64 |
{ |
65 |
CnvPath self = (CnvPath)client; |
66 |
CnvPathEnter(self); |
67 |
} |
68 |
|
69 |
static void CnvPathSelectFileCb(Widget w,XtPointer client,XtPointer call) |
70 |
{ |
71 |
CnvPath p = (CnvPath)client; |
72 |
XawListReturnStruct *ret = (XawListReturnStruct*)call; |
73 |
|
74 |
XtVaSetValues(p->text, |
75 |
XtNstring,ret->string, |
76 |
NULL); |
77 |
} |
78 |
|
79 |
static void CnvPathSelectDirCb(Widget w,XtPointer client,XtPointer call) |
80 |
{ |
81 |
CnvPath p = (CnvPath)client; |
82 |
XawListReturnStruct *ret = (XawListReturnStruct*)call; |
83 |
char path[PATH_MAX+1]; |
84 |
|
85 |
if(strcmp(ret->string,"..") == 0) { |
86 |
char *str; |
87 |
pathcpy(path,p->current); |
88 |
str = path + strlen(path); |
89 |
while(*str != '/' && str > path) str--; |
90 |
*str = 0; |
91 |
} else if(strcmp(ret->string,".") == 0) { |
92 |
sprintf(path,"%s",p->current); |
93 |
} else { |
94 |
sprintf(path,"%s/%s",p->current,ret->string); |
95 |
} |
96 |
p->hold = CnvPathHold; |
97 |
CnvPathListGet(p,path); |
98 |
} |
99 |
|
100 |
/********************************************************************** |
101 |
* Layout |
102 |
**********************************************************************/ |
103 |
|
104 |
static void Layout(CnvPath self,String name) |
105 |
{ |
106 |
Widget cont,cancel,fileView,dirView,ok; |
107 |
|
108 |
self->shell = XtVaCreatePopupShell |
109 |
(name,transientShellWidgetClass,cnv->shell,NULL); |
110 |
cont = XtVaCreateManagedWidget |
111 |
("cont",formWidgetClass,self->shell, |
112 |
NULL); |
113 |
self->cwd = XtVaCreateManagedWidget |
114 |
("cwd",labelWidgetClass,cont, |
115 |
/* |
116 |
XtNfromHoriz,NULL, |
117 |
XtNfromVert,NULL, |
118 |
*/ |
119 |
NULL); |
120 |
self->text = XtVaCreateManagedWidget |
121 |
("text",asciiTextWidgetClass,cont, |
122 |
XtNtype,XawAsciiString, |
123 |
XtNeditType,XawtextEdit, |
124 |
XtNfromHoriz,self->cwd, |
125 |
XtNfromVert,NULL, |
126 |
XtNaccelerators,XtParseAcceleratorTable |
127 |
("#override <Key>Return: CnvPathReturn() \n"), |
128 |
XtNtranslations,XtParseTranslationTable |
129 |
("#override <Key>Tab: CnvNop()\n" |
130 |
"<Key>Return: CnvPathReturn() \n"), |
131 |
NULL); |
132 |
fileView = XtVaCreateManagedWidget |
133 |
("fileView",viewportWidgetClass,cont, |
134 |
XtNfromHoriz,NULL, |
135 |
XtNfromVert,self->cwd, |
136 |
NULL); |
137 |
self->fileList = XtVaCreateManagedWidget |
138 |
("fileList",listWidgetClass,fileView, |
139 |
XtNtranslations,XtParseTranslationTable |
140 |
("#override <Btn1Up>(2): Set() Notify() CnvPathReturn()\n" |
141 |
"<Btn1Down>: Set() Notify() \n"), |
142 |
NULL); |
143 |
XtAddCallback(self->fileList,XtNcallback,CnvPathSelectFileCb, |
144 |
(XtPointer)self); |
145 |
dirView = XtVaCreateManagedWidget |
146 |
("dirView",viewportWidgetClass,cont, |
147 |
XtNfromHoriz,fileView, |
148 |
XtNfromVert,self->cwd, |
149 |
NULL); |
150 |
self->dirList = XtVaCreateManagedWidget |
151 |
("dirList",listWidgetClass,dirView, |
152 |
NULL); |
153 |
XtAddCallback(self->dirList,XtNcallback,CnvPathSelectDirCb,(XtPointer)self); |
154 |
ok = XtVaCreateManagedWidget |
155 |
("ok",commandWidgetClass,cont, |
156 |
XtNfromHoriz,NULL, |
157 |
XtNfromVert,fileView, |
158 |
NULL); |
159 |
XtAddCallback(ok,XtNcallback,CnvPathEnterCb,(XtPointer)self); |
160 |
cancel = XtVaCreateManagedWidget |
161 |
("cancel",commandWidgetClass,cont, |
162 |
XtNfromHoriz,ok, |
163 |
XtNfromVert,fileView, |
164 |
NULL); |
165 |
XtAddCallback(cancel,XtNcallback,CnvPathCancelCb,(XtPointer)self); |
166 |
XtInstallAllAccelerators(cont,cont); |
167 |
} |
168 |
|
169 |
/********************************************************************** |
170 |
* |
171 |
**********************************************************************/ |
172 |
|
173 |
/* |
174 |
* function: select a filepath |
175 |
*/ |
176 |
static void CnvPathEnter(CnvPath self) |
177 |
{ |
178 |
String str; |
179 |
|
180 |
self->hold = CnvPathOk; |
181 |
XtVaGetValues(self->text, |
182 |
XtNstring,&str, |
183 |
NULL); |
184 |
namecpy(self->filename,str); |
185 |
} |
186 |
|
187 |
/* |
188 |
* implicit: App app |
189 |
*/ |
190 |
static void CnvPathListInit(CnvPath p) |
191 |
{ |
192 |
int i; |
193 |
|
194 |
for(i=0; i < EntryMax; i++) { |
195 |
/* debug1("i:%i\n",i); */ |
196 |
p->fileTable[i] = NULL; |
197 |
} |
198 |
for(i=0; i < EntryMax; i++) { |
199 |
/* debug1("i2:%i\n",i); */ |
200 |
p->dirTable[i] = NULL; |
201 |
} |
202 |
p->fileNro = 0; |
203 |
p->dirNro = 0; |
204 |
*(p->filename) = 0; |
205 |
} |
206 |
|
207 |
/* |
208 |
* compare funtion for sorting in CnvPathListGet() |
209 |
*/ |
210 |
static int StrCmp (const void **s1, const void **s2) |
211 |
{ |
212 |
return strcmp (*s1, *s2); |
213 |
} |
214 |
|
215 |
/* |
216 |
* read files and directories from given absolute dir |
217 |
* update them into Path structure. directoty is a crossfire |
218 |
* part of file name ie. LibDir/MapDir<dirname>, althought |
219 |
* it is absolute name in it part, ie it have to begin with '/'. |
220 |
*/ |
221 |
static void CnvPathListGet(CnvPath self,String directory) |
222 |
{ |
223 |
DIR *dir; |
224 |
#ifdef NeXT |
225 |
struct direct *dirent; |
226 |
#else |
227 |
struct dirent *dirent; |
228 |
#endif |
229 |
struct stat statbuf; |
230 |
Cardinal i,fileOld,dirOld; |
231 |
char path[PATH_MAX+1],full[PATH_MAX+1]; |
232 |
|
233 |
/*** form full dir name ***/ |
234 |
sprintf(full,"%s%s",self->root,directory); |
235 |
debug1("CnvPathListGet(), rescan %s\n",full); |
236 |
|
237 |
/*** open it ***/ |
238 |
if(CnvPathNoAccess(self->shell, full)) return; |
239 |
if((dir = opendir(full)) == NULL) CnvDie(self->shell,full); |
240 |
XtVaSetValues(self->cwd, |
241 |
XtNlabel,directory, |
242 |
NULL); |
243 |
pathcpy(self->current,directory); |
244 |
|
245 |
/*** read dir & files ***/ |
246 |
fileOld = self->fileNro; |
247 |
dirOld = self->dirNro; |
248 |
self->fileNro = 0; |
249 |
self->dirNro = 0; |
250 |
while((dirent = readdir(dir)) != NULL) { |
251 |
sprintf(path,"%s/%s",full,dirent->d_name); |
252 |
|
253 |
if (stat ((char *) path, &statbuf) == -1) { |
254 |
perror (path); |
255 |
continue; |
256 |
} |
257 |
if(S_ISDIR(statbuf.st_mode)) { |
258 |
if(self->dirNro >= EntryMax) continue; |
259 |
|
260 |
XtFree(self->dirTable[self->dirNro]); |
261 |
self->dirTable[self->dirNro] = XtNewString(dirent->d_name); |
262 |
|
263 |
self->dirNro++; |
264 |
} else { |
265 |
if(self->fileNro >= EntryMax) continue; |
266 |
|
267 |
XtFree(self->fileTable[self->fileNro]); |
268 |
self->fileTable[self->fileNro] = XtNewString(dirent->d_name); |
269 |
|
270 |
self->fileNro++; |
271 |
} |
272 |
} |
273 |
closedir(dir); |
274 |
|
275 |
/*** free strings ***/ |
276 |
for(i = self->fileNro; i < fileOld; i++) { |
277 |
XtFree(self->fileTable[i]); |
278 |
self->fileTable[i] = NULL; |
279 |
} |
280 |
for(i = self->dirNro; i < dirOld; i++) { |
281 |
XtFree(self->dirTable[i]); |
282 |
self->dirTable[i] = NULL; |
283 |
} |
284 |
|
285 |
/*** sort tables ***/ |
286 |
qsort(self->fileTable,self->fileNro,sizeof(String),(int (*)())StrCmp); |
287 |
qsort(self->dirTable,self->dirNro,sizeof(String),(int (*)())StrCmp); |
288 |
|
289 |
/*** update ***/ |
290 |
XawListChange(self->fileList,self->fileTable,self->fileNro,0,True); |
291 |
XawListChange(self->dirList,self->dirTable,self->dirNro,0,True); |
292 |
} |
293 |
|
294 |
/********************************************************************** |
295 |
* public |
296 |
**********************************************************************/ |
297 |
|
298 |
/* |
299 |
* create new instance of file-selector, no show |
300 |
* dir is crossfire path eg "/" |
301 |
* name: name of this module |
302 |
* root: all |
303 |
* dir : starting directory |
304 |
*/ |
305 |
CnvPath CnvPathCreate(String name,String root,String dir) |
306 |
{ |
307 |
|
308 |
|
309 |
CnvPath self; |
310 |
|
311 |
debug3("CnvPathCreate() %s %s %s\n",name,root,dir); |
312 |
self = (CnvPath) XtMalloc (sizeof (struct CnvPath)); |
313 |
memset(self,0,sizeof(struct CnvPath)); |
314 |
pathcpy(self->root,root); |
315 |
|
316 |
/*** initialize translations if not done ***/ |
317 |
if(hasActions == False) { |
318 |
XtAppAddActions(XtWidgetToApplicationContext(cnv->shell), |
319 |
actions, |
320 |
XtNumber(actions)); |
321 |
hasActions = True; |
322 |
} |
323 |
Layout(self,name); |
324 |
CnvPathListInit(self); |
325 |
CnvCenterWidget(self->shell); |
326 |
CnvPathListGet(self,dir); |
327 |
return self; |
328 |
} |
329 |
|
330 |
/* |
331 |
* remove instance of file-selector |
332 |
*/ |
333 |
void CnvPathDestroy(CnvPath self) |
334 |
{ |
335 |
Cardinal i; |
336 |
debug("CnvPathDestroy()\n"); |
337 |
|
338 |
for(i=0;i<self->dirNro;i++) XtFree(self->dirTable[i]); |
339 |
for(i=0;i<self->fileNro;i++) XtFree(self->fileTable[i]); |
340 |
XtDestroyWidget(self->shell); |
341 |
} |
342 |
|
343 |
/* |
344 |
* member: select a filepath |
345 |
* return: PathResponce & results are in Path-structure |
346 |
*/ |
347 |
CnvPathResponce CnvPathSelect(CnvPath self) |
348 |
{ |
349 |
if(tmpCnvPath) { |
350 |
CnvNotify("File Selector already in use", |
351 |
"Continue",NULL); |
352 |
return CnvPathCancel; |
353 |
} |
354 |
XtVaSetValues(self->text, |
355 |
XtNstring,self->filename, |
356 |
NULL); |
357 |
/*** round ***/ |
358 |
tmpCnvPath = self; |
359 |
self->hold = CnvPathHold; |
360 |
XtPopup(self->shell,XtGrabExclusive); |
361 |
while(self->hold == CnvPathHold) { |
362 |
XtAppProcessEvent(XtWidgetToApplicationContext(self->shell),XtIMXEvent); |
363 |
} |
364 |
XtPopdown(self->shell); |
365 |
tmpCnvPath = NULL; |
366 |
return self->hold; |
367 |
} |
368 |
|
369 |
/* |
370 |
* member: select a filepath |
371 |
* return: PathResponce & results are in Path-structure |
372 |
*/ |
373 |
CnvPathResponce CnvPathSelectAbs(CnvPath self,String path) |
374 |
{ |
375 |
if(tmpCnvPath) { |
376 |
CnvNotify("File Selector already in use", |
377 |
"Continue",NULL); |
378 |
return CnvPathCancel; |
379 |
} |
380 |
XtVaSetValues(self->text, |
381 |
XtNstring,self->filename, |
382 |
NULL); |
383 |
/*** round ***/ |
384 |
tmpCnvPath = self; |
385 |
self->hold = CnvPathHold; |
386 |
XtPopup(self->shell,XtGrabExclusive); |
387 |
while(self->hold == CnvPathHold) { |
388 |
XtAppProcessEvent(XtWidgetToApplicationContext(self->shell),XtIMXEvent); |
389 |
} |
390 |
XtPopdown(self->shell); |
391 |
tmpCnvPath = NULL; |
392 |
sprintf(path,"%s%s/%s",self->root,self->current,self->filename); |
393 |
return self->hold; |
394 |
} |
395 |
|
396 |
/********************************************************************** |
397 |
* utility |
398 |
**********************************************************************/ |
399 |
|
400 |
/* |
401 |
* - path is full absolute name |
402 |
* - return true if NO access |
403 |
*/ |
404 |
Boolean CnvPathNoAccess(Widget w, String path) |
405 |
{ |
406 |
char buf[BUFSIZ]; |
407 |
|
408 |
if (access (path, R_OK | X_OK) == -1) { |
409 |
switch (errno) { |
410 |
case EACCES: |
411 |
sprintf (buf, "Permission denied for %s", path); |
412 |
CnvNotify (buf,Continue,NULL); |
413 |
break; |
414 |
case ENOENT: |
415 |
sprintf (buf, "%s does not exist", path); |
416 |
CnvNotify (buf,Continue,NULL); |
417 |
break; |
418 |
case EIO: |
419 |
sprintf (buf, "IO error in accessing %s", path); |
420 |
CnvNotify (buf,Continue,NULL); |
421 |
break; |
422 |
case ENAMETOOLONG: |
423 |
case ENOTDIR: |
424 |
sprintf (buf, "Error in pathname for %s", path); |
425 |
CnvNotify (buf,Continue); |
426 |
break; |
427 |
default: |
428 |
sprintf (buf, "Error accessing to %s", path); |
429 |
CnvNotify (buf,Continue,NULL); |
430 |
break; |
431 |
} |
432 |
return True; |
433 |
} else { |
434 |
return False; |
435 |
} |
436 |
} |
437 |
|
438 |
/* |
439 |
* - path is full absolute name |
440 |
* - return true if NO access |
441 |
*/ |
442 |
Boolean CnvPathNoWrite(Widget w, String path) |
443 |
{ |
444 |
char buf[BUFSIZ]; |
445 |
|
446 |
if (access (path, R_OK | W_OK) == -1) { |
447 |
switch (errno) { |
448 |
case EACCES: |
449 |
sprintf (buf, "Permission denied for %s", path); |
450 |
CnvNotify (buf,Continue,NULL); |
451 |
break; |
452 |
case ENOENT: |
453 |
sprintf (buf, "%s does not exist", path); |
454 |
CnvNotify (buf,Continue,NULL); |
455 |
break; |
456 |
case EIO: |
457 |
sprintf (buf, "IO error in accessing %s", path); |
458 |
CnvNotify (buf,Continue,NULL); |
459 |
break; |
460 |
case ENAMETOOLONG: |
461 |
case ENOTDIR: |
462 |
sprintf (buf, "Error in pathname for %s", path); |
463 |
CnvNotify (buf,Continue); |
464 |
break; |
465 |
default: |
466 |
sprintf (buf, "Error accessing to %s", path); |
467 |
CnvNotify (buf,Continue,NULL); |
468 |
break; |
469 |
} |
470 |
return True; |
471 |
} else { |
472 |
return False; |
473 |
} |
474 |
} |
475 |
|
476 |
/*** end of CnvPath.c ***/ |
477 |
|
478 |
|