1 /* Document.c - generalized processing of multiple documents
2  *
3  * Copyright (C) 2001 Patrice St-Gelais
4  *         patrstg@users.sourceforge.net
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20 
21 #include "globals.h"
22 #include "doc.h"
23 #include "../icons/attention.xpm"
24 #include "../icons/discard_red.xpm"
25 #include "../icons/save.xpm"
26 
27 extern gint DISPLAY_DOC_OFFSET;
28 extern gboolean INTEGRATED_INTERFACE;
29 
doc_swap_new()30 doc_swap_struct *doc_swap_new() {
31 	doc_swap_struct *dsw;
32 	dsw = (doc_swap_struct *) x_malloc(sizeof(doc_swap_struct), "doc_swap_struct");
33 	dsw->current_doc = NULL;
34 	dsw->current_doc_data = NULL;
35 	dsw->last_doc = NULL;
36 	dsw->doc_list = NULL;
37 	return dsw;
38 }
39 
doc_swap_free(doc_swap_struct * dsw)40 void doc_swap_free(doc_swap_struct *dsw) {
41 	if (dsw)
42 		x_free(dsw);
43 }
44 
doc_make_current(doc_swap_struct * dsw,doc_wrapper * new_current_doc)45 void doc_make_current(doc_swap_struct *dsw, doc_wrapper *new_current_doc) {
46 //	Makes new_current_doc the new current doc....
47 	if (dsw->current_doc == new_current_doc)
48 		return;
49 	// If current_doc does not exist, last_doc takes a NULL value
50 	// (for instance, after a destruction)
51 	if (!g_list_find(dsw->doc_list, dsw->current_doc) )
52 		dsw->last_doc = NULL;
53 	else
54 		dsw->last_doc = dsw->current_doc;
55 	dsw->current_doc = new_current_doc;
56 	dsw->current_doc_data = dsw->current_doc->data;
57 //	printf("MAKE CURRENT: %d == %x == %s\n", dsw->current_doc_data, dsw->current_doc_data, new_current_doc->filename);
58 	if (new_current_doc->type->display)
59 		(*new_current_doc->type->display) (new_current_doc->data);
60 }
61 
doc_save(doc_wrapper * doc)62 gint doc_save (doc_wrapper *doc) {
63 
64 //	Returns TRUE when the file is saved,
65 //		FALSE when it is not
66 	gchar *path_n_file, *new_path_n_file;
67 	gchar *default_dir=NULL;
68 
69 	if (doc->dir)
70 		default_dir = doc->dir;
71 
72 	path_n_file = (gchar *) x_malloc(strlen(default_dir)+strlen(doc->filename)+1, "gchar (path_n_file)");
73 	strcpy(path_n_file,default_dir);
74 	strcat(path_n_file, doc->filename);
75 
76 	if (doc->fname_tochoose) {
77 		new_path_n_file =
78 			GetFilename(doc->type->extensions,
79 				doc->type->nbextensions,
80 				_("Save as..."),
81 				path_n_file,
82 				NEW_FILE,
83 				doc->type->extensions[0].lbl);
84 		x_free(path_n_file);
85 		if (!new_path_n_file)
86 			return FALSE;
87 		path_n_file = new_path_n_file;
88 	}
89 // printf("path_n_file dans DOC_SAVE: %s\n",path_n_file);
90 	(*doc->type->save) (doc->data, path_n_file);
91 	split_dir_file(path_n_file, &doc->dir, &doc->filename, FILESEP);
92 //	We reinitialize the default directory for the current type after a new file save
93 	if (doc->fname_tochoose) {
94 		doc->type->def_dir = (gchar *) x_realloc(doc->type->def_dir, strlen(doc->dir)+1, "gchar (doc->type->def_dir)");
95 		strcpy(doc->type->def_dir,doc->dir);
96 	}
97 	doc->fname_tochoose = FALSE;
98 	doc->if_modified = FALSE;
99 	gtk_window_set_title (GTK_WINDOW (doc->window), g_filename_to_utf8(path_n_file,-1,NULL,NULL,NULL));
100 	return TRUE;
101 }
102 
doc_stats(doc_wrapper * doc)103 void doc_stats (doc_wrapper *doc) {
104 	if (doc->type->stats)
105 		(*doc->type->stats) (doc->data);
106 }
107 
place_document_window(doc_swap_struct * dsw,types_wrapper * tw,GtkWidget * window)108 void place_document_window(doc_swap_struct *dsw, types_wrapper *tw, GtkWidget *window) {
109 
110 //	Guess best placement from tools & creation dialogs positions / size
111 //	"window" can be any window at the screen left
112 //	... tw->tools_window or tw->window (= create_window)
113 	GtkRequisition rq;
114 	static gint pad=0;
115 	gint x, y;
116 //	pad = g_list_length(dsw->doc_list)*DEF_PAD;
117 	if (window) {
118 		gtk_widget_size_request(GTK_WIDGET(window),&rq);
119 		x = DISPLAY_DOC_OFFSET*gdk_screen_width()/100
120 			 + pad + rq.width + tw->win_pos_x;
121 		y = pad + tw->win_tools_pos_y;
122 	}
123 	else { // Probably an integrated interface
124 		x = DISPLAY_DOC_OFFSET*gdk_screen_width()/100
125 			 + pad + tw->win_pos_x;
126 		y = pad + (tw->win_pos_y + tw->win_tools_pos_y)/2;
127 
128 	}
129 	gtk_widget_set_uposition(GTK_WIDGET(dsw->current_doc->window), x, y);
130 	pad += DEF_PAD*2;
131 }
132 
doc_wrapper_new(gchar * filename,gchar * dir,doc_type_struct * current_type)133 doc_wrapper *doc_wrapper_new(gchar *filename, gchar *dir, doc_type_struct *current_type) {
134 	doc_wrapper *dw;
135 	dw = (doc_wrapper *) x_malloc(sizeof(doc_wrapper), "doc_wrapper");
136 //	printf("DOC_WRAPPER_NEW: %d\n",dw);
137 	dw->type_id = DOC_WRAPPER_TYPE;
138 	dw->type = current_type;
139 	dw->data = NULL;
140 	dw->window = NULL;
141 	dw->filename = (gchar *) x_malloc(strlen(filename)+1, "gchar (dw->filename)");
142 	strcpy(dw->filename,filename);
143 	dw->dir = NULL;
144 	if (dir) {
145 		dw->dir = (gchar *) x_malloc(strlen(dir)+1, "gchar (dw->dir)");
146 		strcpy(dw->dir,dir);
147 	}
148 	dw->history = NULL;
149 	dw->max_history = MAX_HISTORY;
150 	dw->to_register_in_history = TRUE;
151 	dw->if_modified = FALSE;
152 	dw->fname_tochoose = FALSE;
153 	dw->creation_mode = TRUE; // Remember to put it FALSE when reading from a file!
154 //	Data struct for the current document type is initialized in doc_window_new
155 	dw->data = NULL;
156 	dw->data_to_show = NULL;
157 	dw->commit_data_adr = NULL;
158 	dw->creation_container = NULL;
159 	dw->tools_container = NULL;
160 	dw->creation_dialog = NULL;
161 	dw->tools_dialog = NULL;
162 	dw->option_dialogs = NULL;
163 	return dw;
164 
165 }
166 
doc_new(doc_swap_struct * dsw,types_wrapper * tw,gchar * path_n_file,gint sequence,gpointer commit_data_adr,GtkWidget * menu,GtkWidget * toolbar)167 gboolean doc_new(doc_swap_struct *dsw, types_wrapper *tw,
168 	gchar *path_n_file, gint sequence, gpointer commit_data_adr,
169 	GtkWidget *menu, GtkWidget *toolbar) {
170 //	Creates a main display window for a new document
171 //	Creates the document
172 //	Initializes some variables
173 
174 	gchar *buf;
175 	GtkWidget *vbox, *hbox, *window_box;
176 // printf("DOC_LIST dans DOC_NEW: %d\n",dsw->doc_list);
177 //	printf("CURRENT_DOC dans DOC_NEW: %d\n",dsw->current_doc);
178 
179 	// Address of the data eventually used for committing the current transaction
180 	// Inherited from app
181 	// *commit_data_adr must be set to NULL when destroying the current document
182 	dsw->current_doc->commit_data_adr = commit_data_adr;
183 
184 	dsw->current_doc->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
185 	gtk_window_set_resizable(GTK_WINDOW(dsw->current_doc->window),TRUE);
186 
187 	place_document_window(dsw, tw, tw->creation_container);
188 
189 	gtk_container_border_width (GTK_CONTAINER(dsw->current_doc->window),DEF_PAD);
190 //	Default size:  25% x W/H
191 	gtk_window_set_default_size(GTK_WINDOW(dsw->current_doc->window),
192 		gdk_screen_width()/4,
193 		gdk_screen_height()/4);
194 //	Some processes need a realized window (because of XPMs icons...)
195 	gtk_widget_realize(GTK_WIDGET(dsw->current_doc->window));
196 
197 	if (GTK_IS_WIDGET(menu) || GTK_IS_WIDGET(toolbar)) {
198 		window_box = gtk_vbox_new(FALSE,0);
199 		gtk_widget_show(GTK_WIDGET(window_box));
200 		gtk_container_add(GTK_CONTAINER(dsw->current_doc->window), window_box);
201 		if (GTK_IS_WIDGET(menu))
202 			gtk_box_pack_start(GTK_BOX(window_box), menu, FALSE, FALSE, 0);
203 		if (GTK_IS_WIDGET(toolbar))
204 			gtk_box_pack_start(GTK_BOX(window_box), toolbar, FALSE, FALSE, 0);
205 	}
206 	else
207 		window_box = dsw->current_doc->window;
208 
209 //	Data and widget struct for current document are initialized and linked to ->window
210 	if (INTEGRATED_INTERFACE) {
211 		// The "window" passed to the type->new function
212 		// is the right part of the actual window, the left
213 		// part being reserved to the creation and tools dialogs
214 
215 		hbox = gtk_hbox_new(FALSE,0);
216 		gtk_widget_show(GTK_WIDGET(hbox));
217 		vbox = gtk_vbox_new(FALSE,0);
218 		gtk_widget_show(GTK_WIDGET(vbox));
219 		gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, DEF_PAD);
220 		gtk_container_add(GTK_CONTAINER(window_box), hbox);
221 		if (GTK_IS_WIDGET(dsw->current_doc->creation_container))
222 			// There is no creation container, for instance,
223 			// when opening a file
224 			gtk_box_pack_start(GTK_BOX(vbox), dsw->current_doc->creation_container, TRUE, TRUE, 0);
225 		gtk_box_pack_start(GTK_BOX(vbox), dsw->current_doc->tools_container, FALSE, FALSE, 0);
226 		dsw->current_doc->data = (gpointer) (*dsw->current_doc->type->new)
227 			(&dsw->current_doc->dir,
228 			&dsw->current_doc->filename,
229 			hbox,
230 			dsw->current_doc->creation_dialog,
231 			dsw->current_doc->option_dialogs,
232 			&dsw->current_doc->if_modified,
233 			&dsw->current_doc->to_register_in_history,
234 			(gpointer) doc_register_in_history,
235 			dsw->current_doc,
236 			path_n_file,
237 			&dsw->current_doc->fname_tochoose,
238 			0);
239 	}
240 	else {
241 		dsw->current_doc->data = (gpointer) (*dsw->current_doc->type->new)
242 			(&dsw->current_doc->dir,
243 			&dsw->current_doc->filename,
244 			window_box,
245 			dsw->current_doc->type->creation_dialog,
246 			dsw->current_doc->type->options_dialogs,
247 			&dsw->current_doc->if_modified,
248 			&dsw->current_doc->to_register_in_history,
249 			(gpointer) doc_register_in_history,
250 			dsw->current_doc,
251 			path_n_file,
252 			&dsw->current_doc->fname_tochoose,
253 			0);
254 	}
255 
256 	if (!dsw->current_doc->data)	//	Something had gone bad!
257 		return FALSE;
258 
259 	dsw->current_doc_data = dsw->current_doc->data;
260 
261 	if (dsw->current_doc->fname_tochoose) {
262 		// File name = "document" + new doc count
263 		// 2005-11-25: added default extension
264 		buf = (gchar *) x_malloc(strlen(_("document"))+8, "gchar (buf - documentN)");
265 		sprintf(buf,"%s%-i.%s",_("document"),sequence%1000,strlow(dsw->current_doc->type->extensions[0].lbl));
266 		dsw->current_doc->filename = buf;
267 	}
268 
269 	gtk_window_set_title (GTK_WINDOW (dsw->current_doc->window),
270 		g_filename_to_utf8(concat_dname_fname(dsw->current_doc->dir,dsw->current_doc->filename), -1, NULL, NULL, NULL));
271 
272 //	The standard close / destroy event
273 	gtk_signal_connect (GTK_OBJECT (dsw->current_doc->window), "delete_event",
274                         GTK_SIGNAL_FUNC(doc_close), (gpointer) dsw);
275 // printf("dsw->current_doc->dir: %s; \n",dsw->current_doc->dir);
276 
277 	gtk_widget_show(GTK_WIDGET(dsw->current_doc->window));
278 //	printf("File name: %s;  Ptr of newly created doc: %d\n", dsw->current_doc->filename, dsw->current_doc->data);
279 	return TRUE;
280 }
281 
doc_prepare_to_load(gchar * path_n_file,types_wrapper * types)282 doc_wrapper *doc_prepare_to_load(gchar *path_n_file, types_wrapper *types) {
283 //	Prepares a document to be read from its extension
284 //	Creates the doc_wrapper struct
285 	gint doc_type_index;
286 	gchar *ext, *dname, *fname;
287 	doc_wrapper *dw;
288 	gchar *buf, *utf8;
289 
290 	if (path_n_file)
291 		split_dir_file(path_n_file, &dname, &fname, FILESEP);
292 	else
293 		return NULL;
294 	ext  = (gchar *) strrchr(fname, '.');
295 
296 //	printf("Dans DOC_LOAD:  PATH_N_FILE: %s;  DNAME: %s;  FNAME: %s; EXT: %s; ",path_n_file,dname, fname, ext, doc_type_index);
297 //	Document type deduced from extension
298 	if (ext)
299 		doc_type_index = find_doc_type_from_ext(1+ext, types);
300 	else {
301 		doc_type_index = -1;
302 	}
303 //	printf("IDX: %d\n", doc_type_index);
304 	if (doc_type_index < 0) {
305 		buf = (gchar *) x_malloc(strlen(buf)+strlen(_("File extension <<%s>> unknown or non-existent"))+1, "gchar (buf)");
306 		sprintf(buf,_("File extension <<%s>> unknown or non-existent"),fname);
307 		my_msg(buf,WARNING);
308 		x_free(buf);
309 		return NULL;
310 	}
311 	if (!filexists(path_n_file)) {
312 		utf8 = g_filename_to_utf8 (path_n_file, -1, NULL, NULL, NULL);
313 		buf = (gchar *) x_malloc(strlen(_("File %s not found or unreadable!"))+strlen(utf8)+1, "gchar (buf - File not found MSG)");
314 		sprintf(buf,_("File %s not found or unreadable!"),utf8);
315 		my_msg(buf,WARNING);
316 		x_free(buf);
317 		free(utf8);
318 		return NULL;
319 	    }
320 	if (dname) {
321 		(types->doc_type_list+doc_type_index)->def_dir = (gchar *)
322 			x_realloc((types->doc_type_list+doc_type_index)->def_dir,strlen(dname)+1, "gchar (def_dir)");
323 		strcpy((types->doc_type_list+doc_type_index)->def_dir,dname);
324 	}
325 	dw =  doc_wrapper_new(fname, dname, types->doc_type_list+doc_type_index);
326 	return dw;
327 }
328 
doc_read(gchar ** path_n_file_adr,types_wrapper * types,doc_swap_struct * dsw,gchar * app_default_dir)329 doc_wrapper *doc_read(gchar **path_n_file_adr, types_wrapper *types,
330 	doc_swap_struct *dsw, gchar *app_default_dir) {
331 //	Returns NULL if the file cannot be read,
332 //	otherwise returns a new doc_wrapper pointer
333 	gchar *default_dir;
334 	gint nb_ext=0, n_ext, i, j;
335 	omenu_list_type *ext_menu=NULL;
336 
337 //	Find all allowable extensions for the current application
338 //	Build an integrated option menu with these	extensions
339 //	... optimization:  calculate once for the session
340 	for (i=0; i<types->nbtypes; i++) {
341 		n_ext = nb_ext;
342 		nb_ext += types->doc_type_list[i].nbextensions;
343 		ext_menu = (omenu_list_type *) x_realloc(ext_menu,nb_ext*sizeof(omenu_list_type), "omenu_list_type");
344 		for (j=0; j<types->doc_type_list[i].nbextensions; j++) {
345 			memcpy(ext_menu+n_ext+j,
346 				types->doc_type_list[i].extensions+j,
347 				sizeof(omenu_list_type));
348 		}
349 	}
350 //	The best guess for the default dir comes from the type of the current document
351 	if (dsw && dsw->current_doc && dsw->current_doc->type->def_dir)
352 		default_dir = dsw->current_doc->type->def_dir;
353 	else
354 		if (types->default_type->def_dir)
355 			default_dir = types->default_type->def_dir;
356 		else
357 			default_dir = app_default_dir;
358 	(*path_n_file_adr) =
359 		GetFilename(	ext_menu,
360 				nb_ext,
361 				_("Open"),
362 				default_dir,
363 				EXISTING_FILE,
364 				ext_menu[0].lbl);
365 	x_free(ext_menu);
366 
367 	return doc_prepare_to_load(*path_n_file_adr,types);
368 }
369 
doc_save_question(doc_wrapper * dw)370 gint doc_save_question (doc_wrapper *dw) {
371 
372 	gint lendir;
373 	gchar *buf, *buf2, *utf8;
374 
375 	lendir =strlen(dw->dir);
376 	buf2 = (gchar *) x_malloc(lendir+strlen(dw->filename)+1, "gchar (buf2 - dw->filename)");
377 	strcpy(buf2,dw->dir);
378 //	buf2[lendir] = FILESEP; // Already included int dw->dir
379 	buf2[lendir] = '\0';
380 	strcat(buf2, dw->filename);
381 	utf8 = g_filename_to_utf8 (buf2, -1, NULL, NULL, NULL);
382 	buf = (gchar *) x_malloc(strlen(_("<%s> has been modified. Save?"))+strlen(utf8)+1, "gchar (buf - Document modified message)");
383 	sprintf(buf,_("<%s> has been modified. Save?"),utf8);
384 	x_free(buf2);
385 	free(utf8);
386 	switch (yes_no_cancel(buf,TRUE)) {
387 		case TRUE:
388 			doc_save(dw);
389 			x_free(buf);
390 			return TRUE;
391 		case CANCEL_YESNO:
392 			x_free(buf);
393 			return CANCEL_YESNO;  	// window / document not destroyed
394 		case FALSE:		// destroy window / document
395 			x_free(buf);
396 			return FALSE;
397 	} // end switch
398 	return TRUE;
399 }
400 
doc_close(GtkWidget * wdg,GdkEvent * event,gpointer callb_data)401 gint doc_close (GtkWidget *wdg, GdkEvent *event, gpointer callb_data) {
402 
403 	gint answer;
404 	GList *node;
405 	doc_swap_struct *dsw;
406 	dsw = (doc_swap_struct *) callb_data;
407 
408 	// We check if the window receiving the delete event is the window
409 	// of the current document
410 	// If not, we make the document related to the window the current one
411 	if (wdg)
412 		if (dsw->current_doc && (wdg!=dsw->current_doc->window)) {
413 			// Search the related document
414 			for (node = dsw->doc_list; node; node=node->next) {
415 				if (((doc_wrapper *) node->data)->window == wdg) {
416 					doc_make_current(dsw, (doc_wrapper *) node->data);
417 					break;
418 				}
419 			}
420 		}
421 	answer = FALSE; // Quit without saving when not modified
422 	if (!node) {
423 		my_msg("Not able to find the document to close!\nClick on a document window to activate the related document",WARNING);
424 		return TRUE;
425 	}
426 	if (dsw->current_doc->if_modified) {
427 		answer = doc_save_question(dsw->current_doc);
428 	}
429 
430 	if (answer==CANCEL_YESNO)
431 		return TRUE;
432 
433 	doc_wrapper_destroy(dsw);
434 
435 	if (INTEGRATED_INTERFACE && (!count_documents(callb_data)))
436 		gtk_main_quit();
437 
438 	return FALSE;
439 }
440 
doc_wrapper_free(doc_wrapper * dw,gboolean free_interface)441 void doc_wrapper_free(doc_wrapper* dw, gboolean free_interface) {
442 	GList *node;
443 	if (dw->type->free) {
444 		(*dw->type->free) (dw->data, free_interface);
445 
446 		// We avoid committing the last transaction
447 		// if it's about the document we are destroying
448 		if (dw->data == *dw->commit_data_adr)
449 			*dw->commit_data_adr = NULL;
450 
451 //	We free all the doc instances in the history
452 		for (node = dw->history; node; node=node->next) {
453 //			printf("DW_FREE- NODE->DATA: %d\n",node->data);
454 			(*dw->type->free) (node->data, FALSE);
455 		}
456 		g_list_free(dw->history);
457 
458 	}
459 	x_free(dw->filename);
460 	x_free(dw->dir);
461 	if (dw->option_dialogs) // For the integrated interface
462 		if (dw->type->options_dialogs_free) {
463 			(*dw->type->options_dialogs_free) (dw->option_dialogs);
464 			dw->option_dialogs = NULL;
465 		}
466 	x_free(dw);
467 }
468 
doc_wrapper_destroy(doc_swap_struct * dsw)469 void doc_wrapper_destroy(doc_swap_struct *dsw) {
470 	gint i;
471 	GtkWidget *tools_window=NULL;
472 	i = g_list_length(dsw->doc_list);
473 
474 	dsw->doc_list = g_list_remove(dsw->doc_list, (gpointer) dsw->current_doc);
475 	i = g_list_length(dsw->doc_list);
476 	if ((!INTEGRATED_INTERFACE) && GTK_IS_WIDGET(dsw->current_doc->type->tools_dialog))
477 		tools_window = gtk_widget_get_parent(dsw->current_doc->type->tools_dialog);
478 
479 	doc_wrapper_free(dsw->current_doc, TRUE);
480 
481 //	CURRENT_DOC should be the next on the list, except if list length is 0!
482 	dsw->current_doc = NULL;
483 	dsw->current_doc_data = NULL;
484 	if (i) {
485 		doc_make_current(dsw,(doc_wrapper *) dsw->doc_list->data);
486 
487 //		gtk_widget_grab_focus(GTK_WIDGET(dsw->current_doc->window));
488 
489 		if (dsw->current_doc)
490 			gdk_window_show(dsw->current_doc->window->window);
491 	}
492 	else
493 	// We hide the tools dialog if there is no document left!
494 		if ((!INTEGRATED_INTERFACE) && GTK_IS_WIDGET(tools_window))
495 			gtk_widget_hide (tools_window);
496 }
497 
get_doc_list_from_type(gpointer gdsw,gchar * type)498 GList *get_doc_list_from_type (gpointer gdsw, gchar * type) {
499 //	Builds a list of dsw->(GList)->doc_data from a given type (HFPNG, POVINI...)
500 	doc_swap_struct *dsw;
501 	GList *node,*list = NULL;
502 	dsw = (doc_swap_struct *) gdsw;
503 	for (node = dsw->doc_list; node; node = node->next) {
504 		if ( !strcmp(((doc_wrapper*)(node->data))->type->type,type) ) {
505 			list = g_list_append(list,((doc_wrapper*)(node->data))->data);
506 		}
507 	}
508 	return list;
509 }
510 
count_modified_documents(doc_swap_struct * dsw)511 gint count_modified_documents (doc_swap_struct *dsw) {
512 	doc_wrapper *dw;
513 	GList *node;
514 	gint count=0;
515 	for (node = dsw->doc_list; node; node = node->next) {
516 		dw = (doc_wrapper *) node->data;
517 		if (dw->if_modified) {
518 			count++;
519 		}
520 	}
521 	return count;
522 }
523 
count_documents(doc_swap_struct * dsw)524 gint count_documents (doc_swap_struct *dsw) {
525 	doc_wrapper *dw;
526 	GList *node;
527 	gint count=0;
528 	for (node = dsw->doc_list; node; node = node->next) {
529 		dw = (doc_wrapper *) node->data;
530 		count++;
531 	}
532 	return count;
533 }
534 
dummy(GtkWidget * wdg,gpointer data)535 void dummy (GtkWidget *wdg, gpointer data) {
536 }
537 
doc_save_callb(GtkWidget * wdg,gpointer data)538 void doc_save_callb (GtkWidget *wdg, gpointer data) {
539 	if (data) {
540 		doc_save ((doc_wrapper *) data);
541 	}
542 }
543 
save_all_dialog_new(GtkWidget * window_to_destroy,doc_swap_struct * dsw)544 GtkWidget *save_all_dialog_new (GtkWidget *window_to_destroy, doc_swap_struct *dsw) {
545 
546 	// Dialog for saving / discarding all the docs at once
547 
548 	// "window" is the dialog window to destroy after saving a document
549 	// (then, we regenerate the dialog)
550 
551 	GtkWidget *dialog, *vbox, *table, *label, *icon, *hbox, *hbox2, *scrolled_window, *window, *toolbar, *wdg;
552 	doc_wrapper *dw;
553 	gint i, modcount;
554 	GList *node;
555 
556 	modcount = count_modified_documents (dsw);
557 
558 	// Window reference for creating pixmaps from xpms
559 	window = ((doc_wrapper *) dsw->doc_list->data)->window;
560 
561 	dialog = gtk_vbox_new (FALSE, DEF_PAD);
562 	gtk_widget_show (dialog);
563 
564 	vbox = gtk_vbox_new (FALSE, DEF_PAD);
565 	gtk_widget_show (vbox);
566 
567 	label = gtk_label_new (_("These documents haven't been saved"));
568 	gtk_widget_show (label);
569 	gtk_box_pack_start (GTK_BOX(vbox), align_widget (label, 0.5, 0.5) , FALSE, FALSE, DEF_PAD);
570 
571 	hbox2 = gtk_hbox_new (FALSE, DEF_PAD);
572 	gtk_widget_show (hbox2);
573 	label = gtk_label_new (_("Click on "));
574 	gtk_widget_show (label);
575 	gtk_box_pack_start (GTK_BOX(hbox2), label, FALSE, FALSE, 0);
576 	gtk_box_pack_start (GTK_BOX(hbox2), create_widget_from_xpm (window, save_xpm), FALSE, FALSE, 0);
577 	label = gtk_label_new (_(" for those you want to save") );
578 	gtk_widget_show (label);
579 	gtk_box_pack_start (GTK_BOX(hbox2), label, FALSE, FALSE, 0);
580 	gtk_box_pack_start (GTK_BOX(vbox), align_widget(hbox2,0.5,0.5), FALSE, FALSE, 0);
581 
582 	hbox = gtk_hbox_new (FALSE, DEF_PAD);
583 	gtk_widget_show (hbox);
584 	gtk_box_pack_start (GTK_BOX(hbox), create_widget_from_xpm (window, attention_xpm), FALSE, FALSE, DEF_PAD);
585 
586 	gtk_box_pack_start (GTK_BOX(hbox), vbox, FALSE, FALSE, DEF_PAD);
587 
588 	gtk_box_pack_start (GTK_BOX(dialog), align_widget(hbox,0.4, 0.5), FALSE, FALSE, 0);
589 
590 	vbox = gtk_vbox_new (FALSE, DEF_PAD);
591 	gtk_widget_show (vbox);
592 
593 	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
594         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
595                                     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
596 	gtk_widget_show (scrolled_window);
597 	gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), vbox);
598 	gtk_widget_set_size_request (scrolled_window, 500, MIN(modcount,6)*80);
599 
600 	table = gtk_table_new (modcount, 3, FALSE);
601 	gtk_widget_show (GTK_WIDGET(table));
602 	gtk_box_pack_start(GTK_BOX(vbox), align_widget(table,0.5,0.5), TRUE, TRUE, 0);
603 
604 	i = 0;
605 	for (node = dsw->doc_list; node; node=node->next) {
606 		dw = (doc_wrapper*)(node->data);
607 		if (!dw->if_modified)
608 			continue;
609 		if (dw->type->get_icon) {
610 			icon = (*dw->type->get_icon) (dw->data, 64, 64);
611 			gtk_table_attach (GTK_TABLE(table), icon, 0, 1, i, i+1, 0, 0, DEF_PAD, DEF_PAD);
612 		}
613 		toolbar = gtk_toolbar_new();
614 		gtk_toolbar_set_orientation(GTK_TOOLBAR(toolbar),GTK_ORIENTATION_HORIZONTAL);
615 		gtk_toolbar_set_style(GTK_TOOLBAR(toolbar),GTK_TOOLBAR_ICONS);
616 		gtk_widget_show(GTK_WIDGET(toolbar));
617 		wdg = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
618 			GTK_TOOLBAR_CHILD_RADIOBUTTON,NULL,_("Discard"),
619 			_("Discard"),NULL,
620 			create_widget_from_xpm(window,discard_red_xpm),
621 			GTK_SIGNAL_FUNC(dummy), (gpointer) NULL);
622 		wdg = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
623 			GTK_TOOLBAR_CHILD_RADIOBUTTON,wdg,_("Save"),
624 			_("Save"),NULL,
625 			create_widget_from_xpm(window,save_xpm),
626 			GTK_SIGNAL_FUNC(doc_save_callb), (gpointer) dw);
627 		if (window_to_destroy && GTK_IS_WIDGET(window_to_destroy))
628 			gtk_signal_connect_object(GTK_OBJECT(wdg), "clicked",
629 				GTK_SIGNAL_FUNC(gtk_widget_destroy), (gpointer) window_to_destroy);
630 		gtk_table_attach (GTK_TABLE(table), GTK_WIDGET(toolbar), 1, 2, i, i+1, 0, 0, DEF_PAD, DEF_PAD);
631 		label = gtk_label_new(g_filename_to_utf8(concat_dname_fname(dw->dir, dw->filename), -1, NULL, NULL, NULL));
632 		gtk_widget_show(label);
633 		gtk_table_attach (GTK_TABLE(table), GTK_WIDGET(label), 2, 3, i, i+1, 0, 0, DEF_PAD, DEF_PAD );
634 		i++;
635 	}
636 
637 	gtk_box_pack_start(GTK_BOX(dialog), scrolled_window, FALSE, FALSE, DEF_PAD);
638 
639 	return dialog;
640 }
641