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