1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
5 * Dialog for quit (selecting what to save)
8 * Morten Welinder (terra@gnome.org)
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <https://www.gnu.org/licenses/>.
24 #include <gnumeric-config.h>
31 #include <gui-clipboard.h>
32 #include <application.h>
34 #include <goffice/goffice.h>
37 #include <glib/gi18n-lib.h>
51 /* ------------------------------------------------------------------------- */
54 url_renderer_func (GtkTreeViewColumn
*tree_column
,
55 GtkCellRenderer
*cell
,
62 char *markup
, *shortname
, *filename
, *longname
, *duri
;
64 gtk_tree_model_get (model
, iter
,
67 g_return_if_fail (GO_IS_DOC (doc
));
69 uri
= go_doc_get_uri (doc
);
70 filename
= go_filename_from_uri (uri
);
72 shortname
= g_filename_display_basename (filename
);
74 shortname
= g_filename_display_basename (uri
);
77 duri
= g_uri_unescape_string (uri
, NULL
);
79 ? g_filename_display_name (duri
)
82 markup
= g_markup_printf_escaped (_("<b>%s</b>\n"
83 "<small>Location: %s</small>"),
86 g_object_set (cell
, "markup", markup
, NULL
);
96 age_renderer_func (GtkTreeViewColumn
*tree_column
,
97 GtkCellRenderer
*cell
,
104 gtk_tree_model_get (model
, iter
,
107 g_return_if_fail (GO_IS_DOC (doc
));
109 if (go_doc_is_dirty (doc
)) {
110 int quitting_time
= GPOINTER_TO_INT
111 (g_object_get_data (G_OBJECT (tree_column
),
113 int age
= quitting_time
-
114 go_doc_get_dirty_time (doc
) / 1000000;
117 agestr
= g_strdup (_("unknown"));
119 agestr
= g_strdup_printf
120 (ngettext ("%d second", "%d seconds", age
),
122 else if (age
< 60 * 60) {
124 agestr
= g_strdup_printf
125 (ngettext ("%d minute", "%d minutes", mins
),
128 agestr
= g_strdup (_("a long time"));
130 g_object_set (cell
, "text", agestr
, NULL
);
133 /* What are we doing here? */
134 g_object_set (cell
, "text", "", NULL
);
136 g_object_unref (doc
);
140 foreach_is_file_set (GtkTreeModel
*model
, GtkTreePath
*path
,
141 GtkTreeIter
*iter
, gboolean
*data
)
145 gtk_tree_model_get (GTK_TREE_MODEL (model
), iter
,
146 QUIT_COL_CHECK
, &value
, -1);
154 files_set (GtkTreeModel
*model
)
156 gboolean files_set_state
= FALSE
;
158 gtk_tree_model_foreach (GTK_TREE_MODEL (model
),
159 (GtkTreeModelForeachFunc
) foreach_is_file_set
,
162 return files_set_state
;
166 cb_toggled_save (GtkCellRendererToggle
*cell
,
170 GtkTreeModel
*model
= GTK_TREE_MODEL (data
);
172 GtkTreePath
*path
= gtk_tree_path_new_from_string (path_string
);
174 if (gtk_tree_model_get_iter (model
, &iter
, path
)) {
176 gtk_tree_model_get (model
, &iter
,
177 QUIT_COL_CHECK
, &value
, -1);
178 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
179 QUIT_COL_CHECK
, !value
, -1);
181 g_warning ("Did not get a valid iterator");
184 gtk_tree_path_free (path
);
188 set_all (GtkTreeModel
*model
, gboolean value
)
191 gboolean ok
= gtk_tree_model_get_iter_first (model
, &iter
);
194 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
195 QUIT_COL_CHECK
, value
, -1);
196 ok
= gtk_tree_model_iter_next (model
, &iter
);
201 cb_select_all (G_GNUC_UNUSED GtkWidget
*button
,
204 set_all (model
, TRUE
);
208 cb_clear_all (G_GNUC_UNUSED GtkWidget
*button
,
211 set_all (model
, FALSE
);
215 cb_list_row_changed_save_sensitivity (GtkListStore
*list
, GtkTreePath
*path_string
,
216 GtkTreeIter
*iter
, GtkWidget
*widget
)
218 GtkTreeModel
*model
= GTK_TREE_MODEL (list
);
220 if (files_set (model
) == TRUE
)
221 gtk_widget_set_sensitive (GTK_WIDGET (widget
), TRUE
);
223 gtk_widget_set_sensitive (GTK_WIDGET (widget
), FALSE
);
227 cb_list_row_changed_discard_sensitivity (GtkListStore
*list
,
228 GtkTreePath
*path_string
,
232 gtk_widget_set_sensitive (GTK_WIDGET (widget
),
233 !files_set (GTK_TREE_MODEL (list
)));
237 show_quit_dialog (GList
*dirty
, WBCGtk
*wbcg
)
241 gboolean multiple
= (dirty
->next
!= NULL
);
243 GtkWidget
*save_selected_button
;
244 GtkCellRenderer
*save_renderer
;
249 int quitting_time
= g_get_real_time () / 1000000;
251 gui
= gnm_gtk_builder_load ("res:ui/quit.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
255 dialog
= GTK_DIALOG (go_gtk_builder_get_widget (gui
, "quit_dialog"));
256 model
= gtk_builder_get_object (gui
, "quit_model");
257 save_selected_button
= go_gtk_builder_get_widget (gui
, "save_selected_button");
258 save_renderer
= GTK_CELL_RENDERER (gtk_builder_get_object (gui
, "save_renderer"));
261 GObject
*model
= gtk_builder_get_object (gui
, "quit_model");
262 g_signal_connect (model
,
264 G_CALLBACK (cb_list_row_changed_discard_sensitivity
),
265 gtk_builder_get_object (gui
, "discard_all_button"));
267 g_signal_connect (model
,
269 G_CALLBACK (cb_list_row_changed_save_sensitivity
),
270 save_selected_button
);
272 gtk_widget_destroy (go_gtk_builder_get_widget (gui
, "save_button"));
274 g_signal_connect (gtk_builder_get_object (gui
, "select_all_button"),
275 "clicked", G_CALLBACK (cb_select_all
),
277 g_signal_connect (gtk_builder_get_object (gui
, "clear_all_button"),
278 "clicked", G_CALLBACK (cb_clear_all
),
281 g_signal_connect (G_OBJECT (save_renderer
),
283 G_CALLBACK (cb_toggled_save
), model
);
286 gtk_tree_view_column_set_visible (GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (gui
, "save_column")),
288 gtk_widget_destroy (save_selected_button
);
289 gtk_widget_destroy (go_gtk_builder_get_widget (gui
, "selection_box"));
292 gtk_tree_view_column_set_cell_data_func
293 (GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (gui
, "url_column")),
294 GTK_CELL_RENDERER (gtk_builder_get_object (gui
, "url_renderer")),
299 age_column
= gtk_builder_get_object (gui
, "age_column");
300 g_object_set_data (age_column
, "quitting_time",
301 GINT_TO_POINTER (quitting_time
));
302 gtk_tree_view_column_set_cell_data_func
303 (GTK_TREE_VIEW_COLUMN (age_column
),
304 GTK_CELL_RENDERER (gtk_builder_get_object (gui
, "age_renderer")),
309 gtk_dialog_set_default_response (dialog
, GTK_RESPONSE_OK
);
311 /* ---------------------------------------- */
312 /* Size the dialog. */
315 GtkWidget
*w
= GTK_WIDGET (wbcg_toplevel (wbcg
));
316 int width
, height
, vsep
;
317 PangoLayout
*layout
=
318 gtk_widget_create_pango_layout (w
, "Mg19");
320 gtk_widget_style_get (go_gtk_builder_get_widget (gui
, "docs_treeview"),
321 "vertical_separator", &vsep
,
324 pango_layout_get_pixel_size (layout
, &width
, &height
);
325 gtk_widget_set_size_request (go_gtk_builder_get_widget (gui
, "docs_scrolledwindow"),
327 (2 * height
+ vsep
) * (4 + 1));
328 g_object_unref (layout
);
331 /* ---------------------------------------- */
332 /* Populate the model. */
334 for (l
= dirty
; l
; l
= l
->next
) {
335 GODoc
*doc
= l
->data
;
337 GtkListStore
*list
= GTK_LIST_STORE (model
);
339 gtk_list_store_append (list
, &iter
);
340 gtk_list_store_set (list
,
342 QUIT_COL_CHECK
, TRUE
,
347 /* ---------------------------------------- */
349 atk_object_set_role (gtk_widget_get_accessible (GTK_WIDGET (dialog
)),
352 res
= go_gtk_dialog_run (dialog
, wbcg_toplevel (wbcg
));
354 case GTK_RESPONSE_CANCEL
:
355 case GTK_RESPONSE_DELETE_EVENT
:
359 case GTK_RESPONSE_NO
:
364 GtkTreeModel
*tmodel
= GTK_TREE_MODEL (model
);
366 gboolean ok
= gtk_tree_model_get_iter_first (tmodel
, &iter
);
368 g_return_val_if_fail (ok
, FALSE
);
371 gboolean save
= TRUE
;
374 gtk_tree_model_get (tmodel
, &iter
,
375 QUIT_COL_CHECK
, &save
,
380 Workbook
*wb
= WORKBOOK (doc
);
381 WBCGtk
*wbcg2
= wbcg_find_for_workbook (wb
, wbcg
, NULL
, NULL
);
383 ok
= wbcg2
&& gui_file_save (wbcg2
, wb_control_view (GNM_WBC (wbcg2
)));
387 g_object_unref (doc
);
389 ok
= gtk_tree_model_iter_next (tmodel
, &iter
);
395 g_object_unref (gui
);
400 /* ------------------------------------------------------------------------- */
403 doc_order (gconstpointer a_
, gconstpointer b_
)
405 GODoc
*a
= (GODoc
*)a_
;
406 GODoc
*b
= (GODoc
*)b_
;
408 /* Primitive, but will work for now. */
409 return go_str_compare (go_doc_get_uri (a
), go_doc_get_uri (b
));
413 dialog_quit (WBCGtk
*wbcg
)
415 GList
*l
, *dirty
= NULL
;
418 for (l
= gnm_app_workbook_list (); l
; l
= l
->next
) {
419 GODoc
*doc
= l
->data
;
420 if (go_doc_is_dirty (GO_DOC (doc
)))
421 dirty
= g_list_prepend (dirty
, doc
);
425 dirty
= g_list_sort (dirty
, doc_order
);
426 quit
= show_quit_dialog (dirty
, wbcg
);
432 l
= g_list_copy (gnm_app_workbook_list ());
434 Workbook
*wb
= l
->data
;
435 l
= g_list_remove (l
, wb
);
436 go_doc_set_dirty (GO_DOC (wb
), FALSE
);
438 gnm_x_store_clipboard_if_needed (wb
);
440 /* This is how we kill it? Ugh! */
445 /* ------------------------------------------------------------------------- */