Compilation: clean up dialog including.
[gnumeric.git] / src / gui-file.c
bloba80883305e8d846b1228bdf7a0f47b2bcd02f007
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * GUI-file.c:
5 * Authors:
6 * Jon K Hellan (hellan@acm.org)
7 * Zbigniew Chyla (cyba@gnome.pl)
8 * Andreas J. Guelzow (aguelzow@pyrshep.ca)
9 */
10 #include <gnumeric-config.h>
11 #include <glib/gi18n-lib.h>
12 #include "gnumeric.h"
13 #include "gui-file.h"
15 #include "gui-util.h"
16 #include "gutils.h"
17 #include "dialogs/dialogs.h"
18 #include "sheet.h"
19 #include "application.h"
20 #include "command-context.h"
21 #include "wbc-gtk-impl.h"
22 #include "workbook-view.h"
23 #include "workbook-priv.h"
24 #include "gnumeric-conf.h"
25 #include "application.h"
27 #include <goffice/goffice.h>
29 #include <gtk/gtk.h>
30 #include <unistd.h>
31 #include <string.h>
33 typedef struct {
34 GOCharmapSel *go_charmap_sel;
35 GtkWidget *charmap_label;
36 GList *openers;
37 } file_opener_format_changed_cb_data;
41 static gint
42 file_opener_description_cmp (gconstpointer a, gconstpointer b)
44 GOFileOpener const *fo_a = a, *fo_b = b;
46 return g_utf8_collate (go_file_opener_get_description (fo_a),
47 go_file_opener_get_description (fo_b));
50 static gint
51 file_saver_description_cmp (gconstpointer a, gconstpointer b)
53 GOFileSaver const *fs_a = a, *fs_b = b;
55 return g_utf8_collate (go_file_saver_get_description (fs_a),
56 go_file_saver_get_description (fs_b));
59 static void
60 make_format_chooser (GList *list, GtkComboBox *combo)
62 GList *l;
63 GtkComboBoxText *bt = GTK_COMBO_BOX_TEXT (combo);
65 /* Make format chooser */
66 for (l = list; l != NULL; l = l->next) {
67 GObject *obj = l->data;
68 gchar const *descr;
70 if (!obj)
71 descr = _("Automatically detected");
72 else if (GO_IS_FILE_OPENER (obj))
73 descr = go_file_opener_get_description (GO_FILE_OPENER (obj));
74 else
75 descr = go_file_saver_get_description (GO_FILE_SAVER (obj));
77 gtk_combo_box_text_append_text (bt, descr);
81 /* Show view in a wbcg. Use current or new wbcg according to policy */
82 void
83 gui_wb_view_show (WBCGtk *wbcg, WorkbookView *wbv)
85 WBCGtk *new_wbcg = NULL;
86 Workbook *tmp_wb = wb_control_get_workbook (GNM_WBC (wbcg));
88 if (go_doc_is_pristine (GO_DOC (tmp_wb))) {
89 g_object_ref (wbcg);
90 g_object_unref (tmp_wb);
91 wb_control_set_view (GNM_WBC (wbcg), wbv, NULL);
92 wb_control_init_state (GNM_WBC (wbcg));
93 } else {
94 GdkScreen *screen = gtk_window_get_screen (wbcg_toplevel (wbcg));
95 WorkbookControl *new_wbc =
96 workbook_control_new_wrapper (GNM_WBC (wbcg),
97 wbv, NULL, screen);
98 new_wbcg = WBC_GTK (new_wbc);
100 wbcg_copy_toolbar_visibility (new_wbcg, wbcg);
103 sheet_update (wb_view_cur_sheet (wbv));
107 * gui_file_read:
109 * Returns: (transfer none): the new #WorkbookView for the file read.
111 WorkbookView *
112 gui_file_read (WBCGtk *wbcg, char const *uri,
113 GOFileOpener const *optional_format, gchar const *optional_encoding)
115 GOIOContext *io_context;
116 WorkbookView *wbv;
118 go_cmd_context_set_sensitive (GO_CMD_CONTEXT (wbcg), FALSE);
119 io_context = go_io_context_new (GO_CMD_CONTEXT (wbcg));
120 wbv = workbook_view_new_from_uri (uri, optional_format, io_context,
121 optional_encoding);
123 if (go_io_error_occurred (io_context) ||
124 go_io_warning_occurred (io_context))
125 go_io_error_display (io_context);
127 g_object_unref (io_context);
128 go_cmd_context_set_sensitive (GO_CMD_CONTEXT (wbcg), TRUE);
130 if (wbv != NULL) {
131 gui_wb_view_show (wbcg, wbv);
132 workbook_update_history (wb_view_get_workbook (wbv), GNM_FILE_SAVE_AS_STYLE_SAVE);
133 } else {
134 /* Somehow fixes #625687. Don't know why. */
135 wbcg_focus_cur_scg (wbcg);
138 return wbv;
141 gboolean
142 gnm_gui_file_template (WBCGtk *wbcg, char const *uri)
144 GOIOContext *io_context;
145 WorkbookView *wbv;
146 GOFileOpener const *optional_format = NULL;
147 gchar const *optional_encoding = NULL;
149 go_cmd_context_set_sensitive (GO_CMD_CONTEXT (wbcg), FALSE);
150 io_context = go_io_context_new (GO_CMD_CONTEXT (wbcg));
151 wbv = workbook_view_new_from_uri (uri, optional_format, io_context,
152 optional_encoding);
154 if (go_io_error_occurred (io_context) ||
155 go_io_warning_occurred (io_context))
156 go_io_error_display (io_context);
158 g_object_unref (io_context);
159 go_cmd_context_set_sensitive (GO_CMD_CONTEXT (wbcg), TRUE);
161 if (wbv != NULL) {
162 Workbook *wb = wb_view_get_workbook (wbv);
163 workbook_set_saveinfo (wb, GO_FILE_FL_NEW, NULL);
164 gui_wb_view_show (wbcg, wbv);
165 return TRUE;
167 return FALSE;
170 static void
171 file_opener_format_changed_cb (GtkComboBox *format_combo,
172 file_opener_format_changed_cb_data *data)
174 GOFileOpener *fo = g_list_nth_data (data->openers,
175 gtk_combo_box_get_active (format_combo));
176 gboolean is_sensitive = fo != NULL && go_file_opener_is_encoding_dependent (fo);
178 gtk_widget_set_sensitive (GTK_WIDGET (data->go_charmap_sel), is_sensitive);
179 gtk_widget_set_sensitive (data->charmap_label, is_sensitive);
183 static gint
184 file_opener_find_by_id (GList *openers, char const *id)
186 GList *l;
187 gint i = 0;
189 if (id == NULL)
190 return 0;
192 for (l = openers; l != NULL; l = l->next, i++) {
193 if (GO_IS_FILE_OPENER (l->data) &&
194 strcmp (id, go_file_opener_get_id(l->data)) == 0)
195 return i;
198 return 0;
201 static void
202 cb_advanced_clicked (GtkButton *advanced, GtkFileChooser *fsel)
204 GtkWidget *extra = g_object_get_data (G_OBJECT (advanced), "extra");
206 gtk_button_set_use_underline (advanced, TRUE);
207 if (gtk_file_chooser_get_extra_widget (fsel)) {
208 /* xgettext: If possible try to use the same mnemonic for
209 * Advanced and Simple */
210 gtk_button_set_label (advanced, _("Advanc_ed"));
211 gtk_file_chooser_set_extra_widget (fsel, NULL);
212 } else {
213 gtk_button_set_label (advanced, _("Simpl_e"));
214 gtk_file_chooser_set_extra_widget (fsel, extra);
219 * Suggests automatic file type recognition, but lets the user choose an
220 * import filter for selected file.
222 void
223 gui_file_open (WBCGtk *wbcg, GnmFileOpenStyle type, char const *default_format)
225 GList *openers = NULL, *all_openers, *l;
226 GtkFileChooser *fsel;
227 GtkWidget *advanced_button;
228 GtkComboBox *format_combo;
229 GtkWidget *go_charmap_sel;
230 file_opener_format_changed_cb_data data;
231 gint opener_default;
232 char const *title = NULL;
233 GSList *uris = NULL;
234 char const *encoding = NULL;
235 GOFileOpener *fo = NULL;
236 Workbook *workbook = wb_control_get_workbook (GNM_WBC (wbcg));
238 all_openers = go_get_file_openers ();
240 if (default_format != NULL) {
241 fo = go_file_opener_for_id (default_format);
244 if (fo != NULL)
245 openers = g_list_prepend (NULL, fo);
246 else {
247 for (l = all_openers; l; l = l->next)
248 if (l->data != NULL) {
249 GOFileOpener *fo = l->data;
250 GSList const *mimes = go_file_opener_get_mimes (fo);
251 GSList *fsavers = NULL, *fl;
253 for (; mimes; mimes = mimes->next) {
254 GOFileSaver *fs = go_file_saver_for_mime_type
255 (mimes->data);
256 if (fs != NULL)
257 fsavers = g_slist_prepend (fsavers, fs);
259 switch (type) {
260 case GNM_FILE_OPEN_STYLE_OPEN:
261 for (fl = fsavers; fl; fl = fl->next) {
262 GOFileSaver *fs = GO_FILE_SAVER (fl->data);
263 if ((go_file_saver_get_save_scope (fs)
264 != GO_FILE_SAVE_RANGE) &&
265 (go_file_saver_get_format_level (fs)
266 == GO_FILE_FL_AUTO)) {
267 openers = g_list_prepend
268 (openers, fo);
269 break;
272 break;
273 case GNM_FILE_OPEN_STYLE_IMPORT:
275 gboolean is_open = FALSE;
276 for (fl = fsavers; fl; fl = fl->next) {
277 GOFileSaver *fs = GO_FILE_SAVER
278 (fl->data);
279 if ((go_file_saver_get_save_scope
280 (fs)
281 != GO_FILE_SAVE_RANGE) &&
282 (go_file_saver_get_format_level
283 (fs)
284 == GO_FILE_FL_AUTO)) {
285 is_open = TRUE;
286 break;
289 if (!(is_open))
290 openers = g_list_prepend
291 (openers, fo);
292 break;
295 g_slist_free (fsavers);
297 openers = g_list_sort (openers, file_opener_description_cmp);
298 /* NULL represents automatic file type recognition */
299 openers = g_list_prepend (openers, NULL);
302 opener_default = file_opener_find_by_id (openers, default_format);
304 if (opener_default != 0)
305 title = (go_file_opener_get_description
306 (g_list_nth_data (openers, opener_default)));
307 if (title == NULL)
308 switch (type) {
309 case GNM_FILE_OPEN_STYLE_OPEN:
310 title = _("Open Spreadsheet File");
311 break;
312 case GNM_FILE_OPEN_STYLE_IMPORT:
313 title = _("Import Data File");
314 break;
316 data.openers = openers;
318 /* Make charmap chooser */
319 go_charmap_sel = go_charmap_sel_new (GO_CHARMAP_SEL_TO_UTF8);
320 data.go_charmap_sel = GO_CHARMAP_SEL(go_charmap_sel);
321 data.charmap_label = gtk_label_new_with_mnemonic (_("Character _encoding:"));
323 /* Make format chooser */
324 format_combo = GTK_COMBO_BOX (gtk_combo_box_text_new ());
325 make_format_chooser (openers, format_combo);
326 g_signal_connect (G_OBJECT (format_combo), "changed",
327 G_CALLBACK (file_opener_format_changed_cb), &data);
328 gtk_combo_box_set_active (format_combo, opener_default);
329 gtk_widget_set_sensitive (GTK_WIDGET (format_combo), opener_default == 0);
330 file_opener_format_changed_cb (format_combo, &data);
332 fsel = GTK_FILE_CHOOSER
333 (g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
334 "action", GTK_FILE_CHOOSER_ACTION_OPEN,
335 "local-only", FALSE,
336 "title", title,
337 "select-multiple", TRUE,
338 NULL));
340 advanced_button = gtk_button_new_with_mnemonic (_("Advanc_ed"));
341 gtk_widget_show (advanced_button);
342 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (fsel))),
343 advanced_button, FALSE, TRUE, 6);
344 gtk_dialog_add_buttons (GTK_DIALOG (fsel),
345 GNM_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
346 GNM_STOCK_OPEN, GTK_RESPONSE_OK,
347 NULL);
348 gtk_dialog_set_default_response (GTK_DIALOG (fsel), GTK_RESPONSE_OK);
350 /* Add Templates bookmark */
352 char *templates = g_build_filename (gnm_sys_data_dir (), "templates", NULL);
353 gtk_file_chooser_add_shortcut_folder (fsel, templates, NULL);
354 g_free (templates);
357 /* Start in the same directory as the current workbook. */
358 gtk_file_chooser_select_uri (fsel, go_doc_get_uri (GO_DOC (workbook)));
359 gtk_file_chooser_unselect_all (fsel);
361 /* Filters */
363 GtkFileFilter *filter;
364 char const *filter_name = NULL;
366 filter = gtk_file_filter_new ();
367 gtk_file_filter_set_name (filter, _("All Files"));
368 gtk_file_filter_add_pattern (filter, "*");
369 gtk_file_chooser_add_filter (fsel, filter);
371 filter = gnm_app_create_opener_filter (openers);
372 if (default_format != NULL) {
373 if (0 == strcmp (default_format,
374 "Gnumeric_stf:stf_assistant"))
375 filter_name = _("Text Files");
377 if (filter_name == NULL)
378 switch (type) {
379 case GNM_FILE_OPEN_STYLE_OPEN:
380 filter_name = _("Spreadsheets");
381 break;
382 case GNM_FILE_OPEN_STYLE_IMPORT:
383 filter_name = _("Data Files");
384 break;
386 gtk_file_filter_set_name (filter, filter_name);
387 gtk_file_chooser_add_filter (fsel, filter);
388 /* Make this filter the default */
389 gtk_file_chooser_set_filter (fsel, filter);
393 GtkWidget *label;
394 GtkWidget *grid = gtk_grid_new ();
396 g_object_set (grid,
397 "column-spacing", 12,
398 "row-spacing", 6,
399 NULL);
400 gtk_widget_set_hexpand (GTK_WIDGET (format_combo), TRUE);
401 gtk_grid_attach (GTK_GRID (grid),
402 GTK_WIDGET (format_combo),
403 1, 0, 1, 1);
404 label = gtk_label_new_with_mnemonic (_("File _type:"));
405 gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
406 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (format_combo));
408 gtk_widget_set_hexpand (go_charmap_sel, TRUE);
409 gtk_grid_attach (GTK_GRID (grid), go_charmap_sel, 1, 1, 1, 1);
410 gtk_grid_attach (GTK_GRID (grid), data.charmap_label, 0, 1, 1, 1);
411 gtk_label_set_mnemonic_widget (GTK_LABEL (data.charmap_label),
412 go_charmap_sel);
414 g_object_ref_sink (grid);
415 g_object_set_data_full (G_OBJECT (advanced_button), "extra",
416 grid, g_object_unref);
417 gtk_widget_show_all (grid);
418 g_signal_connect (G_OBJECT (advanced_button),
419 "clicked",
420 G_CALLBACK (cb_advanced_clicked),
421 fsel);
424 /* Show file selector */
425 if (!go_gtk_file_sel_dialog (wbcg_toplevel (wbcg), GTK_WIDGET (fsel)))
426 goto out;
428 uris = gtk_file_chooser_get_uris (fsel);
429 encoding = go_charmap_sel_get_encoding (GO_CHARMAP_SEL (go_charmap_sel));
430 fo = g_list_nth_data (openers, gtk_combo_box_get_active (format_combo));
432 out:
433 gtk_widget_destroy (GTK_WIDGET (fsel));
434 g_list_free (openers);
436 while (uris) {
437 char *uri = uris->data;
438 GSList *hook = uris;
440 /* Make sure dialog goes away right now. */
441 while (g_main_context_iteration (NULL, FALSE));
443 gui_file_read (wbcg, uri, fo, encoding);
444 g_free (uri);
446 uris = uris->next;
447 g_slist_free_1 (hook);
451 static gboolean
452 check_multiple_sheet_support_if_needed (GOFileSaver *fs,
453 GtkWindow *parent,
454 WorkbookView *wb_view)
456 gboolean ret_val = TRUE;
458 if (go_file_saver_get_save_scope (fs) != GO_FILE_SAVE_WORKBOOK &&
459 gnm_conf_get_core_file_save_single_sheet ()) {
460 Workbook *wb = wb_view_get_workbook (wb_view);
461 const char *msg =
462 _("Selected file format doesn't support "
463 "saving multiple sheets in one file.\n"
464 "If you want to save all sheets, save them "
465 "in separate files or select different file format.\n"
466 "Do you want to save only current sheet?");
467 if (workbook_sheet_count (wb) > 1) {
468 ret_val = go_gtk_query_yes_no (parent, TRUE, "%s", msg);
471 return (ret_val);
474 static gboolean
475 extension_check_disabled (GOFileSaver *fs)
477 GSList *list = gnm_conf_get_core_file_save_extension_check_disabled ();
478 char const *id = go_file_saver_get_id (fs);
480 return (NULL != g_slist_find_custom (list, id, go_str_compare));
483 typedef struct {
484 GtkFileChooser *fsel;
485 GList *savers;
486 } file_saver_format_changed_cb_data;
489 * Change or add the extension for the newly chosen saver to the file
490 * name in the file chooser.
492 static void
493 file_saver_format_changed_cb (GtkComboBox *format_combo,
494 file_saver_format_changed_cb_data *data)
496 GOFileSaver *fs = g_list_nth_data (data->savers, gtk_combo_box_get_active (format_combo));
497 char *uri = gtk_file_chooser_get_uri (data->fsel);
498 char *basename = NULL, *newname = NULL, *dot;
499 char const *ext = go_file_saver_get_extension (fs);
501 if (!uri || !ext)
502 goto out;
504 basename = go_basename_from_uri (uri);
505 if (!basename)
506 goto out;
508 dot = strchr (basename, '.');
509 if (dot)
510 *dot = 0;
512 newname = g_strconcat (basename, ".", ext, NULL);
513 gtk_file_chooser_set_current_name (data->fsel, newname);
515 out:
516 g_free (uri);
517 g_free (basename);
518 g_free (newname);
521 gboolean
522 gui_file_save_as (WBCGtk *wbcg, WorkbookView *wb_view, GnmFileSaveAsStyle type,
523 char const *default_format)
525 GList *savers = NULL, *l;
526 GtkFileChooser *fsel;
527 GtkComboBox *format_combo;
528 GOFileSaver *fs;
529 file_saver_format_changed_cb_data data;
530 gboolean success = FALSE;
531 gchar const *wb_uri;
532 char *uri;
533 Workbook *wb;
534 WBCGtk *wbcg2;
535 char const *title = (type == GNM_FILE_SAVE_AS_STYLE_SAVE) ? _("Save the current workbook as")
536 : _("Export the current workbook or sheet to");
538 g_return_val_if_fail (wbcg != NULL, FALSE);
540 wb = wb_view_get_workbook (wb_view);
541 wbcg2 = wbcg_find_for_workbook (wb, wbcg, NULL, NULL);
543 for (l = go_get_file_savers (); l; l = l->next)
544 switch (type) {
545 case GNM_FILE_SAVE_AS_STYLE_SAVE:
546 if ((l->data == NULL) ||
547 ((go_file_saver_get_save_scope (GO_FILE_SAVER (l->data))
548 != GO_FILE_SAVE_RANGE) &&
549 (go_file_saver_get_format_level (GO_FILE_SAVER (l->data))
550 == GO_FILE_FL_AUTO)))
551 savers = g_list_prepend (savers, l->data);
552 break;
553 case GNM_FILE_SAVE_AS_STYLE_EXPORT:
554 default:
555 if ((l->data == NULL) ||
556 ((go_file_saver_get_save_scope (GO_FILE_SAVER (l->data))
557 != GO_FILE_SAVE_RANGE) &&
558 (go_file_saver_get_format_level (GO_FILE_SAVER (l->data))
559 != GO_FILE_FL_AUTO)))
560 savers = g_list_prepend (savers, l->data);
561 break;
563 data.savers = savers = g_list_sort (savers, file_saver_description_cmp);
565 data.fsel = fsel = GTK_FILE_CHOOSER
566 (g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
567 "action", GTK_FILE_CHOOSER_ACTION_SAVE,
568 "local-only", FALSE,
569 "title", title,
570 NULL));
571 gtk_dialog_add_buttons (GTK_DIALOG (fsel),
572 GNM_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
573 GNM_STOCK_SAVE, GTK_RESPONSE_OK,
574 NULL);
576 gtk_dialog_set_default_response (GTK_DIALOG (fsel), GTK_RESPONSE_OK);
578 /* Filters */
580 GtkFileFilter *filter;
581 GList *l;
583 filter = gtk_file_filter_new ();
584 gtk_file_filter_set_name (filter, _("All Files"));
585 gtk_file_filter_add_pattern (filter, "*");
586 gtk_file_chooser_add_filter (fsel, filter);
588 filter = gtk_file_filter_new ();
589 gtk_file_filter_set_name (filter, _("Spreadsheets"));
590 for (l = savers; l; l = l->next) {
591 GOFileSaver *fs = l->data;
592 char const *ext = go_file_saver_get_extension (fs);
593 char const *mime = go_file_saver_get_mime_type (fs);
595 if (mime)
596 gtk_file_filter_add_mime_type (filter, mime);
598 #warning "FIXME: do we get all extensions?"
599 /* Well, we don't get things we cannot save. */
600 if (ext) {
601 char *pattern = g_strconcat ("*.", ext, NULL);
602 gtk_file_filter_add_pattern (filter, pattern);
603 g_free (pattern);
606 gtk_file_chooser_add_filter (fsel, filter);
607 /* Make this filter the default */
608 gtk_file_chooser_set_filter (fsel, filter);
612 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
613 GtkWidget *label = gtk_label_new_with_mnemonic (_("File _type:"));
614 format_combo = GTK_COMBO_BOX (gtk_combo_box_text_new ());
615 make_format_chooser (savers, format_combo);
616 g_signal_connect (G_OBJECT (format_combo), "changed",
617 G_CALLBACK (file_saver_format_changed_cb), &data);
619 gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 6);
620 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (format_combo), FALSE, TRUE, 6);
621 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (format_combo));
623 gtk_widget_show_all (box);
624 gtk_file_chooser_set_extra_widget (fsel, box);
627 /* Set default file saver */
628 if (type == GNM_FILE_SAVE_AS_STYLE_SAVE) {
629 fs = workbook_get_file_saver (wb);
630 if (!fs || g_list_find (savers, fs) == NULL)
631 fs = go_file_saver_get_default ();
632 } else {
633 if (default_format)
634 fs = go_file_saver_for_id (default_format);
635 else
636 fs = workbook_get_file_exporter (wb);
637 if (!fs || g_list_find (savers, fs) == NULL)
638 fs = go_file_saver_for_id ("Gnumeric_html:latex_table");
641 gtk_combo_box_set_active (format_combo, g_list_index (savers, fs));
643 /* Set default file name */
644 if (type == GNM_FILE_SAVE_AS_STYLE_EXPORT) {
645 char *basename, *dot, *newname;
646 char const *ext = go_file_saver_get_extension (fs);
648 wb_uri = workbook_get_last_export_uri (wb);
649 if (!wb_uri || fs != workbook_get_file_exporter (wb))
650 wb_uri = go_doc_get_uri (GO_DOC (wb));
651 if (!wb_uri) wb_uri = _("Untitled");
652 if (!ext) ext = "txt";
654 basename = go_basename_from_uri (wb_uri);
655 dot = strrchr (basename, '.');
656 if (dot) *dot = 0;
657 newname = g_strconcat (basename, ".", ext, NULL);
659 gtk_file_chooser_set_uri (fsel, wb_uri);
660 gtk_file_chooser_set_current_name (fsel, newname);
662 g_free (basename);
663 g_free (newname);
664 } else {
665 char *basename;
667 wb_uri = go_doc_get_uri (GO_DOC (wb));
668 if (!wb_uri) wb_uri = _("Untitled");
669 basename = go_basename_from_uri (wb_uri);
672 * If the file exists, the following is dominated by the
673 * final set_uri. If the file does not exist, we get the
674 * directory from the first set_uri and the basename set
675 * with set_current_name.
677 gtk_file_chooser_set_uri (fsel, wb_uri);
678 gtk_file_chooser_set_current_name (fsel, basename);
679 gtk_file_chooser_set_uri (fsel, wb_uri);
681 g_free (basename);
684 while (1) {
685 char *uri2 = NULL;
687 /* Show file selector */
688 if (!go_gtk_file_sel_dialog (wbcg_toplevel (wbcg), GTK_WIDGET (fsel)))
689 goto out;
690 fs = g_list_nth_data (savers, gtk_combo_box_get_active (format_combo));
691 if (!fs)
692 goto out;
693 uri = gtk_file_chooser_get_uri (fsel);
694 if (!go_url_check_extension (uri,
695 go_file_saver_get_extension (fs),
696 &uri2) &&
697 !extension_check_disabled (fs) &&
698 !go_gtk_query_yes_no (GTK_WINDOW (fsel),
699 TRUE,
700 _("The given file extension does not match the"
701 " chosen file type. Do you want to use this name"
702 " anyway?"))) {
703 g_free (uri);
704 g_free (uri2);
705 uri = NULL;
706 continue;
709 g_free (uri);
710 uri = uri2;
712 if (go_gtk_url_is_writeable (GTK_WINDOW (fsel), uri,
713 gnm_conf_get_core_file_save_def_overwrite ()))
714 break;
716 g_free (uri);
719 if (wbcg2) {
720 GtkWidget *nb = GTK_WIDGET (wbcg2->notebook_area);
721 GtkAllocation a;
722 gtk_widget_get_allocation (nb, &a);
723 wb_view_preferred_size (wb_view, a.width, a.height);
726 success = check_multiple_sheet_support_if_needed (fs, GTK_WINDOW (fsel), wb_view);
727 if (success) {
728 /* Destroy early so no-one can repress the Save button. */
729 gtk_widget_destroy (GTK_WIDGET (fsel));
730 fsel = NULL;
731 if (workbook_view_save_as (wb_view, fs, uri, GO_CMD_CONTEXT (wbcg)))
732 workbook_update_history (wb, type);
735 g_free (uri);
737 out:
738 if (fsel)
739 gtk_widget_destroy (GTK_WIDGET (fsel));
740 g_list_free (savers);
742 return success;
745 static gboolean
746 warn_about_overwrite (WBCGtk *wbcg,
747 GDateTime *modtime,
748 GDateTime *known_modtime)
750 GtkWidget *dialog;
751 int response;
752 char *shortname, *filename, *longname, *duri, *modtxt;
753 Workbook *wb = wb_control_get_workbook (GNM_WBC (wbcg));
754 const char *uri;
755 GDateTime *modtime_local;
757 uri = go_doc_get_uri (GO_DOC (wb));
758 filename = go_filename_from_uri (uri);
759 if (filename) {
760 shortname = g_filename_display_basename (filename);
761 } else {
762 shortname = g_filename_display_basename (uri);
765 duri = g_uri_unescape_string (uri, NULL);
766 longname = duri
767 ? g_filename_display_name (duri)
768 : g_strdup (uri);
770 modtime_local = g_date_time_to_local (modtime);
771 modtxt = g_date_time_format (modtime_local, _("%F %T"));
772 g_date_time_unref (modtime_local);
774 dialog = gtk_message_dialog_new_with_markup
775 (wbcg_toplevel (wbcg),
776 GTK_DIALOG_DESTROY_WITH_PARENT,
777 GTK_MESSAGE_WARNING,
778 GTK_BUTTONS_NONE,
779 _("The file you are about to save has changed on disk. If you continue, you will overwrite someone else's changes.\n\n"
780 "File: <b>%s</b>\n"
781 "Location: %s\n\n"
782 "Last modified: <b>%s</b>\n"),
783 shortname, longname, modtxt);
784 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
785 _("Overwrite"), GTK_RESPONSE_YES,
786 _("Cancel"), GTK_RESPONSE_NO,
787 NULL);
788 g_free (shortname);
789 g_free (longname);
790 g_free (duri);
791 g_free (filename);
792 g_free (modtxt);
794 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_NO);
795 response = go_gtk_dialog_run (GTK_DIALOG (dialog),
796 wbcg_toplevel (wbcg));
797 return response == GTK_RESPONSE_YES;
800 gboolean
801 gui_file_save (WBCGtk *wbcg, WorkbookView *wb_view)
803 Workbook *wb = wb_view_get_workbook (wb_view);
804 WBCGtk *wbcg2 =
805 wbcg_find_for_workbook (wb, wbcg, NULL, NULL);
807 if (wbcg2) {
808 GtkWidget *nb = GTK_WIDGET (wbcg2->notebook_area);
809 GtkAllocation a;
810 gtk_widget_get_allocation (nb, &a);
811 wb_view_preferred_size (wb_view, a.width, a.height);
814 if (wb->file_format_level < GO_FILE_FL_AUTO)
815 return gui_file_save_as (wbcg, wb_view,
816 GNM_FILE_SAVE_AS_STYLE_SAVE, NULL);
817 else {
818 gboolean ok = TRUE;
819 const char *uri = go_doc_get_uri (GO_DOC (wb));
820 GDateTime *known_modtime = go_doc_get_modtime (GO_DOC (wb));
821 GDateTime *modtime = go_file_get_modtime (uri);
822 gboolean debug_modtime = gnm_debug_flag ("modtime");
824 /* We need a ref because a Ctrl-Q at the wrong time will
825 cause the workbook to disappear at the end of the
826 save. */
827 g_object_ref (wb);
829 if (modtime && known_modtime) {
830 if (g_date_time_equal (known_modtime, modtime)) {
831 if (debug_modtime)
832 g_printerr ("Modtime match\n");
833 } else {
834 if (debug_modtime)
835 g_printerr ("Modtime mismatch\n");
836 ok = warn_about_overwrite (wbcg, modtime, known_modtime);
840 if (ok)
841 ok = workbook_view_save (wb_view, GO_CMD_CONTEXT (wbcg));
842 if (ok)
843 workbook_update_history (wb, GNM_FILE_SAVE_AS_STYLE_SAVE);
844 g_object_unref (wb);
846 if (modtime)
847 g_date_time_unref (modtime);
849 return ok;
853 gboolean
854 gui_file_export_repeat (WBCGtk *wbcg)
856 WorkbookView *wb_view = wb_control_view (GNM_WBC (wbcg));
857 Workbook *wb = wb_view_get_workbook (wb_view);
858 GOFileSaver *fs = workbook_get_file_exporter (wb);
859 gchar const *last_uri = workbook_get_last_export_uri (wb);
861 if (fs != NULL && last_uri != NULL) {
862 char const *msg;
863 GtkWidget *dialog;
865 if (go_file_saver_get_save_scope (fs) != GO_FILE_SAVE_WORKBOOK)
866 msg = _("Do you want to export the <b>current sheet</b> of this "
867 "workbook to the location '<b>%s</b>' "
868 "using the '<b>%s</b>' exporter?");
869 else
870 msg = _("Do you want to export this workbook to the "
871 "location '<b>%s</b>' "
872 "using the '<b>%s</b>' exporter?");
874 /* go_gtk_query_yes_no does not handle markup ... */
875 dialog = gtk_message_dialog_new_with_markup (wbcg_toplevel (wbcg),
876 GTK_DIALOG_DESTROY_WITH_PARENT,
877 GTK_MESSAGE_QUESTION,
878 GTK_BUTTONS_YES_NO,
879 msg, last_uri,
880 go_file_saver_get_description (fs));
881 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
883 if (GTK_RESPONSE_YES ==
884 go_gtk_dialog_run (GTK_DIALOG (dialog), wbcg_toplevel (wbcg))) {
885 /* We need to copy wb->last_export_uri since it will be reset during saving */
886 gchar *uri = g_strdup (last_uri);
887 if(workbook_view_save_as (wb_view, fs, uri, GO_CMD_CONTEXT (wbcg))) {
888 workbook_update_history (wb, GNM_FILE_SAVE_AS_STYLE_EXPORT);
889 g_free (uri);
890 return TRUE;
892 g_free (uri);
894 return FALSE;
895 } else {
896 go_gtk_notice_dialog (wbcg_toplevel (wbcg), GTK_MESSAGE_ERROR,
897 _("Unable to repeat export since no previous "
898 "export information has been saved in this "
899 "session."));
900 return FALSE;