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 <fontforge-config.h>
29 
30 #include "gdraw.h"
31 #include "gfile.h"
32 #include "ggadget.h"
33 #include "ggadgetP.h"
34 #include "gicons.h"
35 #include "gio.h"
36 #include "gwidget.h"
37 #include "ustring.h"
38 
39 struct gfc_data {
40     int done;
41     unichar_t *ret;
42     GGadget *gfc;
43 };
44 
GFD_doesnt(GIOControl * gio)45 static void GFD_doesnt(GIOControl *gio) {
46     /* The filename the user chose doesn't exist, so everything is happy */
47     struct gfc_data *d = gio->userdata;
48     d->done = true;
49     GFileChooserReplaceIO(d->gfc,NULL);
50 }
51 
GFD_exists(GIOControl * gio)52 static void GFD_exists(GIOControl *gio) {
53     /* The filename the user chose exists, ask user if s/he wants to overwrite */
54     struct gfc_data *d = gio->userdata;
55 
56     if ( !_ggadget_use_gettext ) {
57 	const unichar_t *rcb[3]; unichar_t rcmn[2];
58     unichar_t buffer[200];
59 	rcb[2]=NULL;
60 	rcb[0] = GStringGetResource( _STR_Replace, &rcmn[0]);
61 	rcb[1] = GStringGetResource( _STR_Cancel, &rcmn[1]);
62 
63 	u_strcpy(buffer, GStringGetResource(_STR_Fileexistspre,NULL));
64 	u_strcat(buffer, u_GFileNameTail(d->ret));
65 	u_strcat(buffer, GStringGetResource(_STR_Fileexistspost,NULL));
66 	if ( GWidgetAsk(GStringGetResource(_STR_Fileexists,NULL),rcb,rcmn,0,1,buffer)==0 ) {
67 	    d->done = true;
68 	}
69     } else {
70 	const char *rcb[3];
71 	char *temp;
72 	rcb[2]=NULL;
73 	rcb[0] = _("Replace");
74 	rcb[1] = _("Cancel");
75 
76 	if ( GWidgetAsk8(_("File Exists"),rcb,0,1,_("File, %s, exists. Replace it?"),
77 		temp = u2utf8_copy(u_GFileNameTail(d->ret)))==0 ) {
78 	    d->done = true;
79 	}
80 	free(temp);
81     }
82     GFileChooserReplaceIO(d->gfc,NULL);
83 }
84 
GFD_SaveOk(GGadget * g,GEvent * e)85 static int GFD_SaveOk(GGadget *g, GEvent *e) {
86     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
87 	struct gfc_data *d = GDrawGetUserData(GGadgetGetWindow(g));
88 	GGadget *tf;
89 	GFileChooserGetChildren(d->gfc,NULL,NULL,&tf);
90 	if ( *_GGadgetGetTitle(tf)!='\0' ) {
91 	    d->ret = GGadgetGetTitle(d->gfc);
92 	    GIOfileExists(GFileChooserReplaceIO(d->gfc,
93 		    GIOCreate(d->ret,d,GFD_exists,GFD_doesnt)));
94 	}
95     }
96 return( true );
97 }
98 
GFD_Cancel(GGadget * g,GEvent * e)99 static int GFD_Cancel(GGadget *g, GEvent *e) {
100     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
101 	struct gfc_data *d = GDrawGetUserData(GGadgetGetWindow(g));
102 	d->done = true;
103     }
104 return( true );
105 }
106 
GFD_dircreated(GIOControl * gio)107 static void GFD_dircreated(GIOControl *gio) {
108     struct gfc_data *d = gio->userdata;
109     unichar_t *dir = u_copy(gio->path);
110 
111     GFileChooserReplaceIO(d->gfc,NULL);
112     GFileChooserSetDir(d->gfc,dir);
113     free(dir);
114 }
115 
GFD_dircreatefailed(GIOControl * gio)116 static void GFD_dircreatefailed(GIOControl *gio) {
117     /* We couldn't create the directory */
118     struct gfc_data *d = gio->userdata;
119 
120     if ( !_ggadget_use_gettext ) {
121 	unichar_t buffer[500];
122 	unichar_t title[30];
123 
124 	u_strcpy(title, GStringGetResource(_STR_Couldntcreatedir,NULL));
125 	u_strcpy(buffer, title);
126 	uc_strcat(buffer,": ");
127 	u_strcat(buffer, u_GFileNameTail(gio->path));
128 	uc_strcat(buffer, ".\n");
129 	if ( gio->error!=NULL ) {
130 	    u_strcat(buffer,gio->error);
131 	    uc_strcat(buffer, "\n");
132 	}
133 	if ( gio->status[0]!='\0' )
134 	    u_strcat(buffer,gio->status);
135 	GWidgetError(title,buffer);
136     } else {
137 	char *t1=NULL, *t2=NULL;
138 	GWidgetError8(_("Couldn't create directory"),
139 		_("Couldn't create directory: %1$s\n%2$s\n%3$s"),
140 		gio->error!=NULL ? t1 = u2utf8_copy(gio->error) : "",
141 		t2 = u2utf8_copy(gio->status));
142 	free(t1); free(t2);
143     }
144 
145     GFileChooserReplaceIO(d->gfc,NULL);
146 }
147 
GFD_NewDir(GGadget * g,GEvent * e)148 static int GFD_NewDir(GGadget *g, GEvent *e) {
149     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
150 	struct gfc_data *d = GDrawGetUserData(GGadgetGetWindow(g));
151 	unichar_t *newdir;
152 	if ( _ggadget_use_gettext ) {
153 	    char *temp;
154 	    temp = GWidgetAskString8(_("Create directory..."),NULL,_("Directory name?"));
155 	    newdir = utf82u_copy(temp);
156 	    free(temp);
157 	} else
158 	    newdir = GWidgetAskStringR(_STR_Createdir,NULL,_STR_Dirname);
159 	if ( newdir==NULL )
160 return( true );
161 	if ( !u_GFileIsAbsolute(newdir)) {
162 	    unichar_t *temp = u_GFileAppendFile(GFileChooserGetDir(d->gfc),newdir,false);
163 	    free(newdir);
164 	    newdir = temp;
165 	}
166 	GIOmkDir(GFileChooserReplaceIO(d->gfc,
167 		GIOCreate(newdir,d,GFD_dircreated,GFD_dircreatefailed)));
168 	free(newdir);
169     }
170 return( true );
171 }
172 
e_h(GWindow gw,GEvent * event)173 static int e_h(GWindow gw, GEvent *event) {
174     if ( event->type==et_close ) {
175 	struct gfc_data *d = GDrawGetUserData(gw);
176 	d->done = true;
177     } else if ( event->type == et_map ) {
178 	/* Above palettes */
179 	GDrawRaise(gw);
180     } else if ( event->type == et_char ) {
181 return( false );
182     } else if ( event->type == et_mousemove ||
183 	    (event->type==et_mousedown && event->u.mouse.button==3 )) {
184 	struct gfc_data *d = GDrawGetUserData(gw);
185 	GFileChooserPopupCheck(d->gfc,event);
186     } else if (( event->type==et_mouseup || event->type==et_mousedown ) &&
187 	    (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
188 	struct gfc_data *d = GDrawGetUserData(gw);
189 return( GGadgetDispatchEvent((GGadget *) (d->gfc),event));
190     }
191 return( true );
192 }
193 
GWidgetSaveAsFileWithGadget(const unichar_t * title,const unichar_t * defaultfile,const unichar_t * initial_filter,unichar_t ** mimetypes,GFileChooserFilterType filter,GFileChooserInputFilenameFuncType filenamefunc,GGadgetCreateData * optional_gcd)194 unichar_t *GWidgetSaveAsFileWithGadget(const unichar_t *title, const unichar_t *defaultfile,
195 				       const unichar_t *initial_filter, unichar_t **mimetypes,
196 				       GFileChooserFilterType filter,
197 				       GFileChooserInputFilenameFuncType filenamefunc,
198 				       GGadgetCreateData *optional_gcd) {
199     GRect pos;
200     GWindow gw;
201     GWindowAttrs wattrs;
202     GGadgetCreateData gcd[7], boxes[3], *varray[7], *harray[10];
203     GTextInfo label[5];
204     struct gfc_data d;
205     GGadget *pulldown, *files, *tf;
206     int bs = GIntGetResource(_NUM_Buttonsize), bsbigger, totwid;
207     int vi;
208 
209     GProgressPauseTimer();
210     memset(&wattrs,0,sizeof(wattrs));
211     wattrs.mask = wam_events|wam_cursor|wam_wtitle|wam_undercursor|wam_restrict|wam_isdlg;
212     wattrs.event_masks = ~(1<<et_charup);
213     wattrs.restrict_input_to_me = 1;
214     wattrs.is_dlg = 1;
215     wattrs.undercursor = 1;
216     wattrs.cursor = ct_pointer;
217     wattrs.window_title = (unichar_t *) title;
218     pos.x = pos.y = 0;
219     totwid = GGadgetScale(223);
220     bsbigger = 3*bs+4*14>totwid; totwid = bsbigger?3*bs+4*12:totwid;
221     pos.width = GDrawPointsToPixels(NULL,totwid);
222     pos.height = GDrawPointsToPixels(NULL,255);
223     gw = GDrawCreateTopWindow(NULL,&pos,e_h,&d,&wattrs);
224 
225     memset(&label,0,sizeof(label));
226     memset(&gcd,0,sizeof(gcd));
227     memset(&boxes,0,sizeof(boxes));
228     gcd[0].gd.pos.x = 12; gcd[0].gd.pos.y = 6;
229     gcd[0].gd.pos.width = 223-24; gcd[0].gd.pos.height = 180;
230     gcd[0].gd.flags = gg_visible | gg_enabled;
231     gcd[0].gd.cid = 1000;
232     gcd[0].creator = GFileChooserCreate;
233     varray[0] = &gcd[0]; varray[1] = NULL; vi=2;
234 
235     if ( optional_gcd!=NULL ) {
236 	varray[vi++] = optional_gcd; varray[vi++] = NULL;
237     }
238 
239     gcd[1].gd.pos.x = 12; gcd[1].gd.pos.y = 222-3;
240     gcd[1].gd.pos.width = -1;
241     gcd[1].gd.flags = gg_visible | gg_enabled | gg_but_default;
242     if ( _ggadget_use_gettext ) {
243 	label[1].text = (unichar_t *) _("_Save");
244 	label[1].text_is_1byte = true;
245     } else
246 	label[1].text = (unichar_t *) _STR_Save;
247     label[1].text_in_resource = true;
248     gcd[1].gd.mnemonic = 'S';
249     gcd[1].gd.label = &label[1];
250     gcd[1].gd.handle_controlevent = GFD_SaveOk;
251     gcd[1].creator = GButtonCreate;
252     harray[0] = GCD_Glue; harray[1] = &gcd[1];
253 
254     gcd[2].gd.pos.x = (totwid-bs)*100/GIntGetResource(_NUM_ScaleFactor)/2; gcd[2].gd.pos.y = 222;
255     gcd[2].gd.pos.width = -1;
256     gcd[2].gd.flags = gg_visible | gg_enabled;
257     if ( _ggadget_use_gettext ) {
258 	label[2].text = (unichar_t *) _("_Filter");
259 	label[2].text_is_1byte = true;
260     } else
261 	label[2].text = (unichar_t *) _STR_Filter;
262     label[2].text_in_resource = true;
263     gcd[2].gd.mnemonic = 'F';
264     gcd[2].gd.label = &label[2];
265     gcd[2].gd.handle_controlevent = GFileChooserFilterEh;
266     gcd[2].creator = GButtonCreate;
267     harray[2] = GCD_Glue; harray[3] = &gcd[2];
268 
269     gcd[3].gd.pos.x = gcd[2].gd.pos.x; gcd[3].gd.pos.y = 192;
270     gcd[3].gd.pos.width = -1;
271     gcd[3].gd.flags = gg_visible | gg_enabled;
272     if ( _ggadget_use_gettext ) {
273 	label[3].text = (unichar_t *) S_("Directory|_New");
274 	label[3].text_is_1byte = true;
275     } else
276 	label[3].text = (unichar_t *) _STR_New;
277     label[3].text_in_resource = true;
278     label[3].image = &_GIcon_dir;
279     label[3].image_precedes = false;
280     gcd[3].gd.mnemonic = 'N';
281     gcd[3].gd.label = &label[3];
282     gcd[3].gd.handle_controlevent = GFD_NewDir;
283     gcd[3].creator = GButtonCreate;
284     harray[4] = GCD_Glue; harray[5] = &gcd[3];
285 
286     gcd[4].gd.pos.x = -gcd[1].gd.pos.x; gcd[4].gd.pos.y = 222;
287     gcd[4].gd.pos.width = -1;
288     gcd[4].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
289     if ( _ggadget_use_gettext ) {
290 	label[4].text = (unichar_t *) _("_Cancel");
291 	label[4].text_is_1byte = true;
292     } else
293 	label[4].text = (unichar_t *) _STR_Cancel;
294     label[4].text_in_resource = true;
295     gcd[4].gd.label = &label[4];
296     gcd[4].gd.mnemonic = 'C';
297     gcd[4].gd.handle_controlevent = GFD_Cancel;
298     gcd[4].creator = GButtonCreate;
299     harray[6] = GCD_Glue; harray[7] = &gcd[4]; harray[8] = GCD_Glue; harray[9] = NULL;
300 
301     boxes[2].gd.flags = gg_visible | gg_enabled;
302     boxes[2].gd.u.boxelements = harray;
303     boxes[2].creator = GHBoxCreate;
304     varray[vi++] = &boxes[2]; varray[vi++] = NULL;
305     varray[vi++] = NULL;
306 
307     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
308     boxes[0].gd.flags = gg_visible | gg_enabled;
309     boxes[0].gd.u.boxelements = varray;
310     boxes[0].creator = GHVGroupCreate;
311 
312     gcd[5].gd.pos.x = 2; gcd[5].gd.pos.y = 2;
313     gcd[5].gd.pos.width = pos.width-4; gcd[5].gd.pos.height = pos.height-4;
314     gcd[5].gd.flags = gg_enabled | gg_visible | gg_pos_in_pixels;
315     gcd[5].creator = GGroupCreate;
316 
317     GGadgetsCreate(gw,boxes);
318     GGadgetSetUserData(gcd[2].ret,gcd[0].ret);
319     GHVBoxSetExpandableRow(boxes[0].ret,0);
320     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
321     GHVBoxFitWindow(boxes[0].ret);
322 
323     GFileChooserConnectButtons(gcd[0].ret,gcd[1].ret,gcd[2].ret);
324     GFileChooserSetFilterText(gcd[0].ret,initial_filter);
325     GFileChooserSetFilterFunc(gcd[0].ret,filter);
326     GFileChooserSetInputFilenameFunc(gcd[0].ret, filenamefunc);
327     GFileChooserSetMimetypes(gcd[0].ret,mimetypes);
328     GFileChooserSetFilename(gcd[0].ret,defaultfile);
329 //    GGadgetSetTitle(gcd[0].ret,defaultfile);
330     GFileChooserGetChildren(gcd[0].ret,&pulldown,&files,&tf);
331     GWidgetIndicateFocusGadget(tf);
332 
333     memset(&d,'\0',sizeof(d));
334     d.gfc = gcd[0].ret;
335 
336 
337     GWidgetHidePalettes();
338     GDrawSetVisible(gw,true);
339     while ( !d.done )
340 	GDrawProcessOneEvent(NULL);
341     GDrawDestroyWindow(gw);
342     GProgressResumeTimer();
343 return(d.ret);
344 }
345 
GWidgetSaveAsFile(const unichar_t * title,const unichar_t * defaultfile,const unichar_t * initial_filter,unichar_t ** mimetypes,GFileChooserFilterType filter)346 unichar_t *GWidgetSaveAsFile(const unichar_t *title, const unichar_t *defaultfile,
347 	const unichar_t *initial_filter, unichar_t **mimetypes,
348 	GFileChooserFilterType filter) {
349 return( GWidgetSaveAsFileWithGadget(title,defaultfile,initial_filter,mimetypes,
350 				    filter, NULL, NULL ));
351 }
352 
GWidgetSaveAsFileWithGadget8(const char * title,const char * defaultfile,const char * initial_filter,char ** mimetypes,GFileChooserFilterType filter,GFileChooserInputFilenameFuncType filenamefunc,GGadgetCreateData * optional_gcd)353 char *GWidgetSaveAsFileWithGadget8(const char *title, const char *defaultfile,
354 				   const char *initial_filter, char **mimetypes,
355 				   GFileChooserFilterType filter,
356 				   GFileChooserInputFilenameFuncType filenamefunc,
357 				   GGadgetCreateData *optional_gcd) {
358     unichar_t *tit=NULL, *def=NULL, *filt=NULL, **mimes=NULL, *ret;
359     char *utf8_ret;
360     int i;
361 
362     if ( title!=NULL )
363 	tit = utf82u_copy(title);
364     if ( defaultfile!=NULL )
365 	def = utf82u_copy(defaultfile);
366     if ( initial_filter!=NULL )
367 	filt = utf82u_copy(initial_filter);
368     if ( mimetypes!=NULL ) {
369 	for ( i=0; mimetypes[i]!=NULL; ++i );
370 	mimes = malloc((i+1)*sizeof(unichar_t *));
371 	for ( i=0; mimetypes[i]!=NULL; ++i )
372 	    mimes[i] = utf82u_copy(mimetypes[i]);
373 	mimes[i] = NULL;
374     }
375     ret = GWidgetSaveAsFileWithGadget(tit,def,filt,mimes,filter,filenamefunc,optional_gcd);
376     if ( mimes!=NULL ) {
377 	for ( i=0; mimes[i]!=NULL; ++i )
378 	    free(mimes[i]);
379 	free(mimes);
380     }
381     free(filt); free(def); free(tit);
382     utf8_ret = u2utf8_copy(ret);
383     free(ret);
384 return( utf8_ret );
385 }
386 
GWidgetSaveAsFile8(const char * title,const char * defaultfile,const char * initial_filter,char ** mimetypes,GFileChooserFilterType filter)387 char *GWidgetSaveAsFile8(const char *title, const char *defaultfile,
388 	const char *initial_filter, char **mimetypes,
389 	GFileChooserFilterType filter) {
390 return( GWidgetSaveAsFileWithGadget8(title,defaultfile,initial_filter,mimetypes,
391 				     filter, NULL, NULL ));
392 }
393