GUI: Move .ui files from goffice resources to glib resources
[gnumeric.git] / src / dialogs / dialog-quit.c
blobeb62f9d2ad1b218960b28750a46bcfaa2e7501ef
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /*
4 * dialog-quit.c:
5 * Dialog for quit (selecting what to save)
7 * Author:
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>
25 #include <gnumeric.h>
26 #include "dialogs.h"
27 #include <gui-file.h>
28 #include <gui-util.h>
29 #include <workbook.h>
30 #include <wbc-gtk.h>
31 #include <gui-clipboard.h>
32 #include <application.h>
34 #include <goffice/goffice.h>
35 #include <gtk/gtk.h>
37 #include <glib/gi18n-lib.h>
39 #include <string.h>
41 enum {
42 RESPONSE_ALL = 1,
43 RESPONSE_NONE = 2
46 enum {
47 QUIT_COL_CHECK,
48 QUIT_COL_DOC
51 /* ------------------------------------------------------------------------- */
53 static void
54 url_renderer_func (GtkTreeViewColumn *tree_column,
55 GtkCellRenderer *cell,
56 GtkTreeModel *model,
57 GtkTreeIter *iter,
58 gpointer user_data)
60 GODoc *doc = NULL;
61 const char *uri;
62 char *markup, *shortname, *filename, *longname, *duri;
64 gtk_tree_model_get (model, iter,
65 QUIT_COL_DOC, &doc,
66 -1);
67 g_return_if_fail (GO_IS_DOC (doc));
69 uri = go_doc_get_uri (doc);
70 filename = go_filename_from_uri (uri);
71 if (filename) {
72 shortname = g_filename_display_basename (filename);
73 } else {
74 shortname = g_filename_display_basename (uri);
77 duri = g_uri_unescape_string (uri, NULL);
78 longname = duri
79 ? g_filename_display_name (duri)
80 : g_strdup (uri);
82 markup = g_markup_printf_escaped (_("<b>%s</b>\n"
83 "<small>Location: %s</small>"),
84 shortname,
85 longname);
86 g_object_set (cell, "markup", markup, NULL);
87 g_free (markup);
88 g_free (shortname);
89 g_free (longname);
90 g_free (duri);
91 g_free (filename);
92 g_object_unref (doc);
95 static void
96 age_renderer_func (GtkTreeViewColumn *tree_column,
97 GtkCellRenderer *cell,
98 GtkTreeModel *model,
99 GtkTreeIter *iter,
100 gpointer user_data)
102 GODoc *doc = NULL;
104 gtk_tree_model_get (model, iter,
105 QUIT_COL_DOC, &doc,
106 -1);
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),
112 "quitting_time"));
113 int age = quitting_time -
114 go_doc_get_dirty_time (doc) / 1000000;
115 char *agestr;
116 if (age < 0)
117 agestr = g_strdup (_("unknown"));
118 else if (age < 60)
119 agestr = g_strdup_printf
120 (ngettext ("%d second", "%d seconds", age),
121 age);
122 else if (age < 60 * 60) {
123 int mins = age / 60;
124 agestr = g_strdup_printf
125 (ngettext ("%d minute", "%d minutes", mins),
126 mins);
127 } else
128 agestr = g_strdup (_("a long time"));
130 g_object_set (cell, "text", agestr, NULL);
131 g_free (agestr);
132 } else {
133 /* What are we doing here? */
134 g_object_set (cell, "text", "", NULL);
136 g_object_unref (doc);
139 static gboolean
140 foreach_is_file_set (GtkTreeModel *model, GtkTreePath *path,
141 GtkTreeIter *iter, gboolean *data)
143 gboolean value;
145 gtk_tree_model_get (GTK_TREE_MODEL (model), iter,
146 QUIT_COL_CHECK, &value, -1);
148 *data = value;
150 return value;
153 static gboolean
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,
160 &files_set_state);
162 return files_set_state;
165 static void
166 cb_toggled_save (GtkCellRendererToggle *cell,
167 gchar *path_string,
168 gpointer data)
170 GtkTreeModel *model = GTK_TREE_MODEL (data);
171 GtkTreeIter iter;
172 GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
174 if (gtk_tree_model_get_iter (model, &iter, path)) {
175 gboolean value;
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);
180 } else {
181 g_warning ("Did not get a valid iterator");
184 gtk_tree_path_free (path);
187 static void
188 set_all (GtkTreeModel *model, gboolean value)
190 GtkTreeIter iter;
191 gboolean ok = gtk_tree_model_get_iter_first (model, &iter);
193 while (ok) {
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);
200 static void
201 cb_select_all (G_GNUC_UNUSED GtkWidget *button,
202 GtkTreeModel *model)
204 set_all (model, TRUE);
207 static void
208 cb_clear_all (G_GNUC_UNUSED GtkWidget *button,
209 GtkTreeModel *model)
211 set_all (model, FALSE);
214 static void
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);
222 else
223 gtk_widget_set_sensitive (GTK_WIDGET (widget), FALSE);
226 static void
227 cb_list_row_changed_discard_sensitivity (GtkListStore *list,
228 GtkTreePath *path_string,
229 GtkTreeIter *iter,
230 GtkWidget *widget)
232 gtk_widget_set_sensitive (GTK_WIDGET (widget),
233 !files_set (GTK_TREE_MODEL (list)));
236 static gboolean
237 show_quit_dialog (GList *dirty, WBCGtk *wbcg)
239 GtkBuilder *gui;
240 GtkDialog *dialog;
241 gboolean multiple = (dirty->next != NULL);
242 GObject *model;
243 GtkWidget *save_selected_button;
244 GtkCellRenderer *save_renderer;
245 GList *l;
246 int res;
247 gboolean quit;
248 GObject *age_column;
249 int quitting_time = g_get_real_time () / 1000000;
251 gui = gnm_gtk_builder_load ("res:ui/quit.ui", NULL, GO_CMD_CONTEXT (wbcg));
252 if (gui == NULL)
253 return FALSE;
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"));
260 if (multiple) {
261 GObject *model = gtk_builder_get_object (gui, "quit_model");
262 g_signal_connect (model,
263 "row-changed",
264 G_CALLBACK (cb_list_row_changed_discard_sensitivity),
265 gtk_builder_get_object (gui, "discard_all_button"));
267 g_signal_connect (model,
268 "row-changed",
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),
276 model);
277 g_signal_connect (gtk_builder_get_object (gui, "clear_all_button"),
278 "clicked", G_CALLBACK (cb_clear_all),
279 model);
281 g_signal_connect (G_OBJECT (save_renderer),
282 "toggled",
283 G_CALLBACK (cb_toggled_save), model);
285 } else {
286 gtk_tree_view_column_set_visible (GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (gui, "save_column")),
287 FALSE);
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")),
295 url_renderer_func,
296 NULL,
297 NULL);
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")),
305 age_renderer_func,
306 NULL,
307 NULL);
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,
322 NULL);
324 pango_layout_get_pixel_size (layout, &width, &height);
325 gtk_widget_set_size_request (go_gtk_builder_get_widget (gui, "docs_scrolledwindow"),
326 width * 60 / 4,
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;
336 GtkTreeIter iter;
337 GtkListStore *list = GTK_LIST_STORE (model);
339 gtk_list_store_append (list, &iter);
340 gtk_list_store_set (list,
341 &iter,
342 QUIT_COL_CHECK, TRUE,
343 QUIT_COL_DOC, doc,
344 -1);
347 /* ---------------------------------------- */
349 atk_object_set_role (gtk_widget_get_accessible (GTK_WIDGET (dialog)),
350 ATK_ROLE_ALERT);
352 res = go_gtk_dialog_run (dialog, wbcg_toplevel (wbcg));
353 switch (res) {
354 case GTK_RESPONSE_CANCEL:
355 case GTK_RESPONSE_DELETE_EVENT:
356 quit = FALSE;
357 break;
359 case GTK_RESPONSE_NO:
360 quit = TRUE;
361 break;
363 default: {
364 GtkTreeModel *tmodel = GTK_TREE_MODEL (model);
365 GtkTreeIter iter;
366 gboolean ok = gtk_tree_model_get_iter_first (tmodel, &iter);
368 g_return_val_if_fail (ok, FALSE);
369 quit = TRUE;
370 do {
371 gboolean save = TRUE;
372 GODoc *doc = NULL;
374 gtk_tree_model_get (tmodel, &iter,
375 QUIT_COL_CHECK, &save,
376 QUIT_COL_DOC, &doc,
377 -1);
378 if (save) {
379 gboolean ok;
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)));
384 if (!ok)
385 quit = FALSE;
387 g_object_unref (doc);
389 ok = gtk_tree_model_iter_next (tmodel, &iter);
390 } while (ok);
391 break;
395 g_object_unref (gui);
397 return quit;
400 /* ------------------------------------------------------------------------- */
402 static gint
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));
412 void
413 dialog_quit (WBCGtk *wbcg)
415 GList *l, *dirty = NULL;
416 gboolean quit;
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);
424 if (dirty) {
425 dirty = g_list_sort (dirty, doc_order);
426 quit = show_quit_dialog (dirty, wbcg);
427 g_list_free (dirty);
428 if (!quit)
429 return;
432 l = g_list_copy (gnm_app_workbook_list ());
433 while (l) {
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! */
441 g_object_unref (wb);
445 /* ------------------------------------------------------------------------- */