Update Spanish translation
[gnumeric.git] / src / gui-file.c
blob118e13d8fc9978d940f2bdedf140b69a610f5a68
1 /*
2 * GUI-file.c:
4 * Authors:
5 * Jon K Hellan (hellan@acm.org)
6 * Zbigniew Chyla (cyba@gnome.pl)
7 * Andreas J. Guelzow (aguelzow@pyrshep.ca)
8 */
9 #include <gnumeric-config.h>
10 #include <glib/gi18n-lib.h>
11 #include <gnumeric.h>
12 #include <gui-file.h>
14 #include <gui-util.h>
15 #include <gutils.h>
16 #include <dialogs/dialogs.h>
17 #include <sheet.h>
18 #include <application.h>
19 #include <command-context.h>
20 #include <wbc-gtk-impl.h>
21 #include <workbook-view.h>
22 #include <workbook-priv.h>
23 #include <gnumeric-conf.h>
24 #include <application.h>
26 #include <goffice/goffice.h>
28 #include <unistd.h>
29 #include <string.h>
31 typedef struct {
32 GOCharmapSel *go_charmap_sel;
33 GtkWidget *charmap_label;
34 GList *openers;
35 } file_opener_format_changed_cb_data;
39 static gint
40 file_opener_description_cmp (gconstpointer a, gconstpointer b)
42 GOFileOpener const *fo_a = a, *fo_b = b;
44 return g_utf8_collate (go_file_opener_get_description (fo_a),
45 go_file_opener_get_description (fo_b));
48 static gint
49 file_saver_description_cmp (gconstpointer a, gconstpointer b)
51 GOFileSaver const *fs_a = a, *fs_b = b;
53 return g_utf8_collate (go_file_saver_get_description (fs_a),
54 go_file_saver_get_description (fs_b));
57 static void
58 make_format_chooser (GList *list, GtkComboBox *combo)
60 GList *l;
61 GtkComboBoxText *bt = GTK_COMBO_BOX_TEXT (combo);
63 /* Make format chooser */
64 for (l = list; l != NULL; l = l->next) {
65 GObject *obj = l->data;
66 gchar const *descr;
68 if (!obj)
69 descr = _("Automatically detected");
70 else if (GO_IS_FILE_OPENER (obj))
71 descr = go_file_opener_get_description (GO_FILE_OPENER (obj));
72 else
73 descr = go_file_saver_get_description (GO_FILE_SAVER (obj));
75 gtk_combo_box_text_append_text (bt, descr);
79 /* Show view in a wbcg. Use current or new wbcg according to policy */
80 void
81 gui_wb_view_show (WBCGtk *wbcg, WorkbookView *wbv)
83 WBCGtk *new_wbcg = NULL;
84 Workbook *tmp_wb = wb_control_get_workbook (GNM_WBC (wbcg));
86 if (go_doc_is_pristine (GO_DOC (tmp_wb))) {
87 g_object_ref (wbcg);
88 g_object_unref (tmp_wb);
89 wb_control_set_view (GNM_WBC (wbcg), wbv, NULL);
90 wb_control_init_state (GNM_WBC (wbcg));
91 } else {
92 GdkScreen *screen = gtk_window_get_screen (wbcg_toplevel (wbcg));
93 WorkbookControl *new_wbc =
94 workbook_control_new_wrapper (GNM_WBC (wbcg),
95 wbv, NULL, screen);
96 new_wbcg = WBC_GTK (new_wbc);
98 wbcg_copy_toolbar_visibility (new_wbcg, wbcg);
101 sheet_update (wb_view_cur_sheet (wbv));
105 * gui_file_read:
107 * Returns: (transfer none): the new #WorkbookView for the file read.
109 WorkbookView *
110 gui_file_read (WBCGtk *wbcg, char const *uri,
111 GOFileOpener const *optional_format, gchar const *optional_encoding)
113 GOIOContext *io_context;
114 WorkbookView *wbv;
116 go_cmd_context_set_sensitive (GO_CMD_CONTEXT (wbcg), FALSE);
117 io_context = go_io_context_new (GO_CMD_CONTEXT (wbcg));
118 wbv = workbook_view_new_from_uri (uri, optional_format, io_context,
119 optional_encoding);
121 if (go_io_error_occurred (io_context) ||
122 go_io_warning_occurred (io_context))
123 go_io_error_display (io_context);
125 g_object_unref (io_context);
126 go_cmd_context_set_sensitive (GO_CMD_CONTEXT (wbcg), TRUE);
128 if (wbv != NULL) {
129 gui_wb_view_show (wbcg, wbv);
130 workbook_update_history (wb_view_get_workbook (wbv), GNM_FILE_SAVE_AS_STYLE_SAVE);
131 } else {
132 /* Somehow fixes #625687. Don't know why. */
133 wbcg_focus_cur_scg (wbcg);
136 return wbv;
139 gboolean
140 gnm_gui_file_template (WBCGtk *wbcg, char const *uri)
142 GOIOContext *io_context;
143 WorkbookView *wbv;
144 GOFileOpener const *optional_format = NULL;
145 gchar const *optional_encoding = NULL;
147 go_cmd_context_set_sensitive (GO_CMD_CONTEXT (wbcg), FALSE);
148 io_context = go_io_context_new (GO_CMD_CONTEXT (wbcg));
149 wbv = workbook_view_new_from_uri (uri, optional_format, io_context,
150 optional_encoding);
152 if (go_io_error_occurred (io_context) ||
153 go_io_warning_occurred (io_context))
154 go_io_error_display (io_context);
156 g_object_unref (io_context);
157 go_cmd_context_set_sensitive (GO_CMD_CONTEXT (wbcg), TRUE);
159 if (wbv != NULL) {
160 Workbook *wb = wb_view_get_workbook (wbv);
161 workbook_set_saveinfo (wb, GO_FILE_FL_NEW, NULL);
162 gui_wb_view_show (wbcg, wbv);
163 return TRUE;
165 return FALSE;
168 static void
169 file_opener_format_changed_cb (GtkComboBox *format_combo,
170 file_opener_format_changed_cb_data *data)
172 GOFileOpener *fo = g_list_nth_data (data->openers,
173 gtk_combo_box_get_active (format_combo));
174 gboolean is_sensitive = fo != NULL && go_file_opener_is_encoding_dependent (fo);
176 gtk_widget_set_sensitive (GTK_WIDGET (data->go_charmap_sel), is_sensitive);
177 gtk_widget_set_sensitive (data->charmap_label, is_sensitive);
181 static gint
182 file_opener_find_by_id (GList *openers, char const *id)
184 GList *l;
185 gint i = 0;
187 if (id == NULL)
188 return 0;
190 for (l = openers; l != NULL; l = l->next, i++) {
191 if (GO_IS_FILE_OPENER (l->data) &&
192 strcmp (id, go_file_opener_get_id(l->data)) == 0)
193 return i;
196 return 0;
199 static void
200 cb_advanced_clicked (GtkButton *advanced, GtkFileChooser *fsel)
202 GtkWidget *extra = g_object_get_data (G_OBJECT (advanced), "extra");
204 gtk_button_set_use_underline (advanced, TRUE);
205 if (gtk_file_chooser_get_extra_widget (fsel)) {
206 /* xgettext: If possible try to use the same mnemonic for
207 * Advanced and Simple */
208 gtk_button_set_label (advanced, _("Advanc_ed"));
209 gtk_file_chooser_set_extra_widget (fsel, NULL);
210 } else {
211 gtk_button_set_label (advanced, _("Simpl_e"));
212 gtk_file_chooser_set_extra_widget (fsel, extra);
217 * Suggests automatic file type recognition, but lets the user choose an
218 * import filter for selected file.
220 void
221 gui_file_open (WBCGtk *wbcg, GnmFileOpenStyle type, char const *default_format)
223 GList *openers = NULL, *all_openers, *l;
224 GtkFileChooser *fsel;
225 GtkWidget *advanced_button;
226 GtkComboBox *format_combo;
227 GtkWidget *go_charmap_sel;
228 file_opener_format_changed_cb_data data;
229 gint opener_default;
230 char const *title = NULL;
231 GSList *uris = NULL;
232 char const *encoding = NULL;
233 GOFileOpener *fo = NULL;
234 Workbook *workbook = wb_control_get_workbook (GNM_WBC (wbcg));
236 all_openers = go_get_file_openers ();
238 if (default_format != NULL) {
239 fo = go_file_opener_for_id (default_format);
242 if (fo != NULL)
243 openers = g_list_prepend (NULL, fo);
244 else {
245 for (l = all_openers; l; l = l->next)
246 if (l->data != NULL) {
247 GOFileOpener *fo = l->data;
248 GSList const *mimes = go_file_opener_get_mimes (fo);
249 GSList *fsavers = NULL, *fl;
251 for (; mimes; mimes = mimes->next) {
252 GOFileSaver *fs = go_file_saver_for_mime_type
253 (mimes->data);
254 if (fs != NULL)
255 fsavers = g_slist_prepend (fsavers, fs);
257 switch (type) {
258 case GNM_FILE_OPEN_STYLE_OPEN:
259 for (fl = fsavers; fl; fl = fl->next) {
260 GOFileSaver *fs = GO_FILE_SAVER (fl->data);
261 if ((go_file_saver_get_save_scope (fs)
262 != GO_FILE_SAVE_RANGE) &&
263 (go_file_saver_get_format_level (fs)
264 == GO_FILE_FL_AUTO)) {
265 openers = g_list_prepend
266 (openers, fo);
267 break;
270 break;
271 case GNM_FILE_OPEN_STYLE_IMPORT:
273 gboolean is_open = FALSE;
274 for (fl = fsavers; fl; fl = fl->next) {
275 GOFileSaver *fs = GO_FILE_SAVER
276 (fl->data);
277 if ((go_file_saver_get_save_scope
278 (fs)
279 != GO_FILE_SAVE_RANGE) &&
280 (go_file_saver_get_format_level
281 (fs)
282 == GO_FILE_FL_AUTO)) {
283 is_open = TRUE;
284 break;
287 if (!(is_open))
288 openers = g_list_prepend
289 (openers, fo);
290 break;
293 g_slist_free (fsavers);
295 openers = g_list_sort (openers, file_opener_description_cmp);
296 /* NULL represents automatic file type recognition */
297 openers = g_list_prepend (openers, NULL);
300 opener_default = file_opener_find_by_id (openers, default_format);
302 if (opener_default != 0)
303 title = (go_file_opener_get_description
304 (g_list_nth_data (openers, opener_default)));
305 if (title == NULL)
306 switch (type) {
307 case GNM_FILE_OPEN_STYLE_OPEN:
308 title = _("Open Spreadsheet File");
309 break;
310 case GNM_FILE_OPEN_STYLE_IMPORT:
311 title = _("Import Data File");
312 break;
314 data.openers = openers;
316 /* Make charmap chooser */
317 go_charmap_sel = go_charmap_sel_new (GO_CHARMAP_SEL_TO_UTF8);
318 data.go_charmap_sel = GO_CHARMAP_SEL(go_charmap_sel);
319 data.charmap_label = gtk_label_new_with_mnemonic (_("Character _encoding:"));
321 /* Make format chooser */
322 format_combo = GTK_COMBO_BOX (gtk_combo_box_text_new ());
323 make_format_chooser (openers, format_combo);
324 g_signal_connect (G_OBJECT (format_combo), "changed",
325 G_CALLBACK (file_opener_format_changed_cb), &data);
326 gtk_combo_box_set_active (format_combo, opener_default);
327 gtk_widget_set_sensitive (GTK_WIDGET (format_combo), opener_default == 0);
328 file_opener_format_changed_cb (format_combo, &data);
330 fsel = GTK_FILE_CHOOSER
331 (g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
332 "action", GTK_FILE_CHOOSER_ACTION_OPEN,
333 "local-only", FALSE,
334 "title", title,
335 "select-multiple", TRUE,
336 NULL));
338 advanced_button = gtk_button_new_with_mnemonic (_("Advanc_ed"));
339 gtk_widget_show (advanced_button);
340 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (fsel))),
341 advanced_button, FALSE, TRUE, 6);
342 gtk_dialog_add_buttons (GTK_DIALOG (fsel),
343 GNM_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
344 GNM_STOCK_OPEN, GTK_RESPONSE_OK,
345 NULL);
346 gtk_dialog_set_default_response (GTK_DIALOG (fsel), GTK_RESPONSE_OK);
348 /* Add Templates bookmark */
350 char *templates = g_build_filename (gnm_sys_data_dir (), "templates", NULL);
351 gtk_file_chooser_add_shortcut_folder (fsel, templates, NULL);
352 g_free (templates);
355 /* Start in the same directory as the current workbook. */
356 gtk_file_chooser_select_uri (fsel, go_doc_get_uri (GO_DOC (workbook)));
357 gtk_file_chooser_unselect_all (fsel);
359 /* Filters */
361 GtkFileFilter *filter;
362 char const *filter_name = NULL;
364 filter = gtk_file_filter_new ();
365 gtk_file_filter_set_name (filter, _("All Files"));
366 gtk_file_filter_add_pattern (filter, "*");
367 gtk_file_chooser_add_filter (fsel, filter);
369 filter = gnm_app_create_opener_filter (openers);
370 if (default_format != NULL) {
371 if (0 == strcmp (default_format,
372 "Gnumeric_stf:stf_assistant"))
373 filter_name = _("Text Files");
375 if (filter_name == NULL)
376 switch (type) {
377 case GNM_FILE_OPEN_STYLE_OPEN:
378 filter_name = _("Spreadsheets");
379 break;
380 case GNM_FILE_OPEN_STYLE_IMPORT:
381 filter_name = _("Data Files");
382 break;
384 gtk_file_filter_set_name (filter, filter_name);
385 gtk_file_chooser_add_filter (fsel, filter);
386 /* Make this filter the default */
387 gtk_file_chooser_set_filter (fsel, filter);
391 GtkWidget *label;
392 GtkWidget *grid = gtk_grid_new ();
394 g_object_set (grid,
395 "column-spacing", 12,
396 "row-spacing", 6,
397 NULL);
398 gtk_widget_set_hexpand (GTK_WIDGET (format_combo), TRUE);
399 gtk_grid_attach (GTK_GRID (grid),
400 GTK_WIDGET (format_combo),
401 1, 0, 1, 1);
402 label = gtk_label_new_with_mnemonic (_("File _type:"));
403 gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
404 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (format_combo));
406 gtk_widget_set_hexpand (go_charmap_sel, TRUE);
407 gtk_grid_attach (GTK_GRID (grid), go_charmap_sel, 1, 1, 1, 1);
408 gtk_grid_attach (GTK_GRID (grid), data.charmap_label, 0, 1, 1, 1);
409 gtk_label_set_mnemonic_widget (GTK_LABEL (data.charmap_label),
410 go_charmap_sel);
412 g_object_ref_sink (grid);
413 g_object_set_data_full (G_OBJECT (advanced_button), "extra",
414 grid, g_object_unref);
415 gtk_widget_show_all (grid);
416 g_signal_connect (G_OBJECT (advanced_button),
417 "clicked",
418 G_CALLBACK (cb_advanced_clicked),
419 fsel);
422 /* Show file selector */
423 if (!go_gtk_file_sel_dialog (wbcg_toplevel (wbcg), GTK_WIDGET (fsel)))
424 goto out;
426 uris = gtk_file_chooser_get_uris (fsel);
427 encoding = go_charmap_sel_get_encoding (GO_CHARMAP_SEL (go_charmap_sel));
428 fo = g_list_nth_data (openers, gtk_combo_box_get_active (format_combo));
430 out:
431 gtk_widget_destroy (GTK_WIDGET (fsel));
432 g_list_free (openers);
434 while (uris) {
435 char *uri = uris->data;
436 GSList *hook = uris;
438 /* Make sure dialog goes away right now. */
439 while (g_main_context_iteration (NULL, FALSE));
441 gui_file_read (wbcg, uri, fo, encoding);
442 g_free (uri);
444 uris = uris->next;
445 g_slist_free_1 (hook);
449 static gboolean
450 check_multiple_sheet_support_if_needed (GOFileSaver *fs,
451 GtkWindow *parent,
452 WorkbookView *wb_view)
454 gboolean ret_val = TRUE;
456 if (go_file_saver_get_save_scope (fs) != GO_FILE_SAVE_WORKBOOK &&
457 gnm_conf_get_core_file_save_single_sheet ()) {
458 Workbook *wb = wb_view_get_workbook (wb_view);
459 const char *msg =
460 _("Selected file format doesn't support "
461 "saving multiple sheets in one file.\n"
462 "If you want to save all sheets, save them "
463 "in separate files or select different file format.\n"
464 "Do you want to save only current sheet?");
465 if (workbook_sheet_count (wb) > 1) {
466 ret_val = go_gtk_query_yes_no (parent, TRUE, "%s", msg);
469 return (ret_val);
472 static gboolean
473 extension_check_disabled (GOFileSaver *fs)
475 GSList *list = gnm_conf_get_core_file_save_extension_check_disabled ();
476 char const *id = go_file_saver_get_id (fs);
478 return (NULL != g_slist_find_custom (list, id, go_str_compare));
481 typedef struct {
482 GtkFileChooser *fsel;
483 GList *savers;
484 } file_saver_format_changed_cb_data;
487 * Change or add the extension for the newly chosen saver to the file
488 * name in the file chooser.
490 static void
491 file_saver_format_changed_cb (GtkComboBox *format_combo,
492 file_saver_format_changed_cb_data *data)
494 GOFileSaver *fs = g_list_nth_data (data->savers, gtk_combo_box_get_active (format_combo));
495 char *uri = gtk_file_chooser_get_uri (data->fsel);
496 char *basename = NULL, *newname = NULL, *dot;
497 char const *ext = go_file_saver_get_extension (fs);
499 if (!uri || !ext)
500 goto out;
502 basename = go_basename_from_uri (uri);
503 if (!basename)
504 goto out;
506 dot = strchr (basename, '.');
507 if (dot)
508 *dot = 0;
510 newname = g_strconcat (basename, ".", ext, NULL);
511 gtk_file_chooser_set_current_name (data->fsel, newname);
513 out:
514 g_free (uri);
515 g_free (basename);
516 g_free (newname);
519 gboolean
520 gui_file_save_as (WBCGtk *wbcg, WorkbookView *wb_view, GnmFileSaveAsStyle type,
521 char const *default_format)
523 GList *savers = NULL, *l;
524 GtkFileChooser *fsel;
525 GtkComboBox *format_combo;
526 GOFileSaver *fs;
527 file_saver_format_changed_cb_data data;
528 gboolean success = FALSE;
529 gchar const *wb_uri;
530 char *uri;
531 Workbook *wb;
532 WBCGtk *wbcg2;
533 char const *title = (type == GNM_FILE_SAVE_AS_STYLE_SAVE) ? _("Save the current workbook as")
534 : _("Export the current workbook or sheet to");
536 g_return_val_if_fail (wbcg != NULL, FALSE);
538 wb = wb_view_get_workbook (wb_view);
539 wbcg2 = wbcg_find_for_workbook (wb, wbcg, NULL, NULL);
541 for (l = go_get_file_savers (); l; l = l->next)
542 switch (type) {
543 case GNM_FILE_SAVE_AS_STYLE_SAVE:
544 if ((l->data == NULL) ||
545 ((go_file_saver_get_save_scope (GO_FILE_SAVER (l->data))
546 != GO_FILE_SAVE_RANGE) &&
547 (go_file_saver_get_format_level (GO_FILE_SAVER (l->data))
548 == GO_FILE_FL_AUTO)))
549 savers = g_list_prepend (savers, l->data);
550 break;
551 case GNM_FILE_SAVE_AS_STYLE_EXPORT:
552 default:
553 if ((l->data == NULL) ||
554 ((go_file_saver_get_save_scope (GO_FILE_SAVER (l->data))
555 != GO_FILE_SAVE_RANGE) &&
556 (go_file_saver_get_format_level (GO_FILE_SAVER (l->data))
557 != GO_FILE_FL_AUTO)))
558 savers = g_list_prepend (savers, l->data);
559 break;
561 data.savers = savers = g_list_sort (savers, file_saver_description_cmp);
563 data.fsel = fsel = GTK_FILE_CHOOSER
564 (g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
565 "action", GTK_FILE_CHOOSER_ACTION_SAVE,
566 "local-only", FALSE,
567 "title", title,
568 NULL));
569 gtk_dialog_add_buttons (GTK_DIALOG (fsel),
570 GNM_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
571 GNM_STOCK_SAVE, GTK_RESPONSE_OK,
572 NULL);
574 gtk_dialog_set_default_response (GTK_DIALOG (fsel), GTK_RESPONSE_OK);
576 /* Filters */
578 GtkFileFilter *filter;
579 GList *l;
581 filter = gtk_file_filter_new ();
582 gtk_file_filter_set_name (filter, _("All Files"));
583 gtk_file_filter_add_pattern (filter, "*");
584 gtk_file_chooser_add_filter (fsel, filter);
586 filter = gtk_file_filter_new ();
587 gtk_file_filter_set_name (filter, _("Spreadsheets"));
588 for (l = savers; l; l = l->next) {
589 GOFileSaver *fs = l->data;
590 char const *ext = go_file_saver_get_extension (fs);
591 char const *mime = go_file_saver_get_mime_type (fs);
593 if (mime)
594 gtk_file_filter_add_mime_type (filter, mime);
596 #warning "FIXME: do we get all extensions?"
597 /* Well, we don't get things we cannot save. */
598 if (ext) {
599 char *pattern = g_strconcat ("*.", ext, NULL);
600 gtk_file_filter_add_pattern (filter, pattern);
601 g_free (pattern);
604 gtk_file_chooser_add_filter (fsel, filter);
605 /* Make this filter the default */
606 gtk_file_chooser_set_filter (fsel, filter);
610 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
611 GtkWidget *label = gtk_label_new_with_mnemonic (_("File _type:"));
612 format_combo = GTK_COMBO_BOX (gtk_combo_box_text_new ());
613 make_format_chooser (savers, format_combo);
614 g_signal_connect (G_OBJECT (format_combo), "changed",
615 G_CALLBACK (file_saver_format_changed_cb), &data);
617 gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 6);
618 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (format_combo), FALSE, TRUE, 6);
619 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (format_combo));
621 gtk_widget_show_all (box);
622 gtk_file_chooser_set_extra_widget (fsel, box);
625 /* Set default file saver */
626 if (type == GNM_FILE_SAVE_AS_STYLE_SAVE) {
627 fs = workbook_get_file_saver (wb);
628 if (!fs || g_list_find (savers, fs) == NULL)
629 fs = go_file_saver_get_default ();
630 } else {
631 if (default_format)
632 fs = go_file_saver_for_id (default_format);
633 else
634 fs = workbook_get_file_exporter (wb);
635 if (!fs || g_list_find (savers, fs) == NULL)
636 fs = go_file_saver_for_id ("Gnumeric_html:latex_table");
639 gtk_combo_box_set_active (format_combo, g_list_index (savers, fs));
641 /* Set default file name */
642 if (type == GNM_FILE_SAVE_AS_STYLE_EXPORT) {
643 char *basename, *dot, *newname;
644 char const *ext = go_file_saver_get_extension (fs);
646 wb_uri = workbook_get_last_export_uri (wb);
647 if (!wb_uri || fs != workbook_get_file_exporter (wb))
648 wb_uri = go_doc_get_uri (GO_DOC (wb));
649 if (!wb_uri) wb_uri = _("Untitled");
650 if (!ext) ext = "txt";
652 basename = go_basename_from_uri (wb_uri);
653 dot = strrchr (basename, '.');
654 if (dot) *dot = 0;
655 newname = g_strconcat (basename, ".", ext, NULL);
657 gtk_file_chooser_set_uri (fsel, wb_uri);
658 gtk_file_chooser_set_current_name (fsel, newname);
660 g_free (basename);
661 g_free (newname);
662 } else {
663 char *basename;
665 wb_uri = go_doc_get_uri (GO_DOC (wb));
666 if (!wb_uri) wb_uri = _("Untitled");
667 basename = go_basename_from_uri (wb_uri);
670 * If the file exists, the following is dominated by the
671 * final set_uri. If the file does not exist, we get the
672 * directory from the first set_uri and the basename set
673 * with set_current_name.
675 gtk_file_chooser_set_uri (fsel, wb_uri);
676 gtk_file_chooser_set_current_name (fsel, basename);
677 gtk_file_chooser_set_uri (fsel, wb_uri);
679 g_free (basename);
682 while (1) {
683 char *uri2 = NULL;
685 /* Show file selector */
686 if (!go_gtk_file_sel_dialog (wbcg_toplevel (wbcg), GTK_WIDGET (fsel)))
687 goto out;
688 fs = g_list_nth_data (savers, gtk_combo_box_get_active (format_combo));
689 if (!fs)
690 goto out;
691 uri = gtk_file_chooser_get_uri (fsel);
692 if (!go_url_check_extension (uri,
693 go_file_saver_get_extension (fs),
694 &uri2) &&
695 !extension_check_disabled (fs) &&
696 !go_gtk_query_yes_no (GTK_WINDOW (fsel),
697 TRUE,
698 _("The given file extension does not match the"
699 " chosen file type. Do you want to use this name"
700 " anyway?"))) {
701 g_free (uri);
702 g_free (uri2);
703 uri = NULL;
704 continue;
707 g_free (uri);
708 uri = uri2;
710 if (go_gtk_url_is_writeable (GTK_WINDOW (fsel), uri,
711 gnm_conf_get_core_file_save_def_overwrite ()))
712 break;
714 g_free (uri);
717 if (wbcg2) {
718 GtkWidget *nb = GTK_WIDGET (wbcg2->notebook_area);
719 GtkAllocation a;
720 gtk_widget_get_allocation (nb, &a);
721 wb_view_preferred_size (wb_view, a.width, a.height);
724 success = check_multiple_sheet_support_if_needed (fs, GTK_WINDOW (fsel), wb_view);
725 if (success) {
726 /* Destroy early so no-one can repress the Save button. */
727 gtk_widget_destroy (GTK_WIDGET (fsel));
728 fsel = NULL;
729 if (workbook_view_save_as (wb_view, fs, uri, GO_CMD_CONTEXT (wbcg)))
730 workbook_update_history (wb, type);
733 g_free (uri);
735 out:
736 if (fsel)
737 gtk_widget_destroy (GTK_WIDGET (fsel));
738 g_list_free (savers);
740 return success;
743 static gboolean
744 warn_about_overwrite (WBCGtk *wbcg,
745 GDateTime *modtime,
746 GDateTime *known_modtime)
748 GtkWidget *dialog;
749 int response;
750 char *shortname, *filename, *longname, *duri, *modtxt;
751 Workbook *wb = wb_control_get_workbook (GNM_WBC (wbcg));
752 const char *uri;
753 GDateTime *modtime_local;
755 uri = go_doc_get_uri (GO_DOC (wb));
756 filename = go_filename_from_uri (uri);
757 if (filename) {
758 shortname = g_filename_display_basename (filename);
759 } else {
760 shortname = g_filename_display_basename (uri);
763 duri = g_uri_unescape_string (uri, NULL);
764 longname = duri
765 ? g_filename_display_name (duri)
766 : g_strdup (uri);
768 modtime_local = g_date_time_to_local (modtime);
769 modtxt = g_date_time_format (modtime_local, _("%F %T"));
770 g_date_time_unref (modtime_local);
772 dialog = gtk_message_dialog_new_with_markup
773 (wbcg_toplevel (wbcg),
774 GTK_DIALOG_DESTROY_WITH_PARENT,
775 GTK_MESSAGE_WARNING,
776 GTK_BUTTONS_NONE,
777 _("The file you are about to save has changed on disk. If you continue, you will overwrite someone else's changes.\n\n"
778 "File: <b>%s</b>\n"
779 "Location: %s\n\n"
780 "Last modified: <b>%s</b>\n"),
781 shortname, longname, modtxt);
782 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
783 _("Overwrite"), GTK_RESPONSE_YES,
784 _("Cancel"), GTK_RESPONSE_NO,
785 NULL);
786 g_free (shortname);
787 g_free (longname);
788 g_free (duri);
789 g_free (filename);
790 g_free (modtxt);
792 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_NO);
793 response = go_gtk_dialog_run (GTK_DIALOG (dialog),
794 wbcg_toplevel (wbcg));
795 return response == GTK_RESPONSE_YES;
798 gboolean
799 gui_file_save (WBCGtk *wbcg, WorkbookView *wb_view)
801 Workbook *wb = wb_view_get_workbook (wb_view);
802 WBCGtk *wbcg2 =
803 wbcg_find_for_workbook (wb, wbcg, NULL, NULL);
805 if (wbcg2) {
806 GtkWidget *nb = GTK_WIDGET (wbcg2->notebook_area);
807 GtkAllocation a;
808 gtk_widget_get_allocation (nb, &a);
809 wb_view_preferred_size (wb_view, a.width, a.height);
812 if (wb->file_format_level < GO_FILE_FL_AUTO)
813 return gui_file_save_as (wbcg, wb_view,
814 GNM_FILE_SAVE_AS_STYLE_SAVE, NULL);
815 else {
816 gboolean ok = TRUE;
817 const char *uri = go_doc_get_uri (GO_DOC (wb));
818 GDateTime *known_modtime = go_doc_get_modtime (GO_DOC (wb));
819 GDateTime *modtime = go_file_get_modtime (uri);
820 gboolean debug_modtime = gnm_debug_flag ("modtime");
822 /* We need a ref because a Ctrl-Q at the wrong time will
823 cause the workbook to disappear at the end of the
824 save. */
825 g_object_ref (wb);
827 if (modtime && known_modtime) {
828 if (g_date_time_equal (known_modtime, modtime)) {
829 if (debug_modtime)
830 g_printerr ("Modtime match\n");
831 } else {
832 if (debug_modtime)
833 g_printerr ("Modtime mismatch\n");
834 ok = warn_about_overwrite (wbcg, modtime, known_modtime);
838 if (ok)
839 ok = workbook_view_save (wb_view, GO_CMD_CONTEXT (wbcg));
840 if (ok)
841 workbook_update_history (wb, GNM_FILE_SAVE_AS_STYLE_SAVE);
842 g_object_unref (wb);
844 if (modtime)
845 g_date_time_unref (modtime);
847 return ok;
851 gboolean
852 gui_file_export_repeat (WBCGtk *wbcg)
854 WorkbookView *wb_view = wb_control_view (GNM_WBC (wbcg));
855 Workbook *wb = wb_view_get_workbook (wb_view);
856 GOFileSaver *fs = workbook_get_file_exporter (wb);
857 gchar const *last_uri = workbook_get_last_export_uri (wb);
859 if (fs != NULL && last_uri != NULL) {
860 char const *msg;
861 GtkWidget *dialog;
863 if (go_file_saver_get_save_scope (fs) != GO_FILE_SAVE_WORKBOOK)
864 msg = _("Do you want to export the <b>current sheet</b> of this "
865 "workbook to the location '<b>%s</b>' "
866 "using the '<b>%s</b>' exporter?");
867 else
868 msg = _("Do you want to export this workbook to the "
869 "location '<b>%s</b>' "
870 "using the '<b>%s</b>' exporter?");
872 /* go_gtk_query_yes_no does not handle markup ... */
873 dialog = gtk_message_dialog_new_with_markup (wbcg_toplevel (wbcg),
874 GTK_DIALOG_DESTROY_WITH_PARENT,
875 GTK_MESSAGE_QUESTION,
876 GTK_BUTTONS_YES_NO,
877 msg, last_uri,
878 go_file_saver_get_description (fs));
879 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
881 if (GTK_RESPONSE_YES ==
882 go_gtk_dialog_run (GTK_DIALOG (dialog), wbcg_toplevel (wbcg))) {
883 /* We need to copy wb->last_export_uri since it will be reset during saving */
884 gchar *uri = g_strdup (last_uri);
885 if(workbook_view_save_as (wb_view, fs, uri, GO_CMD_CONTEXT (wbcg))) {
886 workbook_update_history (wb, GNM_FILE_SAVE_AS_STYLE_EXPORT);
887 g_free (uri);
888 return TRUE;
890 g_free (uri);
892 return FALSE;
893 } else {
894 go_gtk_notice_dialog (wbcg_toplevel (wbcg), GTK_MESSAGE_ERROR,
895 _("Unable to repeat export since no previous "
896 "export information has been saved in this "
897 "session."));
898 return FALSE;