1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
8
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <assert.h>
29 #include <fontforge-config.h>
30
31 #include "gdraw.h"
32 #include "gdrawP.h"
33 #include "gfile.h"
34 #include "ggadgetP.h"
35 #include "gicons.h"
36 #include "gio.h"
37 #include "gwidgetP.h"
38 #include "ustring.h"
39 #include "utype.h"
40 #ifdef WIN32
41 #include <windows.h>
42
43 // Returns "CDQ" if C:\, D:\ and Q:\ are available.
44 // This could probably be put in fsys.c, but we don't need it anywhere else,
45 // and shouldn't ever.
46 static unsigned int WIN32_DRIVES_MAXLEN = 26;
_DriveLetters()47 static char* _DriveLetters() {
48 int idx = -1;
49 char* ret = calloc(WIN32_DRIVES_MAXLEN+1,sizeof(char));
50 DWORD drives = GetLogicalDrives();
51 assert(drives > 0);
52 for (int d = 0; d < WIN32_DRIVES_MAXLEN; d++) {
53 if ( (drives&(1 << d)) ) {
54 ret[++idx] = 'A'+d;
55 }
56 }
57 return ret;
58 }
59 #endif
60
61 /* This isn't really a gadget, it's just a collection of gadgets with some glue*/
62 /* to make them work together. Therefore there are no expose routines here, */
63 /* nor mouse, nor key. That's all handled by the individual gadgets themselves*/
64 /* Instead we've got a bunch of routines that make them work as a whole */
65 static GBox gfilechooser_box = GBOX_EMPTY; /* no box */
66 static unichar_t *lastdir;
67 static int showhidden = false;
68 static enum { dirs_mixed, dirs_first, dirs_separate } dir_placement = dirs_mixed;
69 static unichar_t **bookmarks = NULL;
70 static void *prefs_changed_data = NULL;
71 static void (*prefs_changed)(void *) = NULL;
72
SubMatch(unichar_t * pattern,unichar_t * eop,unichar_t * name,int ignorecase)73 static unichar_t *SubMatch(unichar_t *pattern, unichar_t *eop, unichar_t *name,int ignorecase) {
74 unichar_t ch, *ppt, *npt, *ept, *eon;
75
76 while ( pattern<eop && ( ch = *pattern)!='\0' ) {
77 if ( ch=='*' ) {
78 if ( pattern[1]=='\0' )
79 return( name+u_strlen(name));
80 for ( npt=name; ; ++npt ) {
81 if ( (eon = SubMatch(pattern+1,eop,npt,ignorecase))!= NULL )
82 return( eon );
83 if ( *npt=='\0' )
84 return( NULL );
85 }
86 } else if ( ch=='?' ) {
87 if ( *name=='\0' )
88 return( NULL );
89 ++name;
90 } else if ( ch=='[' ) {
91 /* [<char>...] matches the chars
92 * [<char>-<char>...] matches any char within the range (inclusive)
93 * the above may be concattenated and the resultant pattern matches
94 * anything thing which matches any of them.
95 * [^<char>...] matches any char which does not match the rest of
96 * the pattern
97 * []...] as a special case a ']' immediately after the '[' matches
98 * itself and does not end the pattern
99 */
100 int found = 0, not=0;
101 ++pattern;
102 if ( pattern[0]=='^' ) { not = 1; ++pattern; }
103 for ( ppt = pattern; (ppt!=pattern || *ppt!=']') && *ppt!='\0' ; ++ppt ) {
104 ch = *ppt;
105 if ( ppt[1]=='-' && ppt[2]!=']' && ppt[2]!='\0' ) {
106 unichar_t ch2 = ppt[2];
107 if ( (*name>=ch && *name<=ch2) ||
108 (ignorecase && islower(ch) && islower(ch2) &&
109 *name>=toupper(ch) && *name<=toupper(ch2)) ||
110 (ignorecase && isupper(ch) && isupper(ch2) &&
111 *name>=tolower(ch) && *name<=tolower(ch2))) {
112 if ( !not ) {
113 found = 1;
114 break;
115 }
116 } else {
117 if ( not ) {
118 found = 1;
119 break;
120 }
121 }
122 ppt += 2;
123 } else if ( ch==*name || (ignorecase && tolower(ch)==tolower(*name)) ) {
124 if ( !not ) {
125 found = 1;
126 break;
127 }
128 } else {
129 if ( not ) {
130 found = 1;
131 break;
132 }
133 }
134 }
135 if ( !found )
136 return( NULL );
137 while ( *ppt!=']' && *ppt!='\0' ) ++ppt;
138 pattern = ppt;
139 ++name;
140 } else if ( ch=='{' ) {
141 /* matches any of a comma separated list of substrings */
142 for ( ppt = pattern+1; *ppt!='\0' ; ppt = ept ) {
143 for ( ept=ppt; *ept!='}' && *ept!=',' && *ept!='\0'; ++ept );
144 npt = SubMatch(ppt,ept,name,ignorecase);
145 if ( npt!=NULL ) {
146 unichar_t *ecurly = ept;
147 while ( *ecurly!='}' && ecurly<eop && *ecurly!='\0' ) ++ecurly;
148 if ( (eon=SubMatch(ecurly+1,eop,npt,ignorecase))!=NULL )
149 return( eon );
150 }
151 if ( *ept=='}' )
152 return( NULL );
153 if ( *ept==',' ) ++ept;
154 }
155 } else if ( ch==*name ) {
156 ++name;
157 } else if ( ignorecase && tolower(ch)==tolower(*name)) {
158 ++name;
159 } else
160 return( NULL );
161 ++pattern;
162 }
163 if (pattern > eop) {
164 return NULL;
165 }
166 return( name );
167 }
168
169 /* Handles *?{}[] wildcards */
GGadgetWildMatch(unichar_t * pattern,unichar_t * name,int ignorecase)170 int GGadgetWildMatch(unichar_t *pattern, unichar_t *name,int ignorecase) {
171 if ( pattern==NULL )
172 return( true );
173
174 unichar_t *eop = pattern + u_strlen(pattern);
175
176 name = SubMatch(pattern,eop,name,ignorecase);
177 if ( name==NULL )
178 return( false );
179 if ( *name=='\0' )
180 return( true );
181
182 return( false );
183 }
184
GFileChooserDefFilter(GGadget * g,GDirEntry * ent,const unichar_t * dir)185 enum fchooserret GFileChooserDefFilter(GGadget *g,GDirEntry *ent,const unichar_t *dir) {
186 GFileChooser *gfc = (GFileChooser *) g;
187 int i;
188 char *mime;
189
190 if ( uc_strcmp(ent->name,".")==0 ) /* Don't show the current directory entry */
191 return( fc_hide );
192 if ( gfc->wildcard!=NULL && *gfc->wildcard=='.' )
193 /* If they asked for hidden files, show them */;
194 else if ( !showhidden && ent->name[0]=='.' && uc_strcmp(ent->name,"..")!=0 )
195 return( fc_hide );
196 if ( ent->isdir ) /* Show all other directories */
197 return( fc_show );
198 if ( gfc->wildcard==NULL && gfc->mimetypes==NULL )
199 return( fc_show );
200 /* If we've got a wildcard, and it matches, then show */
201 if ( gfc->wildcard!=NULL && GGadgetWildMatch(gfc->wildcard,ent->name,true))
202 return( fc_show );
203 /* If no mimetypes then we're done */
204 if ( gfc->mimetypes==NULL )
205 return( fc_hide );
206 /* match the mimetypes */
207 if( ent->mimetype )
208 mime = copy(u_to_c(ent->mimetype));
209 else {
210 char utf8_ent_name[PATH_MAX+1];
211 strncpy(utf8_ent_name,u_to_c( ent->name ),PATH_MAX);
212 utf8_ent_name[PATH_MAX]=0;
213 mime = GIOGetMimeType(utf8_ent_name);
214 }
215
216 if ( mime ) {
217 for ( i=0; gfc->mimetypes[i]!=NULL; ++i )
218 if ( strcasecmp(u_to_c(gfc->mimetypes[i]),mime)==0 ) {
219 free(mime);
220 return( fc_show );
221 }
222 free(mime);
223 }
224
225 return( fc_hide );
226 }
227
GFileChooserPickIcon(GDirEntry * e)228 static GImage *GFileChooserPickIcon(GDirEntry *e) {
229 char mime[100];
230 char utf8_ent_name[PATH_MAX+1];
231 mime[0] = mime[99] = utf8_ent_name[PATH_MAX] = 0;
232 strncpy(utf8_ent_name,u_to_c(e->name),PATH_MAX);
233
234 InitChooserIcons();
235
236 if ( e->isdir ) {
237 if ( !strcmp(utf8_ent_name,"..") )
238 return( &_GIcon_updir );
239 return( &_GIcon_dir );
240 }
241 if ( e->mimetype ) {
242 strncpy(mime,u_to_c(e->mimetype),99);
243 } else {
244 char *temp;
245 if ( (temp=GIOguessMimeType(utf8_ent_name)) || (temp=GIOGetMimeType(utf8_ent_name)) ) {
246 e->mimetype=u_copy(c_to_u(temp));
247 strncpy(mime,temp,99);
248 free(temp);
249 } else
250 return( &_GIcon_unknown );
251 }
252 if (strncasecmp("text/", mime, 5) == 0) {
253 if (strcasecmp("text/html", mime) == 0)
254 return( &_GIcon_texthtml );
255 if (strcasecmp("text/xml", mime) == 0)
256 return( &_GIcon_textxml );
257 if (strcasecmp("text/css", mime) == 0)
258 return( &_GIcon_textcss );
259 if (strcasecmp("text/c", mime) == 0)
260 return( &_GIcon_textc );
261 if (strcasecmp("text/java", mime) == 0)
262 return( &_GIcon_textjava );
263 if (strcasecmp("text/x-makefile", mime) == 0)
264 return( &_GIcon_textmake );
265 if (strcasecmp("text/fontps", mime) == 0)
266 return( &_GIcon_textfontps );
267 if (strcasecmp("text/font", mime) == 0)
268 return( &_GIcon_textfontbdf );
269 if (strcasecmp("text/ps", mime) == 0)
270 return( &_GIcon_textps );
271
272 return( &_GIcon_textplain );
273 }
274
275 if (strncasecmp("image/", mime, 6) == 0)
276 return( &_GIcon_image );
277 if (strncasecmp("video/", mime, 6) == 0)
278 return( &_GIcon_video );
279 if (strncasecmp("audio/", mime, 6) == 0)
280 return( &_GIcon_audio );
281 if (strcasecmp("application/x-navidir", mime) == 0 ||
282 strcasecmp("inode/directory", mime) == 0)
283 return( &_GIcon_dir );
284 if (strcasecmp("application/x-object", mime) == 0)
285 return( &_GIcon_object );
286 if (strcasecmp("application/x-core", mime) == 0)
287 return( &_GIcon_core );
288 if (strcasecmp("application/x-tar", mime) == 0)
289 return( &_GIcon_tar );
290 if (strcasecmp("application/x-compressed", mime) == 0)
291 return( &_GIcon_compressed );
292 if (strcasecmp("application/pdf", mime) == 0)
293 return( &_GIcon_texthtml );
294 if (strcasecmp("application/vnd.font-fontforge-sfd", mime) == 0)
295 return( &_GIcon_textfontsfd );
296 if (strcasecmp("application/x-font-type1", mime) == 0)
297 return( &_GIcon_textfontps );
298 if (strcasecmp("application/x-font-ttf", mime) == 0 ||
299 strcasecmp("application/x-font-otf", mime) == 0 ||
300 strcasecmp("font/woff", mime) == 0 ||
301 strcasecmp("font/woff2", mime) == 0 ||
302 strcasecmp("font/ttf", mime) == 0 ||
303 strcasecmp("font/otf", mime) == 0) {
304 return( &_GIcon_ttf );
305 }
306 if (strcasecmp("application/x-font-cid", mime) == 0 )
307 return( &_GIcon_cid );
308 if (strcasecmp("application/x-macbinary", mime) == 0 ||
309 strcasecmp("application/x-mac-binhex40", mime) == 0 ) {
310 return( &_GIcon_mac );
311 }
312 if (strcasecmp("application/x-mac-dfont", mime) == 0 ||
313 strcasecmp("application/x-mac-suit", mime) == 0 ) {
314 return( &_GIcon_macttf );
315 }
316 if (strcasecmp("application/x-font-pcf", mime) == 0 ||
317 strcasecmp("application/x-font-snf", mime) == 0) {
318 return( &_GIcon_textfontbdf );
319 }
320
321 return( &_GIcon_unknown );
322 }
323
GFileChooserFillList(GFileChooser * gfc,GDirEntry * first,const unichar_t * dir)324 static void GFileChooserFillList(GFileChooser *gfc,GDirEntry *first,
325 const unichar_t *dir) {
326 GDirEntry *e;
327 int len, dlen;
328 GTextInfo **ti, **dti;
329
330 len = dlen = 0;
331 for ( e=first; e!=NULL; e=e->next ) {
332 e->fcdata = (gfc->filter)(&gfc->g,e,dir);
333 if ( e->fcdata!=fc_hide ) {
334 if ( e->isdir )
335 ++dlen;
336 else
337 ++len;
338 }
339 }
340
341 if ( dir_placement == dirs_separate ) {
342 ti = malloc((len+1)*sizeof(GTextInfo *));
343 dti = malloc((dlen+1)*sizeof(GTextInfo *));
344 len = dlen = 0;
345 for ( e=first; e!=NULL; e=e->next ) {
346 if ( e->fcdata!=fc_hide ) {
347 GTextInfo **me;
348 if ( e->isdir )
349 me = &dti[dlen++];
350 else
351 me = &ti[len++];
352
353 *me = calloc(1,sizeof(GTextInfo));
354 (*me)->text = u_copy(e->name);
355 (*me)->image = GFileChooserPickIcon(e);
356 (*me)->fg = COLOR_DEFAULT;
357 (*me)->bg = COLOR_DEFAULT;
358 (*me)->font = NULL;
359 (*me)->disabled = e->fcdata==fc_showdisabled;
360 (*me)->image_precedes = true;
361 (*me)->checked = e->isdir;
362 }
363 }
364 ti[len] = calloc(1,sizeof(GTextInfo));
365 dti[dlen] = calloc(1,sizeof(GTextInfo));
366 GGadgetSetList(&gfc->files->g,ti,false);
367 GGadgetSetList(&gfc->subdirs->g,dti,false);
368 } else {
369 ti = malloc((len+dlen+1)*sizeof(GTextInfo *));
370 len = 0;
371 for ( e=first; e!=NULL; e=e->next ) {
372 if ( e->fcdata!=fc_hide ) {
373 ti[len] = calloc(1,sizeof(GTextInfo));
374 ti[len]->text = u_copy(e->name);
375 ti[len]->image = GFileChooserPickIcon(e);
376 ti[len]->fg = COLOR_DEFAULT;
377 ti[len]->bg = COLOR_DEFAULT;
378 ti[len]->font = NULL;
379 ti[len]->disabled = e->fcdata==fc_showdisabled;
380 ti[len]->image_precedes = true;
381 ti[len]->checked = e->isdir;
382 if ( dir_placement==dirs_first && e->isdir )
383 ((GTextInfo2 *) ti[len])->sort_me_first_in_list = true;
384 ++len;
385 }
386 }
387 ti[len] = calloc(1,sizeof(GTextInfo));
388 GGadgetSetList(&gfc->files->g,ti,false);
389 }
390
391 GGadgetScrollListToText(&gfc->files->g,u_GFileNameTail(_GGadgetGetTitle(&gfc->name->g)),true);
392 }
393
GFileChooserIntermediateDir(GIOControl * gc)394 static void GFileChooserIntermediateDir(GIOControl *gc) {
395 GFileChooser *gfc = (GFileChooser *) (gc->userdata);
396
397 GFileChooserFillList(gfc,GIOgetDirData(gc),gc->path);
398 }
399
GFileChooserReceiveDir(GIOControl * gc)400 static void GFileChooserReceiveDir(GIOControl *gc) {
401 GFileChooser *gfc = (GFileChooser *) (gc->userdata);
402
403 GGadgetSetEnabled(&gfc->files->g,true);
404 GGadgetSetEnabled(&gfc->subdirs->g,true);
405 if ( gfc->lastname!=NULL ) {
406 GGadgetSetTitle(&gfc->name->g,gfc->lastname);
407 free(gfc->lastname);
408 gfc->lastname=NULL;
409 }
410 GFileChooserFillList(gfc,GIOgetDirData(gc),gc->path);
411 GIOclose(gc);
412 gfc->outstanding = NULL;
413 GDrawSetCursor(gfc->g.base,gfc->old_cursor);
414 }
415
GFileChooserErrorDir(GIOControl * gc)416 static void GFileChooserErrorDir(GIOControl *gc) {
417 GFileChooser *gfc = (GFileChooser *) (gc->userdata);
418 GTextInfo *ti[3], _ti[3];
419 static unichar_t nullstr[] = { 0 };
420
421 memset(_ti,'\0',sizeof(_ti));
422 _ti[0].text = gc->error;
423 if ( gc->status[0]!='\0' )
424 _ti[1].text = gc->status;
425 _ti[0].fg = _ti[0].bg = _ti[1].fg = _ti[1].bg = COLOR_DEFAULT;
426 ti[0] = _ti; ti[1] = _ti+1; ti[2] = _ti+2;
427 GGadgetSetEnabled(&gfc->files->g,false);
428 GGadgetSetList(&gfc->files->g,ti,true);
429 GGadgetSetEnabled(&gfc->subdirs->g,false);
430 GGadgetSetList(&gfc->subdirs->g,ti,true);
431 if ( gfc->lastname!=NULL ) {
432 GGadgetSetTitle(&gfc->name->g,gfc->lastname);
433 free(gfc->lastname);
434 gfc->lastname=NULL;
435 } else
436 GGadgetSetTitle(&gfc->name->g,nullstr);
437 if ( gfc->filterb!=NULL && gfc->ok!=NULL )
438 _GWidget_MakeDefaultButton(&gfc->ok->g);
439 GIOcancel(gc);
440 gfc->outstanding = NULL;
441 GDrawSetCursor(gfc->g.base,gfc->old_cursor);
442 }
443
GFileChooserScanDir(GFileChooser * gfc,unichar_t * dir)444 static void GFileChooserScanDir(GFileChooser *gfc,unichar_t *dir) {
445 GTextInfo **ti=NULL;
446 int cnt, tot=0;
447 #ifdef _WIN32
448 char* drives = _DriveLetters();
449 int dcnt = strlen(drives);
450 #endif
451 unichar_t *pt, *ept, *freeme;
452
453 dir = u_GFileNormalize(dir);
454 while ( 1 ) {
455 ept = dir;
456 cnt = 0;
457 if ( (pt=uc_strstr(dir,"://"))!=NULL ) {
458 ept = u_strchr(pt+3,'/');
459 if ( ept==NULL )
460 ept = pt+u_strlen(pt);
461 else
462 ++ept;
463 } else if ( *dir=='/' )
464 ept = dir+1;
465 if ( ept!=dir ) {
466 if ( ti!=NULL ) {
467 ti[tot-cnt] = calloc(1,sizeof(GTextInfo));
468 ti[tot-cnt]->text = u_copyn(dir,ept-dir);
469 ti[tot-cnt]->fg = ti[tot-cnt]->bg = COLOR_DEFAULT;
470 }
471 cnt = 1;
472 }
473 for ( pt = ept; *pt!='\0'; pt = ept ) {
474 for ( ept = pt; *ept!='/' && *ept!='\0'; ++ept );
475 if ( ti!=NULL ) {
476 ti[tot-cnt] = calloc(1,sizeof(GTextInfo));
477 ti[tot-cnt]->text = u_copyn(pt,ept-pt);
478 ti[tot-cnt]->fg = ti[tot-cnt]->bg = COLOR_DEFAULT;
479 }
480 ++cnt;
481 if ( *ept=='/' ) ++ept;
482 }
483 if ( ti!=NULL )
484 break;
485 ti = malloc((cnt+1)*sizeof(GTextInfo *));
486 tot = cnt-1;
487 }
488
489 #ifdef _WIN32
490 ti = realloc(ti, (dcnt+cnt+1)*sizeof(GTextInfo *));
491
492 for (char* c = drives; *c != '\0'; c++) {
493 // Don't put the root twice if we're already on it.
494 if (*c == toupper(dir[0])) continue;
495
496 ti[cnt] = calloc(1,sizeof(GTextInfo));
497 unichar_t* utemp = calloc(3,sizeof(unichar_t));
498 utemp[0] = *c; utemp[1] = ':'; //utemp[2] = '\\'; // utemp[3] = 0;
499 ti[cnt]->text = utemp;
500 ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT;
501 // We don't want to add a new field to GTextInfo as it's used in a lot of places.
502 // This is the next best thing AFAICT.
503 ti[cnt]->userdata = (void*)1;
504 cnt++;
505 }
506 free(drives);
507 #endif
508 ti[cnt] = calloc(1,sizeof(GTextInfo));
509
510 GGadgetSetList(&gfc->directories->g,ti,false);
511 GGadgetSelectOneListItem(&gfc->directories->g,0);
512
513 if ( gfc->outstanding!=NULL ) {
514 GIOcancel(gfc->outstanding);
515 gfc->outstanding = NULL;
516 } else {
517 gfc->old_cursor = GDrawGetCursor(gfc->g.base);
518 GDrawSetCursor(gfc->g.base,ct_watch);
519 }
520
521 gfc->outstanding = GIOCreate(dir,gfc,GFileChooserReceiveDir,
522 GFileChooserErrorDir);
523 gfc->outstanding->receiveintermediate = GFileChooserIntermediateDir;
524 GIOdir(gfc->outstanding);
525
526 freeme = NULL;
527 if ( dir[u_strlen(dir)-1]!='/' ) {
528 freeme = malloc((u_strlen(dir)+3)*sizeof(unichar_t));
529 u_strcpy(freeme,dir);
530 uc_strcat(freeme,"/");
531 dir = freeme;
532 }
533 if ( gfc->hpos+1>=gfc->hmax ) {
534 gfc->hmax = gfc->hmax+20;
535 gfc->history = realloc(gfc->history,(gfc->hmax)*sizeof(unichar_t *));
536 }
537 if ( gfc->hcnt==0 ) {
538 gfc->history[gfc->hcnt++] = u_copy(dir);
539 } else if ( u_strcmp(gfc->history[gfc->hpos],dir)==0 )
540 /* Just a refresh */;
541 else {
542 gfc->history[++gfc->hpos] = u_copy(dir);
543 gfc->hcnt = gfc->hpos+1;
544 }
545 free(freeme);
546 }
547
548 /* Handle events from the text field */
GFileChooserTextChanged(GGadget * t,GEvent * e)549 static int GFileChooserTextChanged(GGadget *t,GEvent *e) {
550 GFileChooser *gfc;
551 GGadget *g = (GGadget *)GGadgetGetUserData(t);
552
553 const unichar_t *pt, *spt;
554 unichar_t * pt_toFree = 0, *local_toFree = 0;
555 if ( e->type!=et_controlevent || e->u.control.subtype!=et_textchanged )
556 return( true );
557 spt = pt = _GGadgetGetTitle(t);
558 #ifdef _WIN32
559 local_toFree = u_GFileNormalizePath(u_copy(spt));
560 pt = spt = local_toFree;
561 #endif
562
563 if ( pt==NULL )
564 return( true );
565 gfc = (GFileChooser *) GGadgetGetUserData(t);
566
567 if( GFileChooserGetInputFilenameFunc(g)(g, &pt,gfc->inputfilenameprevchar)) {
568 pt_toFree = (unichar_t*)pt;
569 spt = pt;
570 GGadgetSetTitle(g, pt);
571 }
572
573 while ( *pt && *pt!='*' && *pt!='?' && *pt!='[' && *pt!='{' )
574 ++pt;
575 if ( *spt!='\0' && spt[u_strlen(spt)-1]=='/' )
576 pt = spt+u_strlen(spt)-1;
577
578 /* if there are no wildcards and no directories in the filename */
579 /* then as it gets changed the list box should show the closest */
580 /* approximation to it */
581 if ( *pt=='\0' ) {
582 GGadgetScrollListToText(&gfc->files->g,spt,true);
583 if ( gfc->filterb!=NULL && gfc->ok!=NULL )
584 _GWidget_MakeDefaultButton(&gfc->ok->g);
585 } else if ( *pt=='/' && e->u.control.u.tf_changed.from_pulldown!=-1 ) {
586 GEvent e;
587 e.type = et_controlevent;
588 e.u.control.subtype = et_buttonactivate;
589 e.u.control.g = (gfc->ok!=NULL?&gfc->ok->g:&gfc->g);
590 e.u.control.u.button.clicks = 0;
591 e.w = e.u.control.g->base;
592 if ( e.u.control.g->handle_controlevent != NULL )
593 (e.u.control.g->handle_controlevent)(e.u.control.g,&e);
594 else
595 GDrawPostEvent(&e);
596 } else {
597 if ( gfc->filterb!=NULL && gfc->ok!=NULL )
598 _GWidget_MakeDefaultButton(&gfc->filterb->g);
599 }
600 free(gfc->lastname); gfc->lastname = NULL;
601 if(pt_toFree)
602 free(pt_toFree);
603
604 if (local_toFree)
605 free(local_toFree);
606
607 if(gfc->inputfilenameprevchar)
608 free(gfc->inputfilenameprevchar);
609 gfc->inputfilenameprevchar = u_copy(_GGadgetGetTitle(t));
610
611 return( true );
612 }
613
GFileChooserCompletion(GGadget * t,int from_tab)614 static unichar_t **GFileChooserCompletion(GGadget *t,int from_tab) {
615 GFileChooser *gfc;
616 const unichar_t *pt, *spt; unichar_t **ret;
617 GTextInfo **ti;
618 int32 len;
619 int i, cnt, doit, match_len;
620
621 pt = spt = _GGadgetGetTitle(t);
622 if ( pt==NULL )
623 return( NULL );
624 while ( *pt && *pt!='/' && *pt!='*' && *pt!='?' && *pt!='[' && *pt!='{' )
625 ++pt;
626 if ( *pt!='\0' )
627 return( NULL ); /* Can't complete if not in cur directory or has wildcards */
628
629 match_len = u_strlen(spt);
630 gfc = (GFileChooser *) GGadgetGetUserData(t);
631 ti = GGadgetGetList(&gfc->files->g,&len);
632 ret = NULL;
633 for ( doit=0; doit<2; ++doit ) {
634 cnt=0;
635 for ( i=0; i<len; ++i ) {
636 if ( u_strncmp(ti[i]->text,spt,match_len)==0 ) {
637 if ( doit ) {
638 if ( ti[i]->checked /* isdirectory */ ) {
639 int len = u_strlen(ti[i]->text);
640 ret[cnt] = malloc((len+2)*sizeof(unichar_t));
641 u_strcpy(ret[cnt],ti[i]->text);
642 ret[cnt][len] = '/';
643 ret[cnt][len+1] = '\0';
644 } else
645 ret[cnt] = u_copy(ti[i]->text);
646 }
647 ++cnt;
648 }
649 }
650 if ( doit )
651 ret[cnt] = NULL;
652 else if ( cnt==0 )
653 return( NULL );
654 else
655 ret = malloc((cnt+1)*sizeof(unichar_t *));
656 }
657 return( ret );
658 }
659
GFileChooserGetCurDir(GFileChooser * gfc,int dirindex)660 static unichar_t *GFileChooserGetCurDir(GFileChooser *gfc,int dirindex) {
661 GTextInfo **ti;
662 int32 len; int j, cnt;
663 unichar_t *dir, *pt;
664
665 ti = GGadgetGetList(&gfc->directories->g,&len);
666 if ( dirindex==-1 )
667 dirindex = 0;
668 dirindex = dirindex;
669
670 for ( j=len-1,cnt=0; j>=dirindex; --j ) {
671 if (ti[j]->userdata != NULL)
672 continue;
673 cnt += u_strlen(ti[j]->text)+1;
674 }
675 pt = dir = malloc((cnt+1)*sizeof(unichar_t));
676 for ( j=len-1; j>=dirindex; --j ) {
677 if (ti[j]->userdata != NULL)
678 continue;
679 u_strcpy(pt,ti[j]->text);
680 pt += u_strlen(pt);
681 if ( pt[-1]!='/' )
682 *pt++ = '/';
683 }
684 *pt = '\0';
685 return( dir );
686 }
687
GFileChooserRefresh(GFileChooser * gfc)688 static void GFileChooserRefresh(GFileChooser *gfc) {
689 unichar_t *dir;
690
691 dir = GFileChooserGetCurDir(gfc,-1);
692 GFileChooserScanDir(gfc,dir);
693 free(dir);
694 }
695
696 static void GFileChooserSetTitle(GGadget *g,const unichar_t *tit);
697
698 /* Handle events from the directory dropdown list */
GFileChooserDListChanged(GGadget * pl,GEvent * e)699 static int GFileChooserDListChanged(GGadget *pl,GEvent *e) {
700 GFileChooser *gfc;
701 int i;
702 unichar_t *dir;
703
704 if ( e->type!=et_controlevent || e->u.control.subtype!=et_listselected )
705 return( true );
706 i = GGadgetGetFirstListSelectedItem(pl);
707 if ( i==-1 )
708 return(true);
709 gfc = (GFileChooser *) GGadgetGetUserData(pl);
710 #ifdef _WIN32
711 int len;
712 GTextInfo **ti;
713 ti = GGadgetGetList(pl,&len);
714 if (ti[i]->userdata != NULL) {
715 GFileChooserSetTitle((GGadget*)gfc, ti[i]->text);
716 GFileChooserRefresh(gfc);
717 return( true );
718 }
719 #endif
720 if ( i==0 ) /* Nothing changed */
721 return( true );
722 dir = GFileChooserGetCurDir(gfc,i);
723 GFileChooserScanDir(gfc,dir);
724 free(dir);
725 return( true );
726 }
727
728 /* Handle events from the file list list */
GFileChooserFListSelected(GGadget * gl,GEvent * e)729 static int GFileChooserFListSelected(GGadget *gl,GEvent *e) {
730 GFileChooser *gfc;
731 int i;
732 int32 listlen; int len, cnt, dirpos, apos;
733 unichar_t *dir, *newdir;
734 GTextInfo *ti, **all;
735
736 if ( e->type!=et_controlevent ||
737 ( e->u.control.subtype!=et_listselected &&
738 e->u.control.subtype!=et_listdoubleclick ))
739 return( true );
740 if ( ((GList *) gl)->multiple_sel ) {
741 all = GGadgetGetList(gl,&listlen);
742 len = cnt = 0;
743 dirpos = apos = -1;
744 for ( i=0; i<listlen; ++i ) {
745 if ( !all[i]->selected )
746 /* Not selected? ignore it */;
747 else if ( all[i]->checked ) /* Directory */
748 dirpos = i;
749 else {
750 len += u_strlen( all[i]->text ) + 2;
751 ++cnt;
752 apos = i;
753 }
754 }
755 if ( dirpos!=-1 && cnt>0 ) {
756 /* If a directory was selected, clear everthing else */
757 for ( i=0; i<listlen; ++i ) if ( i!=dirpos )
758 all[i]->selected = false;
759 _ggadget_redraw(gl);
760 }
761 if ( dirpos!=-1 ) { cnt = 1; apos = dirpos; }
762 } else {
763 cnt = 1;
764 apos = GGadgetGetFirstListSelectedItem(gl);
765 }
766 if ( apos==-1 )
767 return(true);
768 gfc = (GFileChooser *) GGadgetGetUserData(gl);
769 ti = GGadgetGetListItem(gl,apos);
770 if ( e->u.control.subtype==et_listselected && cnt==1 ) {
771 /* Nope, quite doesn't work. Goal is to remember first filename. But */
772 /* if user types into the list box we'll (probably) get several diff*/
773 /* filenames before we hit the directory. So we just ignore the typ-*/
774 /* ing case for now. */
775 if ( ti->checked /* it's a directory */ && e->u.control.u.list.from_mouse &&
776 gfc->lastname==NULL )
777 gfc->lastname = GGadgetGetTitle(&gfc->name->g);
778 if ( ti->checked ) {
779 unichar_t *val = malloc((u_strlen(ti->text)+2)*sizeof(unichar_t));
780 u_strcpy(val,ti->text);
781 uc_strcat(val,"/");
782 GGadgetSetTitle(&gfc->name->g,val);
783 free(val);
784 if ( gfc->filterb!=NULL && gfc->ok!=NULL )
785 _GWidget_MakeDefaultButton(&gfc->filterb->g);
786 } else {
787 GGadgetSetTitle(&gfc->name->g,ti->text);
788 if ( gfc->filterb!=NULL && gfc->ok!=NULL )
789 _GWidget_MakeDefaultButton(&gfc->ok->g);
790 free(gfc->lastname);
791 gfc->lastname = NULL;
792 }
793 } else if ( e->u.control.subtype==et_listselected ) {
794 unichar_t *val, *upt = malloc((len+1)*sizeof(unichar_t));
795 val = upt;
796 for ( i=0; i<listlen; ++i ) {
797 if ( all[i]->selected ) {
798 u_strcpy(upt,all[i]->text);
799 upt += u_strlen(upt);
800 if ( --cnt>0 ) {
801 uc_strcpy(upt,"; ");
802 upt += 2;
803 }
804 }
805 }
806 GGadgetSetTitle(&gfc->name->g,val);
807 free(val);
808 } else if ( ti->checked /* it's a directory */ ) {
809 dir = GFileChooserGetCurDir(gfc,-1);
810 newdir = u_GFileAppendFile(dir,ti->text,true);
811 GFileChooserScanDir(gfc,newdir);
812 free(dir); free(newdir);
813 } else {
814 /* Post the double click (on a file) to the parent */
815 /* if we know what the ok button is then pretend it got pressed */
816 /* otherwise just send a list double click from ourselves */
817 if ( gfc->ok!=NULL ) {
818 e->u.control.subtype = et_buttonactivate;
819 e->u.control.g = &gfc->ok->g;
820 e->u.control.u.button.clicks = 0;
821 e->w = e->u.control.g->base;
822 } else
823 e->u.control.g = &gfc->g;
824 if ( e->u.control.g->handle_controlevent != NULL )
825 (e->u.control.g->handle_controlevent)(e->u.control.g,e);
826 else
827 GDrawPostEvent(e);
828 }
829 return( true );
830 }
831
GFCHideToggle(GWindow gw,struct gmenuitem * mi,GEvent * e)832 static void GFCHideToggle(GWindow gw,struct gmenuitem *mi,GEvent *e) {
833 GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
834 unichar_t *dir;
835
836 showhidden = !showhidden;
837
838 dir = GFileChooserGetCurDir(gfc,-1);
839 GFileChooserScanDir(gfc,dir);
840 free(dir);
841
842 if ( prefs_changed!=NULL )
843 (prefs_changed)(prefs_changed_data);
844 }
845
GFCRemetric(GFileChooser * gfc)846 static void GFCRemetric(GFileChooser *gfc) {
847 GRect size;
848
849 GGadgetGetSize(&gfc->topbox->g,&size);
850 GGadgetResize(&gfc->topbox->g,size.width,size.height);
851 }
852
GFCDirsAmidToggle(GWindow gw,struct gmenuitem * mi,GEvent * e)853 static void GFCDirsAmidToggle(GWindow gw,struct gmenuitem *mi,GEvent *e) {
854 GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
855 unichar_t *dir;
856
857 if ( dir_placement==dirs_separate ) {
858 GGadgetSetVisible(&gfc->subdirs->g,false);
859 GFCRemetric(gfc);
860 }
861 dir_placement = dirs_mixed;
862
863 dir = GFileChooserGetCurDir(gfc,-1);
864 GFileChooserScanDir(gfc,dir);
865 free(dir);
866
867 if ( prefs_changed!=NULL )
868 (prefs_changed)(prefs_changed_data);
869 }
870
GFCDirsFirstToggle(GWindow gw,struct gmenuitem * mi,GEvent * e)871 static void GFCDirsFirstToggle(GWindow gw,struct gmenuitem *mi,GEvent *e) {
872 GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
873 unichar_t *dir;
874
875 if ( dir_placement==dirs_separate ) {
876 GGadgetSetVisible(&gfc->subdirs->g,false);
877 GFCRemetric(gfc);
878 }
879 dir_placement = dirs_first;
880
881 dir = GFileChooserGetCurDir(gfc,-1);
882 GFileChooserScanDir(gfc,dir);
883 free(dir);
884
885 if ( prefs_changed!=NULL )
886 (prefs_changed)(prefs_changed_data);
887 }
888
GFCDirsSeparateToggle(GWindow gw,struct gmenuitem * mi,GEvent * e)889 static void GFCDirsSeparateToggle(GWindow gw,struct gmenuitem *mi,GEvent *e) {
890 GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
891 unichar_t *dir;
892
893 if ( dir_placement!=dirs_separate ) {
894 GGadgetSetVisible(&gfc->subdirs->g,true);
895 GFCRemetric(gfc);
896 }
897 dir_placement = dirs_separate;
898
899 dir = GFileChooserGetCurDir(gfc,-1);
900 GFileChooserScanDir(gfc,dir);
901 free(dir);
902
903 if ( prefs_changed!=NULL )
904 (prefs_changed)(prefs_changed_data);
905 }
906
GFCRefresh(GWindow gw,struct gmenuitem * mi,GEvent * e)907 static void GFCRefresh(GWindow gw,struct gmenuitem *mi,GEvent *e) {
908 GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
909 GFileChooserRefresh(gfc);
910 }
911
GFileChooserHome(GGadget * g,GEvent * e)912 static int GFileChooserHome(GGadget *g, GEvent *e) {
913 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
914 unichar_t* homedir = u_GFileGetHomeDocumentsDir();
915 if ( homedir==NULL )
916 GGadgetSetEnabled(g,false);
917 else {
918 GFileChooser *gfc = (GFileChooser *) GGadgetGetUserData(g);
919 GFileChooserScanDir(gfc,homedir);
920 free(homedir);
921 }
922 }
923 return( true );
924 }
925
GFileChooserUpDirButton(GGadget * g,GEvent * e)926 static int GFileChooserUpDirButton(GGadget *g, GEvent *e) {
927 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
928 GFileChooser *gfc = (GFileChooser *) GGadgetGetUserData(g);
929 unichar_t *dir, *newdir;
930 static unichar_t dotdot[] = { '.', '.', 0 };
931 dir = GFileChooserGetCurDir(gfc,-1);
932 newdir = u_GFileAppendFile(dir,dotdot,true);
933 GFileChooserScanDir(gfc,newdir);
934 free(dir); free(newdir);
935 }
936 return( true );
937 }
938
939 static GMenuItem gfcpopupmenu[] = {
940 { { (unichar_t *) N_("Show Hidden Files"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 1, 0, 0, 0, 1, 0, 0, 'H' }, '\0', ksm_control, NULL, NULL, GFCHideToggle, 0 },
941 { { (unichar_t *) N_("Directories Amid Files"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 1, 0, 0, 0, 1, 0, 0, 'H' }, '\0', ksm_control, NULL, NULL, GFCDirsAmidToggle, 0 },
942 { { (unichar_t *) N_("Directories First"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 1, 0, 0, 0, 1, 0, 0, 'H' }, '\0', ksm_control, NULL, NULL, GFCDirsFirstToggle, 0 },
943 { { (unichar_t *) N_("Directories Separate"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 1, 0, 0, 0, 1, 0, 0, 'H' }, '\0', ksm_control, NULL, NULL, GFCDirsSeparateToggle, 0 },
944 { { (unichar_t *) N_("Refresh File List"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, 'H' }, '\0', ksm_control, NULL, NULL, GFCRefresh, 0 },
945 GMENUITEM_EMPTY
946 };
947 static int gotten=false;
948
GFCPopupMenu(GGadget * g,GEvent * e)949 static void GFCPopupMenu(GGadget *g, GEvent *e) {
950 int i;
951 // The reason this casting works is a bit of a hack.
952 // If this was initiated from a right click, `g` will be the GFC GGadget.
953 // Then its userdata would be the initiator's, and NOT the GFC struct.
954 // Thus we cannot call GGadgetGetUserData.
955 // However, since in the GFC struct, its GGadget comes first, effectively
956 // the pointer to its GGadget will equal the pointer to its GFC struct.
957 // I have ensured that all calls to this function pass the GFC GGadget.
958 GFileChooser *gfc = (GFileChooser *) g;
959
960 for ( i=0; gfcpopupmenu[i].ti.text!=NULL || gfcpopupmenu[i].ti.line; ++i )
961 gfcpopupmenu[i].ti.userdata = gfc;
962 gfcpopupmenu[0].ti.checked = showhidden;
963 gfcpopupmenu[1].ti.checked = dir_placement == dirs_mixed;
964 gfcpopupmenu[2].ti.checked = dir_placement == dirs_first;
965 gfcpopupmenu[3].ti.checked = dir_placement == dirs_separate;
966 if ( !gotten ) {
967 gotten = true;
968 for ( i=0; gfcpopupmenu[i].ti.text!=NULL || gfcpopupmenu[i].ti.line; ++i )
969 gfcpopupmenu[i].ti.text = (unichar_t *) _( (char *) gfcpopupmenu[i].ti.text);
970 }
971 GMenuCreatePopupMenu(g->base,e, gfcpopupmenu);
972 }
973
GFileChooserConfigure(GGadget * g,GEvent * e)974 static int GFileChooserConfigure(GGadget *g, GEvent *e) {
975 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonpress ) {
976 GEvent fake;
977 GRect pos;
978 GGadgetGetSize(g,&pos);
979 memset(&fake,0,sizeof(fake));
980 fake.type = et_mousedown;
981 fake.w = g->base;
982 fake.u.mouse.x = pos.x;
983 fake.u.mouse.y = pos.y+pos.height;
984 GFCPopupMenu((GGadget*)GGadgetGetUserData(g),&fake);
985 }
986 return( true );
987 }
988
GFCBack(GWindow gw,struct gmenuitem * mi,GEvent * e)989 static void GFCBack(GWindow gw,struct gmenuitem *mi,GEvent *e) {
990 GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
991
992 if ( gfc->hpos<=0 )
993 return;
994 --gfc->hpos;
995 GFileChooserScanDir(gfc,gfc->history[gfc->hpos]);
996 }
997
GFCForward(GWindow gw,struct gmenuitem * mi,GEvent * e)998 static void GFCForward(GWindow gw,struct gmenuitem *mi,GEvent *e) {
999 GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
1000
1001 if ( gfc->hpos+1>=gfc->hcnt )
1002 return;
1003 ++gfc->hpos;
1004 GFileChooserScanDir(gfc,gfc->history[gfc->hpos]);
1005 }
1006
GFCAddCur(GWindow gw,struct gmenuitem * mi,GEvent * e)1007 static void GFCAddCur(GWindow gw,struct gmenuitem *mi,GEvent *e) {
1008 GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
1009 unichar_t *dir;
1010 int bcnt;
1011
1012 dir = GFileChooserGetCurDir(gfc,-1);
1013 bcnt = 0;
1014 if ( bookmarks!=NULL )
1015 for ( ; bookmarks[bcnt]!=NULL; ++bcnt );
1016 bookmarks = realloc(bookmarks,(bcnt+2)*sizeof(unichar_t *));
1017 bookmarks[bcnt] = dir;
1018 bookmarks[bcnt+1] = NULL;
1019
1020 if ( prefs_changed!=NULL )
1021 (prefs_changed)(prefs_changed_data);
1022 }
1023
GFCRemoveBook(GWindow gw,struct gmenuitem * mi,GEvent * e)1024 static void GFCRemoveBook(GWindow gw,struct gmenuitem *mi,GEvent *e) {
1025 int i,bcnt;
1026 char **books;
1027 char *sel;
1028 char *buts[2];
1029
1030 if ( bookmarks==NULL || bookmarks[0]==NULL )
1031 return; /* All gone */
1032 for ( bcnt=0; bookmarks[bcnt]!=NULL; ++bcnt );
1033 sel = calloc(bcnt,1);
1034 books = calloc(bcnt+1,sizeof(char *));
1035 for ( bcnt=0; bookmarks[bcnt]!=NULL; ++bcnt )
1036 books[bcnt] = u2utf8_copy(bookmarks[bcnt]);
1037 books[bcnt] = NULL;
1038 buts[0] = _("_Remove");
1039 buts[1] = _("_Cancel");
1040 if ( GWidgetChoicesBM8( _("Remove bookmarks"),(const char **) books,sel,bcnt,buts,
1041 _("Remove selected bookmarks"))==0 ) {
1042 for ( i=bcnt=0; bookmarks[bcnt]!=NULL; ++bcnt ) {
1043 if ( sel[bcnt] ) {
1044 free(bookmarks[bcnt]);
1045 } else {
1046 bookmarks[i++] = bookmarks[bcnt];
1047 }
1048 }
1049 bookmarks[i] = NULL;
1050
1051 if ( prefs_changed!=NULL )
1052 (prefs_changed)(prefs_changed_data);
1053 }
1054 for ( i=0; books[i]!=NULL; ++i )
1055 free(books[i]);
1056 free(books);
1057 free(sel);
1058 }
1059
GFCBookmark(GWindow gw,struct gmenuitem * mi,GEvent * e)1060 static void GFCBookmark(GWindow gw,struct gmenuitem *mi,GEvent *e) {
1061 GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
1062 char *home;
1063
1064 if ( *bookmarks[mi->mid]=='~' && bookmarks[mi->mid][1]=='/' &&
1065 (home = getenv("HOME"))!=NULL ) {
1066 unichar_t *space;
1067 space = malloc((strlen(home)+u_strlen(bookmarks[mi->mid])+2)*sizeof(unichar_t));
1068 uc_strcpy(space,home);
1069 u_strcat(space,bookmarks[mi->mid]+1);
1070 GFileChooserScanDir(gfc,space);
1071 free(space);
1072 } else
1073 GFileChooserScanDir(gfc,bookmarks[mi->mid]);
1074 }
1075
GFCPath(GWindow gw,struct gmenuitem * mi,GEvent * e)1076 static void GFCPath(GWindow gw,struct gmenuitem *mi,GEvent *e) {
1077 GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
1078 char *home;
1079
1080 if ( *gfc->paths[mi->mid]=='~' && gfc->paths[mi->mid][1]=='/' &&
1081 (home = getenv("HOME"))!=NULL ) {
1082 unichar_t *space;
1083 space = malloc((strlen(home)+u_strlen(bookmarks[mi->mid])+2)*sizeof(unichar_t));
1084 uc_strcpy(space,home);
1085 u_strcat(space,gfc->paths[mi->mid]+1);
1086 GFileChooserScanDir(gfc,space);
1087 free(space);
1088 } else
1089 GFileChooserScanDir(gfc,gfc->paths[mi->mid]);
1090 }
1091
1092 static GMenuItem gfcbookmarkmenu[] = {
1093 { { (unichar_t *) N_("Directory|Back"), &_GIcon_backarrow, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 0, 0, '\0' }, '\0', ksm_control, NULL, NULL, GFCBack, 0 },
1094 { { (unichar_t *) N_("Directory|Forward"), &_GIcon_forwardarrow, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 0, 0, '\0' }, '\0', ksm_control, NULL, NULL, GFCForward, 0 },
1095 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 1, 0, 0, 0, '\0' }, '\0', 0, NULL, NULL, NULL, 0 }, /* line */
1096 { { (unichar_t *) N_("Bookmark Current Dir"), &_GIcon_bookmark, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 0, 0, '\0' }, '\0', ksm_control, NULL, NULL, GFCAddCur, 0 },
1097 { { (unichar_t *) N_("Remove Bookmark..."), &_GIcon_nobookmark, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 0, 0, '\0' }, '\0', ksm_control, NULL, NULL, GFCRemoveBook, 0 },
1098 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 1, 0, 0, 0, '\0' }, '\0', 0, NULL, NULL, NULL, 0 }, /* line */
1099 GMENUITEM_EMPTY
1100 };
1101 static int bgotten=false;
1102
GFileChooserBookmarks(GGadget * g,GEvent * e)1103 static int GFileChooserBookmarks(GGadget *g, GEvent *e) {
1104 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonpress ) {
1105 GFileChooser *gfc = (GFileChooser *) GGadgetGetUserData(g);
1106 GMenuItem *mi;
1107 int i, bcnt, mcnt, pcnt;
1108 GEvent fake;
1109 GRect pos;
1110
1111 if ( !bgotten ) {
1112 bgotten = true;
1113 for ( i=0; gfcbookmarkmenu[i].ti.text!=NULL || gfcbookmarkmenu[i].ti.line; ++i )
1114 if ( gfcbookmarkmenu[i].ti.text!=NULL )
1115 gfcbookmarkmenu[i].ti.text = (unichar_t *) S_( (char *) gfcbookmarkmenu[i].ti.text);
1116 }
1117 for ( mcnt=0; gfcbookmarkmenu[mcnt].ti.text!=NULL || gfcbookmarkmenu[mcnt].ti.line; ++mcnt );
1118 bcnt = 0;
1119 if ( bookmarks!=NULL )
1120 for ( ; bookmarks[bcnt]!=NULL; ++bcnt );
1121 if ( gfc->paths!=NULL ) {
1122 for ( pcnt=0; gfc->paths[pcnt]!=NULL; ++pcnt );
1123 if ( pcnt!=0 && bcnt!=0 ) ++pcnt;
1124 bcnt += pcnt;
1125 }
1126 mi = calloc((mcnt+bcnt+1),sizeof(GMenuItem));
1127 for ( mcnt=0; gfcbookmarkmenu[mcnt].ti.text!=NULL || gfcbookmarkmenu[mcnt].ti.line; ++mcnt ) {
1128 mi[mcnt] = gfcbookmarkmenu[mcnt];
1129 mi[mcnt].ti.text = (unichar_t *) copy( (char *) mi[mcnt].ti.text);
1130 mi[mcnt].ti.userdata = gfc;
1131 }
1132 if ( gfc->hpos==0 )
1133 mi[0].ti.disabled = true; /* can't go further back */
1134 if ( gfc->hpos+1>=gfc->hcnt )
1135 mi[1].ti.disabled = true; /* can't go further forward */
1136 if ( bookmarks==NULL )
1137 mi[4].ti.disabled = true; /* can't remove bookmarks, already none */
1138 else {
1139 if ( gfc->paths!=NULL ) {
1140 for ( bcnt=0; gfc->paths[bcnt]!=NULL; ++bcnt ) {
1141 mi[mcnt+bcnt].ti.text = u_copy(gfc->paths[bcnt]);
1142 mi[mcnt+bcnt].ti.fg = mi[mcnt+bcnt].ti.bg = COLOR_DEFAULT;
1143 mi[mcnt+bcnt].ti.userdata = gfc;
1144 mi[mcnt+bcnt].mid = bcnt;
1145 mi[mcnt+bcnt].invoke = GFCPath;
1146 }
1147 mcnt+=bcnt;
1148 if ( bookmarks!=NULL && bookmarks[0]!=NULL ) {
1149 mi[mcnt].ti.line = true;
1150 mi[mcnt].ti.fg = mi[mcnt].ti.bg = COLOR_DEFAULT;
1151 ++mcnt;
1152 }
1153 }
1154 for ( bcnt=0; bookmarks[bcnt]!=NULL; ++bcnt ) {
1155 mi[mcnt+bcnt].ti.text = u_copy(bookmarks[bcnt]);
1156 mi[mcnt+bcnt].ti.fg = mi[mcnt+bcnt].ti.bg = COLOR_DEFAULT;
1157 mi[mcnt+bcnt].ti.userdata = gfc;
1158 mi[mcnt+bcnt].mid = bcnt;
1159 mi[mcnt+bcnt].invoke = GFCBookmark;
1160 }
1161 }
1162 GGadgetGetSize(g,&pos);
1163 memset(&fake,0,sizeof(fake));
1164 fake.type = et_mousedown;
1165 fake.w = g->base;
1166 fake.u.mouse.x = pos.x;
1167 fake.u.mouse.y = pos.y+pos.height;
1168 GMenuCreatePopupMenu(gfc->g.base,&fake, mi);
1169 GMenuItemArrayFree(mi);
1170 }
1171 return( true );
1172 }
1173
1174 /* Routine to be called as the mouse moves across the dlg */
GFileChooserPopupCheck(GGadget * g,GEvent * e)1175 void GFileChooserPopupCheck(GGadget *g,GEvent *e) {
1176 GFileChooser *gfc = (GFileChooser *) g;
1177 int inside=false;
1178
1179 if ( e->type == et_mousemove && (e->u.mouse.state&ksm_buttons)==0 ) {
1180 GGadgetEndPopup();
1181 for ( g=((GContainerD *) (gfc->g.base->widget_data))->gadgets; g!=NULL; g=g->prev ) {
1182 if ( g!=(GGadget *) gfc && g!=(GGadget *) (gfc->filterb) &&
1183 g!=(GGadget *) (gfc->files) &&
1184 g->takes_input &&
1185 e->u.mouse.x >= g->r.x &&
1186 e->u.mouse.x<g->r.x+g->r.width &&
1187 e->u.mouse.y >= g->r.y &&
1188 e->u.mouse.y<g->r.y+g->r.height ) {
1189 inside = true;
1190 break;
1191 }
1192 }
1193 if ( !inside )
1194 GGadgetPreparePopup(gfc->g.base,gfc->wildcard);
1195 } else if ( e->type == et_mousedown && e->u.mouse.button==3 ) {
1196 GFCPopupMenu(g,e);
1197 }
1198 }
1199
1200 /* Routine to be called by the filter button */
GFileChooserFilterIt(GGadget * g)1201 void GFileChooserFilterIt(GGadget *g) {
1202 GFileChooser *gfc = (GFileChooser *) g;
1203 unichar_t *pt, *spt, *slashpt, *dir, *temp;
1204 unichar_t *tofree = NULL;
1205 int wasdir;
1206
1207 wasdir = gfc->lastname!=NULL;
1208
1209 spt = (unichar_t *) _GGadgetGetTitle(&gfc->name->g);
1210 #ifdef _WIN32
1211 spt = tofree = u_GFileNormalizePath(u_copy(spt));
1212 #endif
1213 if ( *spt=='\0' ) { /* Werner tells me that pressing the Filter button with nothing should show the default filter mask */
1214 if ( gfc->wildcard!=NULL )
1215 GGadgetSetTitle(&gfc->name->g,gfc->wildcard);
1216 return;
1217 }
1218
1219 if (( slashpt = u_strrchr(spt,'/'))==NULL )
1220 slashpt = spt;
1221 else
1222 ++slashpt;
1223 pt = slashpt;
1224 while ( *pt && *pt!='*' && *pt!='?' && *pt!='[' && *pt!='{' )
1225 ++pt;
1226 if ( *pt!='\0' ) {
1227 free(gfc->wildcard);
1228 gfc->wildcard = u_copy(slashpt);
1229 } else if ( gfc->lastname==NULL )
1230 gfc->lastname = u_copy(slashpt);
1231 if( u_GFileIsAbsolute(spt) )
1232 dir = u_copyn(spt,slashpt-spt);
1233 else {
1234 unichar_t *curdir = GFileChooserGetCurDir(gfc,-1);
1235 if ( slashpt!=spt ) {
1236 temp = u_copyn(spt,slashpt-spt);
1237 dir = u_GFileAppendFile(curdir,temp,true);
1238 free(temp);
1239 } else if ( wasdir && *pt=='\0' )
1240 dir = u_GFileAppendFile(curdir,spt,true);
1241 else
1242 dir = curdir;
1243 if ( dir!=curdir )
1244 free(curdir);
1245 }
1246 GFileChooserScanDir(gfc,dir);
1247 free(dir);
1248 free(tofree);
1249 }
1250
1251 /* A function that may be connected to a filter button as its handle_controlevent */
GFileChooserFilterEh(GGadget * g,GEvent * e)1252 int GFileChooserFilterEh(GGadget *g, GEvent *e) {
1253 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate )
1254 GFileChooserFilterIt(GGadgetGetUserData(g));
1255 return( true );
1256 }
1257
GFileChooserConnectButtons(GGadget * g,GGadget * ok,GGadget * filter)1258 void GFileChooserConnectButtons(GGadget *g,GGadget *ok, GGadget *filter) {
1259 GFileChooser *gfc = (GFileChooser *) g;
1260 gfc->ok = (GButton *) ok;
1261 gfc->filterb = (GButton *) filter;
1262 }
1263
GFileChooserSetFilterText(GGadget * g,const unichar_t * wildcard)1264 void GFileChooserSetFilterText(GGadget *g,const unichar_t *wildcard) {
1265 GFileChooser *gfc = (GFileChooser *) g;
1266 free(gfc->wildcard);
1267 gfc->wildcard = u_copy(wildcard);
1268 }
1269
GFileChooserGetFilterText(GGadget * g)1270 unichar_t *GFileChooserGetFilterText(GGadget *g) {
1271 GFileChooser *gfc = (GFileChooser *) g;
1272 return( gfc->wildcard );
1273 }
1274
GFileChooserSetFilterFunc(GGadget * g,GFileChooserFilterType filter)1275 void GFileChooserSetFilterFunc(GGadget *g,GFileChooserFilterType filter) {
1276 GFileChooser *gfc = (GFileChooser *) g;
1277 if ( filter==NULL )
1278 filter = GFileChooserDefFilter;
1279 gfc->filter = filter;
1280 }
1281
GFileChooserGetFilterFunc(GGadget * g)1282 GFileChooserFilterType GFileChooserGetFilterFunc(GGadget *g) {
1283 GFileChooser *gfc = (GFileChooser *) g;
1284 return( gfc->filter );
1285 }
1286
1287 /**
1288 * no change to the current filename by default
1289 *
1290 * if a change is desired, then currentFilename should point to the
1291 * new string and return 1 to allow the caller to free this new
1292 * string.
1293 */
GFileChooserDefInputFilenameFunc(GGadget * g,const unichar_t ** currentFilename,unichar_t * oldfilename)1294 int GFileChooserDefInputFilenameFunc( GGadget *g,
1295 const unichar_t ** currentFilename,
1296 unichar_t* oldfilename ) {
1297 return 0;
1298 }
1299
GFileChooserSetInputFilenameFunc(GGadget * g,GFileChooserInputFilenameFuncType func)1300 void GFileChooserSetInputFilenameFunc(GGadget *g,GFileChooserInputFilenameFuncType func) {
1301 GFileChooser *gfc = (GFileChooser *) g;
1302 if ( func==NULL )
1303 func = GFileChooserDefInputFilenameFunc;
1304 gfc->inputfilenamefunc = func;
1305 }
1306
GFileChooserGetInputFilenameFunc(GGadget * g)1307 GFileChooserInputFilenameFuncType GFileChooserGetInputFilenameFunc(GGadget *g) {
1308 GFileChooser *gfc = (GFileChooser *) g;
1309 if ( gfc->inputfilenamefunc==NULL )
1310 return GFileChooserDefInputFilenameFunc;
1311 return( gfc->inputfilenamefunc );
1312 }
1313
1314
GFileChooserSetFilename(GGadget * g,const unichar_t * defaultfile)1315 void GFileChooserSetFilename(GGadget *g,const unichar_t *defaultfile)
1316 {
1317 GFileChooser *gfc = (GFileChooser *) g;
1318
1319 GGadgetSetTitle(g,defaultfile);
1320
1321 // if this is the first time we are here, we assume
1322 // the current filename is what it was before. Less NULL
1323 // checks in the callback function below.
1324 if(!gfc->inputfilenameprevchar)
1325 gfc->inputfilenameprevchar = u_copy(_GGadgetGetTitle(&gfc->name->g));
1326
1327 }
1328
1329
GFileChooserSetMimetypes(GGadget * g,unichar_t ** mimetypes)1330 void GFileChooserSetMimetypes(GGadget *g,unichar_t **mimetypes) {
1331 GFileChooser *gfc = (GFileChooser *) g;
1332 int i;
1333
1334 if ( gfc->mimetypes ) {
1335 for ( i=0; gfc->mimetypes[i]!=NULL; ++i )
1336 free( gfc->mimetypes[i]);
1337 free(gfc->mimetypes);
1338 }
1339 if ( mimetypes ) {
1340 for ( i=0; mimetypes[i]!=NULL; ++i );
1341 gfc->mimetypes = malloc((i+1)*sizeof(unichar_t *));
1342 for ( i=0; mimetypes[i]!=NULL; ++i )
1343 gfc->mimetypes[i] = u_copy(mimetypes[i]);
1344 gfc->mimetypes[i] = NULL;
1345 } else
1346 gfc->mimetypes = NULL;
1347 }
1348
GFileChooserGetMimetypes(GGadget * g)1349 unichar_t **GFileChooserGetMimetypes(GGadget *g) {
1350 GFileChooser *gfc = (GFileChooser *) g;
1351 return( gfc->mimetypes );
1352 }
1353
1354 /* Change the current file, or the current directory/file */
GFileChooserSetTitle(GGadget * g,const unichar_t * tit)1355 static void GFileChooserSetTitle(GGadget *g,const unichar_t *tit) {
1356 GFileChooser *gfc = (GFileChooser *) g;
1357 unichar_t *pt, *curdir, *temp, *dir, *base;
1358
1359 if ( tit==NULL ) {
1360 curdir = GFileChooserGetCurDir(gfc,-1);
1361 GFileChooserScanDir(gfc,curdir);
1362 free(curdir);
1363 return;
1364 }
1365
1366 pt = u_strrchr(tit,'/');
1367 free(gfc->lastname);
1368 gfc->lastname = NULL;
1369
1370 if ( u_GFileIsAbsolute(tit) ){
1371 base = uc_strstr(tit, "://");
1372 if(!base) base = (unichar_t*) tit;
1373 if(pt > base && pt[1] && (pt[1]!='.' || pt[2]!='\0')){
1374 gfc->lastname = u_copy(pt+1);
1375 dir = u_copyn(tit, pt-tit);
1376 }
1377 else{
1378 dir = u_copy(tit);
1379 }
1380 GFileChooserScanDir(gfc,dir);
1381 free(dir);
1382 } else if ( pt==NULL ) {
1383 GGadgetSetTitle(&gfc->name->g,tit);
1384 curdir = GFileChooserGetCurDir(gfc,-1);
1385 GFileChooserScanDir(gfc,curdir);
1386 free(curdir);
1387 } else {
1388 curdir = GFileChooserGetCurDir(gfc,-1);
1389 temp = u_copyn(tit,pt-tit);
1390 dir = u_GFileAppendFile(curdir,temp,true);
1391 free(temp); free(curdir);
1392 free(gfc->lastname);
1393 if ( pt[1]!='\0' )
1394 gfc->lastname = u_copy(pt+1);
1395 GFileChooserScanDir(gfc,dir);
1396 free(dir);
1397 }
1398 }
1399
GFileChooserRefreshList(GGadget * g)1400 void GFileChooserRefreshList(GGadget *g) {
1401 GFileChooser *gfc = (GFileChooser *) g;
1402 unichar_t *curdir;
1403
1404 curdir = GFileChooserGetCurDir(gfc,-1);
1405 GFileChooserScanDir(gfc,curdir);
1406 free(curdir);
1407 }
1408
1409 /* Get the current directory/file */
GFileChooserGetTitle(GGadget * g)1410 static unichar_t *GFileChooserGetTitle(GGadget *g) {
1411 GFileChooser *gfc = (GFileChooser *) g;
1412 unichar_t *spt, *curdir, *file;
1413
1414 spt = u_GFileNormalizePath(u_copy((unichar_t *)_GGadgetGetTitle(&gfc->name->g)));
1415 if ( u_GFileIsAbsolute(spt) )
1416 file = spt;
1417 else {
1418 curdir = GFileChooserGetCurDir(gfc,-1);
1419 file = u_GFileAppendFile(curdir,spt,gfc->lastname!=NULL);
1420 free(curdir);
1421 }
1422 if (file != spt) {
1423 free(spt);
1424 }
1425 return( file );
1426 }
1427
GFileChooser_destroy(GGadget * g)1428 static void GFileChooser_destroy(GGadget *g) {
1429 GFileChooser *gfc = (GFileChooser *) g;
1430 int i;
1431
1432 free(lastdir);
1433 lastdir = GFileChooserGetCurDir(gfc,-1);
1434
1435 if ( gfc->outstanding )
1436 GIOcancel(gfc->outstanding);
1437 GGadgetDestroy(&gfc->topbox->g); /* destroys everything */
1438 if ( gfc->paths!=NULL ) {
1439 for ( i=0; gfc->paths[i]!=NULL; ++i )
1440 free(gfc->paths[i]);
1441 free(gfc->paths);
1442 }
1443 free(gfc->wildcard);
1444 free(gfc->lastname);
1445 if ( gfc->mimetypes ) {
1446 for ( i=0; gfc->mimetypes[i]!=NULL; ++i )
1447 free( gfc->mimetypes[i]);
1448 free(gfc->mimetypes);
1449 }
1450 for ( i=0; i<gfc->hcnt; ++i )
1451 free(gfc->history[i]);
1452 free(gfc->history);
1453 _ggadget_destroy(&gfc->g);
1454 }
1455
gfilechooser_expose(GWindow pixmap,GGadget * g,GEvent * event)1456 static int gfilechooser_expose(GWindow pixmap, GGadget *g, GEvent *event) {
1457 return( true );
1458 }
1459
gfilechooser_mouse(GGadget * g,GEvent * event)1460 static int gfilechooser_mouse(GGadget *g, GEvent *event) {
1461 GFileChooser *gfc = (GFileChooser *) g;
1462
1463 if (( event->type==et_mouseup || event->type==et_mousedown ) &&
1464 (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
1465 if ( gfc->files->vsb!=NULL )
1466 return( GGadgetDispatchEvent(&gfc->files->vsb->g,event));
1467 else
1468 return( true );
1469 }
1470
1471 return( false );
1472 }
1473
gfilechooser_noop(GGadget * g,GEvent * event)1474 static int gfilechooser_noop(GGadget *g, GEvent *event) {
1475 return( false );
1476 }
1477
gfilechooser_timer(GGadget * g,GEvent * event)1478 static int gfilechooser_timer(GGadget *g, GEvent *event) {
1479 return( false );
1480 }
1481
gfilechooser_move(GGadget * g,int32 x,int32 y)1482 static void gfilechooser_move(GGadget *g, int32 x, int32 y ) {
1483 GFileChooser *gfc = (GFileChooser *) g;
1484
1485 GGadgetMove(&gfc->topbox->g,x,y);
1486 _ggadget_move(g,x,y);
1487 }
1488
gfilechooser_resize(GGadget * g,int32 width,int32 height)1489 static void gfilechooser_resize(GGadget *g, int32 width, int32 height ) {
1490 GFileChooser *gfc = (GFileChooser *) g;
1491
1492 GGadgetResize(&gfc->topbox->g,width,height);
1493 _ggadget_resize(g,width,height);
1494 }
1495
gfilechooser_setvisible(GGadget * g,int visible)1496 static void gfilechooser_setvisible(GGadget *g, int visible ) {
1497 GFileChooser *gfc = (GFileChooser *) g;
1498 GGadgetSetVisible(&gfc->files->g,visible);
1499 GGadgetSetVisible(&gfc->directories->g,visible);
1500 GGadgetSetVisible(&gfc->name->g,visible);
1501 GGadgetSetVisible(&gfc->up->g,visible);
1502 GGadgetSetVisible(&gfc->home->g,visible);
1503 GGadgetSetVisible(&gfc->bookmarks->g,visible);
1504 GGadgetSetVisible(&gfc->config->g,visible);
1505 GGadgetSetVisible(&gfc->topbox->g,visible);
1506 _ggadget_setvisible(g,visible);
1507 }
1508
gfilechooser_setenabled(GGadget * g,int enabled)1509 static void gfilechooser_setenabled(GGadget *g, int enabled ) {
1510 GFileChooser *gfc = (GFileChooser *) g;
1511 GGadgetSetEnabled(&gfc->files->g,enabled);
1512 GGadgetSetEnabled(&gfc->subdirs->g,enabled);
1513 GGadgetSetEnabled(&gfc->directories->g,enabled);
1514 GGadgetSetEnabled(&gfc->name->g,enabled);
1515 GGadgetSetEnabled(&gfc->up->g,enabled);
1516 GGadgetSetEnabled(&gfc->home->g,enabled);
1517 GGadgetSetEnabled(&gfc->bookmarks->g,enabled);
1518 GGadgetSetEnabled(&gfc->config->g,enabled);
1519 GGadgetSetEnabled(&gfc->topbox->g,enabled);
1520 _ggadget_setenabled(g,enabled);
1521 }
1522
GFileChooserGetDesiredSize(GGadget * g,GRect * outer,GRect * inner)1523 static void GFileChooserGetDesiredSize(GGadget *g,GRect *outer,GRect *inner) {
1524 if ( inner!=NULL ) {
1525 int bp = GBoxBorderWidth(g->base,g->box);
1526 inner->x = inner->y = 0;
1527 inner->width = g->desired_width - 2*bp;
1528 inner->height = g->desired_height - 2*bp;
1529 }
1530 if ( outer!=NULL ) {
1531 outer->x = outer->y = 0;
1532 outer->width = g->desired_width;
1533 outer->height = g->desired_height;
1534 }
1535 }
1536
gfilechooser_FillsWindow(GGadget * g)1537 static int gfilechooser_FillsWindow(GGadget *g) {
1538 return( g->prev==NULL &&
1539 (_GWidgetGetGadgets(g->base)==g ||
1540 _GWidgetGetGadgets(g->base)==(GGadget *) ((GFileChooser *) g)->up ));
1541 }
1542
1543 struct gfuncs GFileChooser_funcs = {
1544 0,
1545 sizeof(struct gfuncs),
1546
1547 gfilechooser_expose,
1548 gfilechooser_mouse,
1549 gfilechooser_noop,
1550 NULL,
1551 NULL,
1552 gfilechooser_timer,
1553 NULL,
1554
1555 _ggadget_redraw,
1556 gfilechooser_move,
1557 gfilechooser_resize,
1558 gfilechooser_setvisible,
1559 gfilechooser_setenabled,
1560 _ggadget_getsize,
1561 _ggadget_getinnersize,
1562
1563 GFileChooser_destroy,
1564
1565 GFileChooserSetTitle,
1566 NULL,
1567 GFileChooserGetTitle,
1568 NULL,
1569 NULL,
1570 NULL,
1571 NULL,
1572 NULL,
1573
1574 NULL,
1575 NULL,
1576 NULL,
1577 NULL,
1578 NULL,
1579 NULL,
1580 NULL,
1581 NULL,
1582 NULL,
1583 NULL,
1584
1585 GFileChooserGetDesiredSize,
1586 _ggadget_setDesiredSize,
1587 gfilechooser_FillsWindow,
1588 NULL
1589 };
1590
GFileChooserCreateChildren(GFileChooser * gfc,int flags)1591 static void GFileChooserCreateChildren(GFileChooser *gfc, int flags) {
1592 GGadgetCreateData gcd[9], boxes[4], *varray[9], *harray[12], *harray2[4];
1593 GTextInfo label[9];
1594 int k=0, l=0, homek, upk, bookk, confk, dirsk, subdirsk, filesk, textk;
1595
1596 memset(&gcd,'\0',sizeof(gcd));
1597 memset(&boxes,'\0',sizeof(boxes));
1598 memset(&label,'\0',sizeof(label));
1599
1600 gcd[k].gd.flags = gg_visible|gg_enabled;
1601 gcd[k].gd.popup_msg = _("Home Folder");
1602 label[k].image = &_GIcon_homefolder;
1603 gcd[k].gd.label = &label[k];
1604 gcd[k].gd.handle_controlevent = GFileChooserHome;
1605 homek = k;
1606 gcd[k++].creator = GButtonCreate;
1607 harray[l++] = &gcd[k-1]; harray[l++] = GCD_Glue;
1608
1609 gcd[k].gd.flags = gg_visible|gg_enabled;
1610 gcd[k].gd.popup_msg = _("Bookmarks");
1611 label[k].image = &_GIcon_bookmark;
1612 gcd[k].gd.label = &label[k];
1613 gcd[k].gd.handle_controlevent = GFileChooserBookmarks;
1614 bookk = k;
1615 gcd[k++].creator = GButtonCreate;
1616 harray[l++] = &gcd[k-1]; harray[l++] = GCD_Glue;
1617
1618 gcd[k].gd.flags = gg_visible|gg_enabled|gg_list_exactlyone;
1619 gcd[k].gd.handle_controlevent = GFileChooserDListChanged;
1620 dirsk = k;
1621 gcd[k++].creator = GListButtonCreate;
1622 harray[l++] = &gcd[k-1]; harray[l++] = GCD_Glue;
1623
1624 gcd[k].gd.flags = gg_visible|gg_enabled;
1625 gcd[k].gd.popup_msg = _("Parent Folder");
1626 label[k].image = &_GIcon_updir;
1627 gcd[k].gd.label = &label[k];
1628 gcd[k].gd.handle_controlevent = GFileChooserUpDirButton;
1629 upk = k;
1630 gcd[k++].creator = GButtonCreate;
1631 harray[l++] = &gcd[k-1]; harray[l++] = GCD_Glue;
1632
1633 gcd[k].gd.flags = gg_visible|gg_enabled;
1634 gcd[k].gd.popup_msg = _("Configure");
1635 label[k].image = &_GIcon_configtool;
1636 gcd[k].gd.label = &label[k];
1637 gcd[k].gd.handle_controlevent = GFileChooserConfigure;
1638 confk = k;
1639 gcd[k++].creator = GButtonCreate;
1640 harray[l++] = &gcd[k-1]; harray[l++] = NULL;
1641
1642 boxes[2].gd.flags = gg_enabled|gg_visible;
1643 boxes[2].gd.u.boxelements = harray;
1644 boxes[2].creator = GHBoxCreate;
1645
1646 l=0;
1647 varray[l++] = &boxes[2];
1648
1649 if ( dir_placement==dirs_separate )
1650 gcd[k].gd.flags = gg_visible|gg_enabled|gg_list_alphabetic|gg_list_exactlyone;
1651 else
1652 gcd[k].gd.flags = gg_enabled|gg_list_alphabetic|gg_list_exactlyone;
1653 gcd[k].gd.handle_controlevent = GFileChooserFListSelected;
1654 subdirsk = k;
1655 gcd[k++].creator = GListCreate;
1656 harray2[0] = &gcd[k-1];
1657
1658 if ( flags & gg_file_multiple )
1659 gcd[k].gd.flags = gg_visible|gg_enabled|gg_list_alphabetic|gg_list_multiplesel;
1660 else
1661 gcd[k].gd.flags = gg_visible|gg_enabled|gg_list_alphabetic|gg_list_exactlyone;
1662 gcd[k].gd.handle_controlevent = GFileChooserFListSelected;
1663 filesk = k;
1664 gcd[k++].creator = GListCreate;
1665 harray2[1] = &gcd[k-1]; harray2[2] = NULL;
1666
1667 boxes[3].gd.flags = gg_enabled|gg_visible;
1668 boxes[3].gd.u.boxelements = harray2;
1669 boxes[3].creator = GHBoxCreate;
1670 varray[l++] = &boxes[3];
1671
1672 gcd[k].gd.flags = gg_visible|gg_enabled;
1673 gcd[k].gd.handle_controlevent = GFileChooserTextChanged;
1674 textk = k;
1675 if ( flags&gg_file_pulldown )
1676 gcd[k++].creator = GListFieldCreate;
1677 else
1678 gcd[k++].creator = GTextCompletionCreate;
1679 varray[l++] = &gcd[k-1]; varray[l] = NULL;
1680
1681 boxes[0].gd.pos.x = gfc->g.r.x;
1682 boxes[0].gd.pos.y = gfc->g.r.y;
1683 boxes[0].gd.pos.width = gfc->g.r.width;
1684 boxes[0].gd.pos.height = gfc->g.r.height;
1685 boxes[0].gd.flags = gg_enabled|gg_visible;
1686 boxes[0].gd.u.boxelements = varray;
1687 boxes[0].creator = GVBoxCreate;
1688
1689 for ( l=0; l<k; ++l )
1690 gcd[l].data = gfc;
1691
1692 GGadgetsCreate(gfc->g.base,boxes);
1693
1694 gfc->topbox = (GHVBox *) boxes[0].ret;
1695 gfc->home = (GButton *) gcd[homek].ret;
1696 gfc->bookmarks = (GButton *) gcd[bookk].ret;
1697 gfc->directories = (GListButton *) gcd[dirsk].ret;
1698 gfc->up = (GButton *) gcd[upk ].ret;
1699 gfc->config = (GButton *) gcd[confk].ret;
1700 gfc->subdirs = (GList *) gcd[subdirsk].ret;
1701 gfc->files = (GList *) gcd[filesk].ret;
1702 gfc->name = (GTextField *) gcd[textk].ret;
1703
1704 gfc->home->g.contained = true;
1705 gfc->bookmarks->g.contained = true;
1706 gfc->directories->g.contained = true;
1707 gfc->up->g.contained = true;
1708 gfc->config->g.contained = true;
1709 gfc->subdirs->g.contained = true;
1710 gfc->files->g.contained = true;
1711 gfc->name->g.contained = true;
1712 gfc->topbox->g.contained = true;
1713
1714 GCompletionFieldSetCompletion(&gfc->name->g,GFileChooserCompletion);
1715 GCompletionFieldSetCompletionMode(&gfc->name->g,true);
1716
1717 GHVBoxSetExpandableRow(boxes[0].ret,1);
1718 GHVBoxSetExpandableCol(boxes[2].ret,4);
1719 if ( boxes[0].gd.pos.width!=0 && boxes[0].gd.pos.height!=0 )
1720 GGadgetResize(boxes[0].ret,boxes[0].gd.pos.width,boxes[0].gd.pos.height);
1721 }
1722
GFileChooserCreate(struct gwindow * base,GGadgetData * gd,void * data)1723 GGadget *GFileChooserCreate(struct gwindow *base, GGadgetData *gd,void *data) {
1724 GFileChooser *gfc = (GFileChooser *) calloc(1,sizeof(GFileChooser));
1725
1726 gfc->g.funcs = &GFileChooser_funcs;
1727 _GGadget_Create(&gfc->g,base,gd,data,&gfilechooser_box);
1728 gfc->g.takes_input = gfc->g.takes_keyboard = false; gfc->g.focusable = false;
1729 if ( gfc->g.r.width == 0 )
1730 gfc->g.r.width = GGadgetScale(GDrawPointsToPixels(base,140));
1731 if ( gfc->g.r.height == 0 )
1732 gfc->g.r.height = GDrawPointsToPixels(base,100);
1733 gfc->g.desired_width = gfc->g.r.width;
1734 gfc->g.desired_height = gfc->g.r.height;
1735 gfc->g.inner = gfc->g.r;
1736 _GGadget_FinalPosition(&gfc->g,base,gd);
1737
1738 GFileChooserCreateChildren(gfc, gd->flags);
1739 gfc->filter = GFileChooserDefFilter;
1740 GFileChooserSetInputFilenameFunc( (GGadget*)gfc, 0 );
1741 if ( gd->flags & gg_group_end )
1742 _GGadgetCloseGroup(&gfc->g);
1743
1744 if ( lastdir==NULL ) {
1745 static unichar_t dot[] = { '.', '\0' };
1746 unichar_t buffer[1025];
1747 lastdir = u_copy(u_GFileGetAbsoluteName(dot,buffer,sizeof(buffer)/sizeof(unichar_t)));
1748 }
1749 if ( gd->label==NULL || gd->label->text==NULL )
1750 GFileChooserSetTitle(&gfc->g,lastdir);
1751 else if ( u_GFileIsAbsolute(gd->label->text) )
1752 GFileChooserSetTitle(&gfc->g,gd->label->text);
1753 else {
1754 unichar_t *temp = u_GFileAppendFile(lastdir,gd->label->text,false);
1755 temp = u_GFileNormalize(temp);
1756 GFileChooserSetTitle(&gfc->g,temp);
1757 free(temp);
1758 }
1759
1760 return( &gfc->g );
1761 }
1762
GFileChooserSetDir(GGadget * g,unichar_t * dir)1763 void GFileChooserSetDir(GGadget *g,unichar_t *dir) {
1764 GFileChooserScanDir((GFileChooser *) g,dir);
1765 }
1766
GFileChooserGetDir(GGadget * g)1767 unichar_t *GFileChooserGetDir(GGadget *g) {
1768 return( GFileChooserGetCurDir((GFileChooser *) g,-1));
1769 }
1770
GFileChooserReplaceIO(GGadget * g,GIOControl * gc)1771 GIOControl *GFileChooserReplaceIO(GGadget *g,GIOControl *gc) {
1772 GFileChooser *gfc = (GFileChooser *)g;
1773
1774 if ( gfc->outstanding!=NULL ) {
1775 GIOclose(gfc->outstanding);
1776 gfc->outstanding = NULL;
1777 GDrawSetCursor(gfc->g.base,gfc->old_cursor);
1778 }
1779 if ( gc!=NULL ) {
1780 gfc->old_cursor = GDrawGetCursor(gfc->g.base);
1781 GDrawSetCursor(gfc->g.base,ct_watch);
1782 gfc->outstanding = gc;
1783 }
1784 return( gc );
1785 }
1786
GFileChooserGetChildren(GGadget * g,GGadget ** pulldown,GGadget ** list,GGadget ** tf)1787 void GFileChooserGetChildren(GGadget *g,GGadget **pulldown, GGadget **list, GGadget **tf) {
1788 GFileChooser *gfc = (GFileChooser *)g;
1789
1790 if ( pulldown!=NULL ) *pulldown = &gfc->directories->g;
1791 if ( tf!=NULL ) *tf = &gfc->name->g;
1792 if ( list!=NULL ) *list = &gfc->files->g;
1793 }
1794
GFileChooserPosIsDir(GGadget * g,int pos)1795 int GFileChooserPosIsDir(GGadget *g, int pos) {
1796 GFileChooser *gfc = (GFileChooser *)g;
1797 GGadget *list = &gfc->files->g;
1798 GTextInfo *ti;
1799
1800 ti = GGadgetGetListItem(list,pos);
1801 if ( ti==NULL )
1802 return( false );
1803
1804 return( ti->checked );
1805 }
1806
GFileChooserFileNameOfPos(GGadget * g,int pos)1807 unichar_t *GFileChooserFileNameOfPos(GGadget *g, int pos) {
1808 GFileChooser *gfc = (GFileChooser *)g;
1809 GGadget *list = &gfc->files->g;
1810 GTextInfo *ti;
1811 unichar_t *curdir, *file;
1812
1813 ti = GGadgetGetListItem(list,pos);
1814 if ( ti==NULL )
1815 return( NULL );
1816
1817 curdir = GFileChooserGetCurDir(gfc,-1);
1818 file = u_GFileAppendFile(curdir,ti->text,false);
1819 free(curdir);
1820 return( file );
1821 }
1822
GFileChooserSetShowHidden(int sh)1823 void GFileChooserSetShowHidden(int sh) {
1824 showhidden = sh;
1825 }
1826
GFileChooserGetShowHidden(void)1827 int GFileChooserGetShowHidden(void) {
1828 return( showhidden );
1829 }
1830
GFileChooserSetDirectoryPlacement(int dp)1831 void GFileChooserSetDirectoryPlacement(int dp) {
1832 dir_placement = dp;
1833 }
1834
GFileChooserGetDirectoryPlacement(void)1835 int GFileChooserGetDirectoryPlacement(void) {
1836 return( dir_placement );
1837 }
1838
GFileChooserSetBookmarks(unichar_t ** b)1839 void GFileChooserSetBookmarks(unichar_t **b) {
1840 if ( bookmarks!=NULL && bookmarks!=b ) {
1841 int i;
1842
1843 for ( i=0; bookmarks[i]!=NULL; ++i )
1844 free(bookmarks[i]);
1845 free(bookmarks);
1846 }
1847 bookmarks = b;
1848 }
1849
GFileChooserGetBookmarks(void)1850 unichar_t **GFileChooserGetBookmarks(void) {
1851 return( bookmarks );
1852 }
1853
GFileChooserSetPrefsChangedCallback(void * data,void (* p_c)(void *))1854 void GFileChooserSetPrefsChangedCallback(void *data, void (*p_c)(void *)) {
1855 prefs_changed = p_c;
1856 prefs_changed_data = data;
1857 }
1858
GFileChooserSetPaths(GGadget * g,const char * const * path)1859 void GFileChooserSetPaths(GGadget *g, const char* const* path) {
1860 unichar_t **dirs = NULL;
1861 int dcnt;
1862 GFileChooser *gfc = (GFileChooser *) g;
1863
1864 if ( gfc->paths!=NULL ) {
1865 for ( dcnt=0; gfc->paths[dcnt]!=NULL; ++dcnt )
1866 free( gfc->paths[dcnt] );
1867 free(gfc->paths);
1868 gfc->paths = NULL;
1869 }
1870 if ( path==NULL || path[0]==NULL )
1871 return;
1872
1873 for ( dcnt=0; path[dcnt]!=NULL; ++dcnt );
1874 gfc->paths = dirs = malloc((dcnt+1)*sizeof(unichar_t *));
1875 for ( dcnt=0; path[dcnt]!=NULL; ++dcnt )
1876 dirs[dcnt] = utf82u_copy(path[dcnt]);
1877 dirs[dcnt] = NULL;
1878 }
1879