Bump gEDA version
[geda-gaf.git] / gschem / src / gschem_close_confirmation_dialog.c
bloba3c3d597fe039a02951980157707b34771fb819a
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 gEDA Contributors (see ChangeLog for details)
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 /*! \todo STILL NEED to clean up line lengths in aa and tr */
21 #include <config.h>
23 #include <stdio.h>
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
31 #include "gschem.h"
33 #define GLADE_HOOKUP_OBJECT(component,widget,name) \
34 g_object_set_data_full (G_OBJECT (component), name, \
35 gtk_widget_ref (widget), (GDestroyNotify) g_object_unref)
39 /***************** Start of Close Confirmation dialog box ************/
41 #define TYPE_CLOSE_CONFIRMATION_DIALOG (close_confirmation_dialog_get_type ())
42 #define CLOSE_CONFIRMATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CLOSE_CONFIRMATION_DIALOG, CloseConfirmationDialog))
43 #define CLOSE_CONFIRMATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_CLOSE_CONFIRMATION_DIALOG, CloseConfirmationDialogClass))
44 #define IS_CLOSE_CONFIRMATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CLOSE_CONFIRMATION_DIALOG))
45 #define IS_CLOSE_CONFIRMATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLOSE_CONFIRMATION_DIALOG))
46 #define CLOSE_CONFIRMATION_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),TYPE_CLOSE_CONFIRMATION_DIALOG, CloseConfirmationDialogClass))
49 typedef struct _CloseConfirmationDialog CloseConfirmationDialog;
50 typedef struct _CloseConfirmationDialogClass CloseConfirmationDialogClass;
52 struct _CloseConfirmationDialog
54 GtkDialog parent;
56 GschemToplevel *w_current;
58 GtkListStore *store_unsaved_pages;
61 struct _CloseConfirmationDialogClass
63 GtkDialogClass parent_class;
67 enum {
68 PROP_GSCHEM_TOPLEVEL = 1,
69 PROP_UNSAVED_PAGE,
70 PROP_UNSAVED_PAGES,
71 PROP_SELECTED_PAGES
74 enum {
75 COLUMN_SAVE,
76 COLUMN_PAGE,
77 NUM_COLUMNS
81 static gpointer close_confirmation_dialog_parent_class = NULL;
84 static void close_confirmation_dialog_class_init (CloseConfirmationDialogClass *klass);
85 static void close_confirmation_dialog_init (CloseConfirmationDialog *self);
86 static void close_confirmation_dialog_set_property (GObject *object,
87 guint property_id,
88 const GValue *value,
89 GParamSpec *pspec);
90 static void close_confirmation_dialog_get_property (GObject *object,
91 guint property_id,
92 GValue *value,
93 GParamSpec *pspec);
94 static GObject* close_confirmation_dialog_constructor (GType type,
95 guint n_construct_properties,
96 GObjectConstructParam *construct_params);
98 GList *close_confirmation_dialog_get_selected_pages (CloseConfirmationDialog *dialog);
102 GType
103 close_confirmation_dialog_get_type ()
105 static GType close_confirmation_dialog_type = 0;
107 if (!close_confirmation_dialog_type) {
108 static const GTypeInfo close_confirmation_dialog_info = {
109 sizeof(CloseConfirmationDialogClass),
110 NULL, /* base_init */
111 NULL, /* base_finalize */
112 (GClassInitFunc) close_confirmation_dialog_class_init,
113 NULL, /* class_finalize */
114 NULL, /* class_data */
115 sizeof(CloseConfirmationDialog),
116 0, /* n_preallocs */
117 (GInstanceInitFunc) close_confirmation_dialog_init,
120 close_confirmation_dialog_type =
121 g_type_register_static (GTK_TYPE_DIALOG,
122 "CloseConfirmationDialog",
123 &close_confirmation_dialog_info, 0);
126 return close_confirmation_dialog_type;
129 static void
130 close_confirmation_dialog_class_init (CloseConfirmationDialogClass *klass)
132 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
134 close_confirmation_dialog_parent_class = g_type_class_peek_parent (klass);
136 gobject_class->constructor = close_confirmation_dialog_constructor;
137 gobject_class->set_property = close_confirmation_dialog_set_property;
138 gobject_class->get_property = close_confirmation_dialog_get_property;
140 g_object_class_install_property (
141 gobject_class, PROP_GSCHEM_TOPLEVEL,
142 g_param_spec_pointer ("gschem-toplevel",
145 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
146 g_object_class_install_property (
147 gobject_class, PROP_UNSAVED_PAGE,
148 g_param_spec_pointer ("unsaved-page",
151 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
152 g_object_class_install_property (
153 gobject_class, PROP_UNSAVED_PAGES,
154 g_param_spec_pointer ("unsaved-pages",
157 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
158 g_object_class_install_property (
159 gobject_class, PROP_SELECTED_PAGES,
160 g_param_spec_pointer ("selected-pages",
163 G_PARAM_READABLE));
167 static void
168 close_confirmation_dialog_init (CloseConfirmationDialog *self)
170 /* create model for treeview and populate */
171 self->store_unsaved_pages = gtk_list_store_new (NUM_COLUMNS,
172 G_TYPE_BOOLEAN, /* save? */
173 G_TYPE_POINTER); /* page */
177 /*! \brief Returns the number of pages in the model.
178 * \par Function Description
179 * This function determines the number of pages with unsaved changes
180 * from the model.
182 * \param [in] model The tree model.
183 * \returns The number of pages with unsaved changes.
185 static gint
186 count_pages (GtkTreeModel *model)
188 GtkTreeIter iter;
189 gint n_pages;
191 gtk_tree_model_get_iter_first (model, &iter);
192 for (n_pages = 1;
193 gtk_tree_model_iter_next (model, &iter);
194 n_pages++);
196 return n_pages;
199 /*! \brief Returns the name to use for the given page in the model.
200 * \par Function Description
201 * This function determines the text to be used to identify a
202 * specific page from the model of pages with unsaved changes.
204 * If <B>piter</B> is NULL, the name for the first page of the model
205 * is returned. Otherwise, it returns the name for the page defined
206 * by the pointed iterator.
208 * The returned value must be freed by caller.
210 * \param [in] model The tree model.
211 * \param [in] piter A pointer on a GtkTreeIter of model or NULL.
212 * \returns The name for the page.
214 static gchar*
215 get_page_name (GtkTreeModel *model, GtkTreeIter *piter)
217 GtkTreeIter iter;
218 PAGE *page;
220 g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
222 if (piter == NULL) {
223 gtk_tree_model_get_iter_first (model, &iter);
224 } else {
225 iter = *piter;
228 gtk_tree_model_get (model, &iter,
229 COLUMN_PAGE, &page,
230 -1);
231 g_assert (page != NULL && page->page_filename != NULL);
232 if (page->is_untitled)
233 return g_strdup (_("Untitled page"));
234 return g_path_get_basename (page->page_filename);
237 /*! \brief Sets the contents of the name cell in the treeview of dialog.
238 * \par Function Description
239 * This functions sets the cell of the treeview with the short name
240 * of the page obtained with <B>get_page_name()</B>.
242 * \param [in] tree_column A GtkTreeColumn.
243 * \param [in] cell The GtkCellRenderer that is being rendered by
244 * tree_column.
245 * \param [in] tree_model The GtkTreeModel being rendered.
246 * \param [in] iter A GtkTreeIter of the current row rendered.
247 * \param [in] data .
249 static void
250 close_confirmation_dialog_set_page_name (GtkTreeViewColumn *tree_column,
251 GtkCellRenderer *cell,
252 GtkTreeModel *tree_model,
253 GtkTreeIter *iter,
254 gpointer data)
256 gchar *page_name;
258 page_name = get_page_name (tree_model, iter);
259 g_object_set (cell,
260 "text", page_name,
261 NULL);
262 g_free (page_name);
266 /*! \brief Callback function for the toggled signal of check box in treeview.
267 * \par Function Description
268 * This functions changes the value of the save column in the model
269 * for the affected row when user toggles the check box in the
270 * treeview.
272 * \param [in] cell_renderer The GtkCellRendererToggle.
273 * \param [in] path The GtkTreePath to the concerned row in model.
274 * \param [in] user_data The dialog as user data.
276 static void
277 close_confirmation_dialog_callback_renderer_toggled (GtkCellRendererToggle *cell_renderer,
278 gchar *path,
279 gpointer user_data)
281 CloseConfirmationDialog *dialog = CLOSE_CONFIRMATION_DIALOG (user_data);
282 GtkTreeModel *model;
283 GtkTreeIter iter;
284 gboolean save;
286 model = GTK_TREE_MODEL (dialog->store_unsaved_pages);
288 if (!gtk_tree_model_get_iter_from_string (model, &iter, path)) {
289 return;
291 gtk_tree_model_get (model, &iter,
292 COLUMN_SAVE, &save,
293 -1);
294 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
295 COLUMN_SAVE, (save != TRUE),
296 -1);
300 /*! \brief Adds a treeview to confirmation dialog for selecting of pages.
301 * \par Function Description
302 * This function adds a treeview and caption to display the content
303 * of the dialog model of pages with unsaved changes.
305 * The treeview displays the page names with check boxes.
307 * \param [in] dialog The dialog.
308 * \returns A pointer on the GtkVBox to add to dialog.
310 static GtkWidget*
311 close_confirmation_dialog_build_page_list (CloseConfirmationDialog *dialog)
313 GtkWidget *vbox, *scrolled_window, *treeview, *label;
314 GtkCellRenderer *renderer;
315 GtkTreeViewColumn *column;
316 const gchar *text;
318 /* place the treeview and its caption into their own box */
319 vbox = GTK_WIDGET (g_object_new (GTK_TYPE_VBOX,
320 /* GtkBox */
321 "homogeneous", FALSE,
322 "spacing", 8,
323 NULL));
325 /* the list of pages with changes */
326 /* - scrolled window as container for the treeview first */
327 scrolled_window = GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
328 /* GtkScrolledWindow */
329 "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
330 "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
331 "shadow-type", GTK_SHADOW_IN,
332 NULL));
333 /* - then the treeview */
334 /* create model for treeview and populate */
335 treeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
336 /* GtkTreeView */
337 "enable-search", FALSE,
338 "headers-visible", FALSE,
339 "model", dialog->store_unsaved_pages,
340 NULL));
341 renderer = gtk_cell_renderer_toggle_new ();
342 g_signal_connect (renderer, "toggled",
343 G_CALLBACK (
344 close_confirmation_dialog_callback_renderer_toggled),
345 dialog);
346 column = gtk_tree_view_column_new_with_attributes ("Save?",
347 renderer,
348 "active", COLUMN_SAVE,
349 NULL);
350 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
352 renderer = gtk_cell_renderer_text_new ();
353 column = GTK_TREE_VIEW_COLUMN (
354 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
355 /* GtkTreeViewColumn */
356 "title", _("Name"),
357 NULL));
358 gtk_tree_view_column_pack_start (column, renderer, TRUE);
359 gtk_tree_view_column_set_cell_data_func (column, renderer,
360 close_confirmation_dialog_set_page_name,
361 NULL, NULL);
362 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
364 gtk_container_add (GTK_CONTAINER (scrolled_window), treeview);
366 gtk_box_pack_end (GTK_BOX (vbox), scrolled_window,
367 TRUE, TRUE, 0);
369 /* the caption label above the list of pages */
370 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
371 /* GtkMisc */
372 "xalign", 0.0,
373 "yalign", 0.0,
374 /* GtkLabel */
375 "wrap", TRUE,
376 "mnemonic-widget", treeview,
377 NULL));
378 text = _("S_elect the files you want to save:");
379 gtk_label_set_text_with_mnemonic (GTK_LABEL (label), text);
380 gtk_label_set_mnemonic_widget (GTK_LABEL (label), treeview);
381 gtk_box_pack_start (GTK_BOX (vbox), label,
382 FALSE, FALSE, 0);
384 return vbox;
387 static GObject*
388 close_confirmation_dialog_constructor (GType type,
389 guint n_construct_properties,
390 GObjectConstructParam *construct_params)
392 GObject *object;
393 CloseConfirmationDialog *dialog;
394 GtkWidget *hbox, *image, *vbox, *label;
395 GtkTreeIter iter;
396 gboolean ret, single_page;
397 gchar *tmp, *str;
398 const gchar *cstr;
400 /* chain up to constructor of parent class */
401 object =
402 G_OBJECT_CLASS (close_confirmation_dialog_parent_class)->constructor (
403 type,
404 n_construct_properties,
405 construct_params);
406 dialog = CLOSE_CONFIRMATION_DIALOG (object);
408 g_object_set (dialog,
409 /* GtkDialog */
410 "has-separator", FALSE,
411 /* GtkWindow */
412 "resizable", FALSE,
413 "skip-taskbar-hint", TRUE,
414 /* GtkContainer */
415 "border-width", 5,
416 NULL);
417 g_object_set (GTK_DIALOG (dialog)->vbox,
418 /* GtkBox */
419 "spacing", 14,
420 NULL);
421 g_object_set (GTK_DIALOG (dialog)->action_area,
422 /* GtkBox */
423 "spacing", 6,
424 /* GtkContainer */
425 "border-width", 5,
426 NULL);
428 /* check if there is one or more than one page with changes */
429 ret = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (
430 dialog->store_unsaved_pages),
431 &iter);
432 g_assert (ret);
433 single_page = !gtk_tree_model_iter_next (GTK_TREE_MODEL (
434 dialog->store_unsaved_pages),
435 &iter);
437 /* here starts the layout of the dialog */
438 hbox = GTK_WIDGET (g_object_new (GTK_TYPE_HBOX,
439 /* GtkContainer */
440 "border-width", 5,
441 /* GtkBox */
442 "homogeneous", FALSE,
443 "spacing", 12,
444 NULL));
446 /* warning image */
447 image = g_object_new (GTK_TYPE_IMAGE,
448 /* GtkMisc */
449 "xalign", 0.5,
450 "yalign", 0.0,
451 /* GtkImage */
452 "stock", GTK_STOCK_DIALOG_WARNING,
453 "icon-size", GTK_ICON_SIZE_DIALOG,
454 NULL);
455 gtk_box_pack_start (GTK_BOX (hbox), image,
456 FALSE, FALSE, 0);
458 /* vertical box on the right hand side of the dialog */
459 vbox = GTK_WIDGET (g_object_new (GTK_TYPE_VBOX,
460 /* GtkBox */
461 "homogeneous", FALSE,
462 "spacing", 12,
463 NULL));
465 /* primary label */
466 if (single_page) {
467 /* single page */
468 GtkTreeModel *model = GTK_TREE_MODEL (dialog->store_unsaved_pages);
469 GtkTreeIter iter;
470 PAGE *page;
472 gtk_tree_model_get_iter_first (model, &iter);
473 gtk_tree_model_get (model, &iter,
474 COLUMN_PAGE, &page,
475 -1);
476 g_assert (page != NULL);
478 x_window_set_current_page (dialog->w_current, page);
480 if (page->is_untitled)
481 tmp = g_strdup (_("Save changes before closing?"));
482 else {
483 gchar *page_name = g_path_get_basename (page->page_filename);
484 tmp = g_strdup_printf (
485 _("Save the changes to \"%s\" before closing?"),
486 page_name);
487 g_free (page_name);
489 } else {
490 /* multi page */
491 tmp = g_strdup_printf (
492 _("There are %d files with unsaved changes.\n"
493 "Save changes before closing?"),
494 count_pages (GTK_TREE_MODEL (dialog->store_unsaved_pages)));
496 str = g_strconcat ("<big><b>", tmp, "</b></big>", NULL);
497 g_free (tmp);
498 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
499 /* GtkMisc */
500 "xalign", 0.0,
501 "yalign", 0.0,
502 "selectable", TRUE,
503 /* GtkLabel */
504 "wrap", TRUE,
505 "use-markup", TRUE,
506 "label", str,
507 NULL));
508 g_free (str);
509 gtk_box_pack_start (GTK_BOX (vbox), label,
510 FALSE, FALSE, 0);
512 if (!single_page) {
513 /* more than one page with changes, display each page and offer */
514 /* the opportunity to save them before exiting */
515 gtk_box_pack_start (GTK_BOX (vbox),
516 close_confirmation_dialog_build_page_list (dialog),
517 FALSE, FALSE, 0);
520 /* secondary label */
521 cstr = _("If you don't save, all your changes will be permanently lost.");
522 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
523 /* GtkMisc */
524 "xalign", 0.0,
525 "yalign", 0.0,
526 "selectable", TRUE,
527 /* GtkLabel */
528 "wrap", TRUE,
529 "label", cstr,
530 NULL));
531 gtk_box_pack_start (GTK_BOX (vbox), label,
532 FALSE, FALSE, 0);
535 gtk_box_pack_start (GTK_BOX (hbox), vbox,
536 FALSE, FALSE, 0);
539 /* add buttons to dialog action area */
540 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
541 _("Close _without saving"), GTK_RESPONSE_NO,
542 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
543 GTK_STOCK_SAVE, GTK_RESPONSE_YES,
544 NULL);
546 /* Set the alternative button order (ok, cancel, help) for other systems */
547 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog),
548 GTK_RESPONSE_YES,
549 GTK_RESPONSE_NO,
550 GTK_RESPONSE_CANCEL,
551 -1);
553 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
555 /* all done, let's show the contents of the dialog */
556 gtk_widget_show_all (hbox);
558 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
559 FALSE, FALSE, 0);
561 return object;
564 static void
565 close_confirmation_dialog_set_property (GObject *object,
566 guint property_id,
567 const GValue *value,
568 GParamSpec *pspec)
570 CloseConfirmationDialog *dialog = CLOSE_CONFIRMATION_DIALOG (object);
571 GtkTreeIter iter;
572 gpointer data;
573 GList *p_current;
575 switch(property_id) {
576 case PROP_GSCHEM_TOPLEVEL:
577 dialog->w_current = GSCHEM_TOPLEVEL (g_value_get_pointer (value));
578 break;
580 case PROP_UNSAVED_PAGE:
581 data = g_value_get_pointer (value);
582 if (data != NULL) {
583 /* add single page to model */
584 gtk_list_store_append (dialog->store_unsaved_pages,
585 &iter);
586 gtk_list_store_set (dialog->store_unsaved_pages,
587 &iter,
588 COLUMN_SAVE, TRUE,
589 COLUMN_PAGE, data,
590 -1);
592 break;
594 case PROP_UNSAVED_PAGES:
595 data = g_value_get_pointer (value);
596 /* add set of pages to model */
597 for (p_current = (GList*)data;
598 p_current != NULL;
599 p_current = g_list_next (p_current)) {
600 gtk_list_store_append (dialog->store_unsaved_pages,
601 &iter);
602 gtk_list_store_set (dialog->store_unsaved_pages,
603 &iter,
604 COLUMN_SAVE, TRUE,
605 COLUMN_PAGE, p_current->data,
606 -1);
608 break;
610 default:
611 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
616 static void
617 close_confirmation_dialog_get_property (GObject *object,
618 guint property_id,
619 GValue *value,
620 GParamSpec *pspec)
622 CloseConfirmationDialog *dialog = CLOSE_CONFIRMATION_DIALOG (object);
624 switch(property_id) {
625 case PROP_GSCHEM_TOPLEVEL:
626 g_value_set_pointer (value, dialog->w_current);
627 break;
629 case PROP_SELECTED_PAGES:
630 g_value_set_pointer (
631 value,
632 close_confirmation_dialog_get_selected_pages (dialog));
633 break;
635 default:
636 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
641 /*! \brief Helps building a list of selected page to save.
642 * \par Function Description
643 * This is the <B>GtkTreeModelForeachFunc</B> for function
644 * <B>close_confirmation_dialog_get_selected_pages()</B>.
646 * It builds from the tree model a list of PAGEs for which a save
647 * action has been requested. Each selected page is appended to the
648 * GList pointed by <B>data</B>
650 * \param [in] model The tree model.
651 * \param [in] path .
652 * \param [in] iter .
653 * \param [in] data A pointer on a GList* to fill.
654 * \returns FALSE to continue walking the tree.
656 static gboolean
657 get_selected_pages (GtkTreeModel *model,
658 GtkTreePath *path,
659 GtkTreeIter *iter,
660 gpointer data)
662 PAGE *page;
663 gboolean save;
665 gtk_tree_model_get (model, iter,
666 COLUMN_SAVE, &save,
667 COLUMN_PAGE, &page,
668 -1);
669 if (save) {
670 g_assert (page != NULL);
671 *(GList**)data = g_list_append (*(GList**)data, page);
674 return FALSE;
677 /*! \brief Returns a list of the selected pages with changes to save.
678 * \par Function Description
679 * This function returns the pages that the user has selected in the
680 * confirmation dialog.
682 * The returned list must be freed.
684 * \param [in] dialog The dialog.
685 * \returns A GList of selected PAGE* in dialog.
687 GList*
688 close_confirmation_dialog_get_selected_pages (CloseConfirmationDialog *dialog)
690 GList *selected = NULL;
692 gtk_tree_model_foreach (GTK_TREE_MODEL (dialog->store_unsaved_pages),
693 (GtkTreeModelForeachFunc)get_selected_pages,
694 &selected);
696 return selected;
700 /*! \brief Asks for confirmation before closing a changed page.
701 * \par Function Description
702 * This function asks the user to confirm its closing order for
703 * page <B>page</B> while it still has unsaved changes.
705 * It displays a message dialog inviting the user to cancel the
706 * closing, or to discard the changes or to save the changes to a
707 * file.
709 * \param [in] w_current The toplevel environment.
710 * \param [in] page The page to close.
712 * \return TRUE if okay to continue with closing page, FALSE
713 * otherwise.
715 gboolean
716 x_dialog_close_changed_page (GschemToplevel *w_current, PAGE *page)
718 GtkWidget *dialog;
719 gint response_id;
720 gboolean result = FALSE;
722 g_return_val_if_fail (page != NULL && page->CHANGED, TRUE);
724 dialog = GTK_WIDGET (g_object_new (TYPE_CLOSE_CONFIRMATION_DIALOG,
725 "gschem-toplevel", w_current,
726 "unsaved-page", page,
727 NULL));
728 /* set default response signal. This is usually triggered by the
729 "Return" key */
730 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
731 GTK_RESPONSE_YES);
733 response_id = gtk_dialog_run (GTK_DIALOG (dialog));
734 gtk_widget_destroy (dialog);
736 switch (response_id) {
737 case GTK_RESPONSE_NO:
738 /* action selected: close without saving */
739 /* close the page, discard changes */
740 result = TRUE;
741 break;
744 case GTK_RESPONSE_YES:
745 /* action selected: save */
746 if (x_highlevel_save_page (w_current, page))
747 result = TRUE;
748 /* no, user has cancelled the save and page has changes */
749 /* do not close page */
750 break;
752 case GTK_RESPONSE_CANCEL:
753 /* action selected: cancel */
754 /* fall through */
755 default:
756 /* Hit when the user breaks out of the dialog with the escape key
757 * or otherwise destroys the dialog window without a proper response */
758 /* nothing to do */
759 break;
762 return result;
765 /*! \brief Asks for confirmation before closing a window.
766 * \par Function Description
767 * This function asks the user to confirm its closing order for
768 * the given window.
770 * The user is given the possibility to save the pages that currently
771 * have unsaved changes, if any.
773 * It returns TRUE if the user really accepts the close of the
774 * window. Otherwise the user has somehow cancelled and the window
775 * must not be closed.
777 * \param [in] w_current The toplevel environment.
778 * \returns TRUE if the window can be closed, FALSE otherwise.
780 gboolean
781 x_dialog_close_window (GschemToplevel *w_current)
783 TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
784 GList *iter;
785 GtkWidget *dialog;
786 PAGE *p_current;
787 GList *unsaved_pages, *p_unsaved;
788 gboolean ret = FALSE;
790 for ( iter = geda_list_get_glist( toplevel->pages ), unsaved_pages = NULL;
791 iter != NULL;
792 iter = g_list_next( iter ) ) {
794 p_current = (PAGE*)iter->data;
796 if (p_current->CHANGED) {
797 unsaved_pages = g_list_append (unsaved_pages, (gpointer)p_current);
801 if (unsaved_pages == NULL) {
802 /* no page with unsaved changes, close window */
803 return TRUE;
806 dialog = GTK_WIDGET (g_object_new (TYPE_CLOSE_CONFIRMATION_DIALOG,
807 "gschem-toplevel", w_current,
808 "unsaved-pages", unsaved_pages,
809 NULL));
811 gtk_window_set_transient_for (GTK_WINDOW (dialog),
812 GTK_WINDOW (w_current->main_window));
814 g_list_free (unsaved_pages);
815 unsaved_pages = NULL;
817 switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
818 case GTK_RESPONSE_NO:
819 /* action selected: close without saving */
820 /* discard changes, ok to close window */
821 ret = TRUE;
822 break;
824 case GTK_RESPONSE_YES:
825 /* action selected: save */
826 g_object_get (dialog,
827 "selected-pages", &unsaved_pages,
828 NULL);
829 ret = TRUE;
830 break;
832 case GTK_RESPONSE_CANCEL:
833 /* action selected: cancel */
834 /* fall through */
835 default:
836 /* Hit when the user breaks out of the dialog with the escape key
837 * or otherwise destroys the dialog window without a proper response */
838 ret = FALSE;
839 break;
841 gtk_widget_destroy (dialog);
843 /* if response was "save", save all selected pages */
844 for (p_unsaved = unsaved_pages;
845 p_unsaved != NULL;
846 p_unsaved = g_list_next (p_unsaved)) {
847 p_current = (PAGE *) p_unsaved->data;
849 if (!x_highlevel_save_page (w_current, p_current))
850 /* if user cancelled save, do not close window */
851 ret = FALSE;
853 g_list_free (unsaved_pages);
855 return ret;
858 /***************** End of Close Confirmation dialog box **************/