Hi,
This patch
-Fixes the problem with the active diagram changing during resize
-Adds an asterisk to the tab to show that a diagram has been modified.
-Adds a new dialog to give the user the ability to choose which unsaved
files to save at exit.
The bulk of the patch is the new files exit_dialog.c and exit_dialog.h
Index: display.c
===================================================================
--- display.c (revision 3721)
+++ display.c (working copy)
@@ -96,6 +96,12 @@
GtkStatusbar *statusbar;
guint context_id;
+ if (is_integrated_ui ())
+ {
+ integrated_ui_show_diagram_modified_status (ddisp);
+ return;
+ }
+
if (diagram_is_modified(ddisp->diagram))
{
statusbar = GTK_STATUSBAR (ddisp->modified_status);
Index: makefile.msc
===================================================================
--- makefile.msc (revision 3721)
+++ makefile.msc (working copy)
@@ -48,6 +48,7 @@
disp_callbacks.obj \
display.obj \
dynamic_refresh.obj \
+ exit_dialog.obj \
export_png.obj \
filedlg.obj \
grid.obj \
Index: app_procs.c
===================================================================
--- app_procs.c (revision 3721)
+++ app_procs.c (working copy)
@@ -95,6 +95,7 @@
#include "persistence.h"
#include "sheets.h"
#include "utils.h"
+#include "exit_dialog.h"
#if defined(HAVE_LIBPNG) && defined(HAVE_LIBART)
extern DiaExportFilter png_export_filter;
@@ -1017,9 +1018,60 @@
}
if (diagram_modified_exists()) {
+ if (is_integrated_ui ())
+ {
+ GtkWidget *dialog;
+ int result;
+ exit_dialog_item_array_t *items = NULL;
+ GList * list;
+ Diagram * diagram;
+
+ dialog = exit_dialog_make (GTK_WINDOW (interface_get_toolbox_shell ()),
+ _("Exiting Dia"));
+
+ list = dia_open_diagrams();
+ while (list)
+ {
+ diagram = list->data;
+
+ if (diagram_is_modified (diagram))
+ {
+ const gchar * name = diagram_get_name (diagram);
+ const gchar * path = diagram->filename;
+ exit_dialog_add_item (dialog, name, path, diagram);
+ }
+
+ list = g_slist_next (list);
+ }
+
+ result = exit_dialog_run (dialog, &items);
+
+ gtk_widget_destroy (dialog);
+
+ if (result == EXIT_DIALOG_EXIT_CANCEL)
+ {
+ return FALSE;
+ }
+ else if (result == EXIT_DIALOG_EXIT_SAVE_SELECTED)
+ {
+ int i;
+ for (i = 0 ; i < items->array_size ; i++)
+ {
+ gchar *filename;
+
+ diagram = items->array[i].data;
+ filename = g_filename_from_utf8 (diagram->filename, -1, NULL, NULL, NULL);
+ diagram_update_extents (diagram);
+ diagram_save (diagram, filename);
+ g_free (filename);
+ }
+ exit_dialog_free_items (items);
+ }
+ }
+ else
+ {
GtkWidget *dialog;
GtkWidget *button;
-
dialog = gtk_message_dialog_new(
NULL, GTK_DIALOG_MODAL,
GTK_MESSAGE_QUESTION,
@@ -1047,6 +1099,7 @@
return FALSE;
}
gtk_widget_destroy(dialog);
+ }
}
prefs_save();
Index: exit_dialog.c
===================================================================
--- exit_dialog.c (revision 0)
+++ exit_dialog.c (revision 0)
@@ -0,0 +1,435 @@
+/*
+ * exit_dialog.h: Dialog to allow the user to choose which data to
+ * save on exit or to cancel exit.
+ *
+ * Copyright (C) 2007 Patrick Hallinan
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* TODO: Non-modal api */
+
+#include <config.h>
+
+#include "exit_dialog.h"
+
+#include "intl.h"
+
+#include <gtk/gtk.h>
+
+#include <glib.h>
+
+#define EXIT_DIALOG_ITEM_DATA _("EXIT_DIALOG_ITEM_DATA")
+
+enum {
+ CHECK_COL,
+ NAME_COL,
+ PATH_COL,
+ DATA_COL, /* To store optional data (not shown in listview) */
+ NUM_COL
+};
+
+typedef struct
+{
+ GSList * item_list;
+ GtkTreeView * treeview;
+
+} exit_dialog_item_data_t;
+
+static void selected_state_set_all (GtkTreeView * treeview,
+ gboolean state);
+
+static gint get_selected_items (GtkWidget * dialog,
+ exit_dialog_item_array_t ** items);
+
+/* Event Handlers */
+static void select_all_clicked (GtkButton * button,
+ gpointer data);
+
+static void select_none_clicked (GtkButton * button,
+ gpointer data);
+
+static void toggle_check_button (GtkCellRendererToggle * renderer,
+ gchar * path,
+ GtkTreeView * treeview);
+
+/* A dialog to allow a user to select which unsaved files to save
+ * (if any) or to abort exiting
+ *
+ * @param parent_window This is needed for modal behavior.
+ * @param title Text display on the dialog's title bar.
+ * @return The dialog.
+ */
+GtkWidget *
+exit_dialog_make (GtkWindow * parent_window,
+ gchar * title)
+{
+ GtkWidget * dialog = gtk_dialog_new_with_buttons (title, parent_window,
+ GTK_DIALOG_MODAL,
+ _("Do Not Exit"),
+ EXIT_DIALOG_EXIT_CANCEL,
+ _("Exit Without Save"),
+ EXIT_DIALOG_EXIT_NO_SAVE,
+ _("Save Selected"),
+ EXIT_DIALOG_EXIT_SAVE_SELECTED,
+ NULL);
+
+ GtkBox * vbox = GTK_BOX (GTK_DIALOG(dialog)->vbox);
+
+ GtkWidget * label = gtk_label_new (_("The following are not saved:"));
+
+ GSList * list;
+ GtkWidget * scrolled;
+ GtkWidget * button;
+ GtkWidget * hbox;
+
+ GtkWidget * treeview;
+ GtkListStore * model;
+ GtkCellRenderer * renderer;
+ GtkTreeViewColumn * column;
+
+ exit_dialog_item_data_t * data;
+
+ gtk_box_pack_start (vbox, label, FALSE, FALSE, 0);
+
+ gtk_widget_show (label);
+
+ /* Scrolled window for displaying things which need saving */
+ scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_box_pack_start (vbox, scrolled, TRUE, TRUE, 0);
+ gtk_widget_show (scrolled);
+
+ model = gtk_list_store_new (NUM_COL, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
+
+ treeview = gtk_tree_view_new_with_model ( GTK_TREE_MODEL(model));
+
+ renderer = gtk_cell_renderer_toggle_new ();
+
+ column = gtk_tree_view_column_new_with_attributes (_("Save"), renderer,
+ _("active"), CHECK_COL,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+ g_signal_connect (G_OBJECT (renderer), "toggled",
+ G_CALLBACK (toggle_check_button),
+ treeview);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("Name"), renderer,
+ "text", NAME_COL,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("Path"), renderer,
+ "text", PATH_COL,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled), GTK_WIDGET (treeview));
+
+
+ hbox = gtk_hbox_new (FALSE, 3);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ button = gtk_button_new_with_label (_("Select All"));
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 3);
+ gtk_widget_show (button);
+
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (select_all_clicked),
+ treeview);
+
+ button = gtk_button_new_with_label (_("Select None"));
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 3);
+ gtk_widget_show (button);
+
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (select_none_clicked),
+ treeview);
+
+ g_object_unref (model);
+ gtk_widget_show (GTK_WIDGET (treeview));
+
+ list = g_slist_alloc ();
+
+ data = g_malloc (sizeof (exit_dialog_item_data_t));
+ data->item_list = list;
+ data->treeview = GTK_TREE_VIEW (treeview);
+
+ gtk_widget_show_all (GTK_WIDGET(vbox));
+
+ g_object_set_data (G_OBJECT (dialog), EXIT_DIALOG_ITEM_DATA, data);
+
+ return dialog;
+}
+
+/**
+ * Add name and path of a file that needs to be saved
+ * @param dialog Exit dialog created with exit_dialog_make()
+ * @param name User identifiable name of the thing which needs saving.
+ * @param path File system path of the thing which needs saving.
+ * @param optional_data Optional data to be returned with selected file info.
+ */
+void
+exit_dialog_add_item (GtkWidget * dialog,
+ const gchar * name,
+ const gchar * path,
+ const gpointer optional_data)
+{
+ GtkTreeIter iter;
+ GtkListStore * model;
+
+ exit_dialog_item_data_t * data =
+ g_object_get_data (G_OBJECT (dialog), EXIT_DIALOG_ITEM_DATA);
+
+ model = GTK_LIST_STORE (gtk_tree_view_get_model (data->treeview));
+
+ gtk_list_store_append (model, &iter);
+
+ gtk_list_store_set (model, &iter,
+ CHECK_COL, 1,
+ NAME_COL, name,
+ PATH_COL, path,
+ DATA_COL, optional_data,
+ -1);
+}
+
+gint
+exit_dialog_run (GtkWidget * dialog,
+ exit_dialog_item_array_t ** items)
+{
+ gint result;
+ gint count;
+
+ while (TRUE)
+ {
+ result = gtk_dialog_run ( GTK_DIALOG(dialog));
+
+ switch (result)
+ {
+ case EXIT_DIALOG_EXIT_CANCEL:
+ case EXIT_DIALOG_EXIT_NO_SAVE:
+ *items = NULL;
+ return result;
+ }
+
+ count = get_selected_items (dialog, items);
+
+ if (count == 0)
+ {
+ const gchar * msg = _("Nothing selected for saving. Would you like to try again?");
+
+ GtkWidget * msg_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_YES_NO,
+ msg);
+
+ gint yes_or_no = gtk_dialog_run (GTK_DIALOG (msg_dialog));
+
+ gtk_widget_destroy (msg_dialog);
+
+ if (yes_or_no == GTK_RESPONSE_NO)
+ {
+ return EXIT_DIALOG_EXIT_NO_SAVE;
+ }
+ }
+ else
+ {
+ return EXIT_DIALOG_EXIT_SAVE_SELECTED;
+ }
+ }
+}
+
+
+/**
+ * Gets the list of items selected for saving by the user.
+ * @param dialog Exit dialog.
+ * @param items Structure to hold the selected items. Set to NULL if not items selected.
+ * @return The number of selected items.
+ */
+gint
+get_selected_items (GtkWidget * dialog,
+ exit_dialog_item_array_t ** items)
+{
+ exit_dialog_item_data_t * data;
+ GtkTreeIter iter;
+ GtkListStore * model;
+ gboolean valid;
+ GSList * list = NULL;
+ GSList * list_iter;
+ gint selected_count;
+ gint i;
+
+ data = g_object_get_data (G_OBJECT (dialog), EXIT_DIALOG_ITEM_DATA);
+
+ model = GTK_LIST_STORE (gtk_tree_view_get_model (data->treeview));
+
+ /* Get the first iter in the list */
+ valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
+
+ /* Get the selected items */
+ while (valid)
+ {
+ const char * name;
+ const char * path;
+ gpointer data;
+ gboolean is_selected;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
+ CHECK_COL, &is_selected,
+ NAME_COL, &name,
+ PATH_COL, &path,
+ DATA_COL, &data,
+ -1);
+
+ if (is_selected)
+ {
+ exit_dialog_item_t * item = g_new (exit_dialog_item_t,1);
+ item->name = name;
+ item->path = path;
+ item->data = data;
+ list = g_slist_prepend (list, item);
+ }
+
+ valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
+ }
+
+ selected_count = g_slist_length (list);
+
+ if (selected_count > 0)
+ {
+ *items = g_new (exit_dialog_item_array_t,1);
+ (*items)->array_size = selected_count;
+ (*items)->array = g_new (exit_dialog_item_t, (*items)->array_size);
+
+ list_iter = list;
+ for(i = 0 ; i < selected_count ; i++)
+ {
+ exit_dialog_item_t * item = list_iter->data;
+ (*items)->array[i].name = item->name;
+ (*items)->array[i].path = item->path;
+ (*items)->array[i].data = item->data;
+ list_iter = g_slist_next(list_iter);
+ }
+
+ g_slist_free (list);
+ }
+ else
+ {
+ *items = NULL;
+ }
+
+ return selected_count;
+}
+
+/**
+ * Free memory allocated for the exit_dialog_item_array_t. This
+ * will not free any memory not allocated by the dialog itself
+ * @param items Item array struct returned by exit_dialog_run()
+ */
+void exit_dialog_free_items (exit_dialog_item_array_t * items)
+{
+ if (items)
+ {
+ int i;
+ for (i = 0 ; i < items->array_size ; i++)
+ {
+ /* Cast is needed to remove warning because of const decl */
+ g_free ( (char*)items->array[i].name);
+ g_free ( (char*)items->array[i].path);
+ }
+
+ g_free (items);
+ }
+}
+
+/**
+ * Handler for the check box (button) in the exit dialogs treeview.
+ * This is needed to cause the check box to change state when the
+ * user clicks it
+ */
+static void toggle_check_button (GtkCellRendererToggle * renderer,
+ gchar * path,
+ GtkTreeView * treeview)
+{
+ GtkTreeModel * model;
+ GtkTreeIter iter;
+ gboolean value;
+
+ model = gtk_tree_view_get_model (treeview);
+ if (gtk_tree_model_get_iter_from_string (model, &iter, path))
+ {
+ gtk_tree_model_get (model, &iter, CHECK_COL, &value, -1);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, CHECK_COL, !value, -1);
+ }
+}
+
+/**
+ * Sets the state of the save checkbox in the treeview to the
+ * state specified by the caller.
+ * @param treeview The treeview in the exit dialog box.
+ * @param state Set to TRUE to select all, FALSE to de-select all.
+ */
+static void selected_state_set_all (GtkTreeView * treeview,
+ gboolean state)
+{
+ GtkTreeIter iter;
+ GtkListStore * model;
+ gboolean valid;
+
+ model = GTK_LIST_STORE (gtk_tree_view_get_model (treeview));
+
+ /* Get the first iter in the list */
+ valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
+
+ while (valid)
+ {
+ gtk_list_store_set (model, &iter,
+ CHECK_COL, state,
+ -1);
+
+ valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
+ }
+}
+
+/**
+ * Handler for Select All button. Causes all checkboxes in the
+ * exit dialog box treeview to be checked.
+ * @param button The Select all button.
+ * @param data The treeview
+ */
+static void select_all_clicked (GtkButton * button,
+ gpointer data)
+{
+ selected_state_set_all (data, TRUE);
+}
+
+/**
+ * Handler for Select All button. Causes all checkboxes in the
+ * exit dialog box treeview to be un-checked.
+ * @param button The Select all button.
+ * @param data The treeview
+ */
+static void select_none_clicked (GtkButton * button,
+ gpointer data)
+{
+ selected_state_set_all (data, FALSE);
+}
+
+
Index: exit_dialog.h
===================================================================
--- exit_dialog.h (revision 0)
+++ exit_dialog.h (revision 0)
@@ -0,0 +1,70 @@
+/*
+ * exit_dialog.h: Dialog to allow the user to choose which data to
+ * save on exit or to cancel exit.
+ *
+ * Copyright (C) 2007 Patrick Hallinan
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EXIT_DIALOG_H
+#define EXIT_DIALOG_H
+
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkwindow.h>
+
+G_BEGIN_DECLS
+
+enum {
+ EXIT_DIALOG_EXIT_NO_SAVE,
+ EXIT_DIALOG_EXIT_SAVE_SELECTED,
+ EXIT_DIALOG_EXIT_CANCEL
+};
+
+GtkWidget *
+exit_dialog_make (GtkWindow * parent_window,
+ gchar * title);
+
+void
+exit_dialog_add_item (GtkWidget * dialog,
+ const gchar * name,
+ const gchar * filepath,
+ const gpointer optional_data);
+
+typedef struct
+{
+ const gchar * name;
+ const gchar * path;
+ gpointer data;
+
+} exit_dialog_item_t;
+
+typedef struct
+{
+ size_t array_size;
+ exit_dialog_item_t * array;
+
+} exit_dialog_item_array_t;
+
+gint
+exit_dialog_run (GtkWidget * dialog,
+ exit_dialog_item_array_t ** items_to_save);
+
+void exit_dialog_free_items (exit_dialog_item_array_t *);
+
+G_END_DECLS
+
+#endif
+
Index: Makefile.am
===================================================================
--- Makefile.am (revision 3721)
+++ Makefile.am (working copy)
@@ -90,6 +90,8 @@
oafinfo_DATA = $(dia_oafinfo)
dia_core_files = \
+ exit_dialog.h \
+ exit_dialog.c \
diagram.c \
diagram.h \
preferences.c \
Index: interface.c
===================================================================
--- interface.c (revision 3721)
+++ interface.c (working copy)
@@ -438,6 +438,41 @@
}
/**
+ * Change diagram notebook label to show that the diagram has
+ * been modified (or that it hasn't been modified).
+ *
+ * @param ddisp The display which needs the label updated.
+ */
+void integrated_ui_show_diagram_modified_status (DDisplay *ddisp)
+{
+ GtkLabel * label = g_object_get_data (G_OBJECT (ddisp->container), "tab-label");
+ const gchar * name;
+ const gchar * sep;
+
+ sep = g_strrstr (ddisp->diagram->filename,G_DIR_SEPARATOR_S);
+
+ if (sep)
+ {
+ name = sep + 1; /* IS THIS PORTABLE??? */
+ }
+ else
+ {
+ name = ddisp->diagram->filename;
+ }
+
+ if (diagram_is_modified (ddisp->diagram))
+ {
+ const gchar * text = g_strdup_printf ("*%s",name);
+ gtk_label_set_text (label, text);
+ g_free (text);
+ }
+ else
+ {
+ gtk_label_set_text (label,name);
+ }
+}
+
+/**
* @param ddisp The diagram display object that a window is created for
* @param title
*/
Index: interface.h
===================================================================
--- interface.h (revision 3721)
+++ interface.h (working copy)
@@ -53,12 +53,10 @@
void integrated_ui_main_statusbar_show (void);
void integrated_ui_main_statusbar_hide (void);
-/*
-void synchronize_ui_to_active_display (DDisplay *ddisp);
-*/
-
int is_integrated_ui (void);
+void integrated_ui_show_diagram_modified_status (DDisplay *ddisp);
+
void create_display_shell(DDisplay *ddisp,
int width, int height,
char *title, int use_mbar, int top_level_window);
Index: makefile.mingw
===================================================================
--- makefile.mingw (revision 3721)
+++ makefile.mingw (working copy)
@@ -43,6 +43,7 @@
disp_callbacks.o \
display.o \
dynamic_refresh.o \
+ exit_dialog.o \
export_png.o \
filedlg.o \
grid.o \
Index: disp_callbacks.c
===================================================================
--- disp_callbacks.c (revision 3721)
+++ disp_callbacks.c (working copy)
@@ -527,7 +527,11 @@
ddisp->canvas->allocation.height);
ddisplay_update_scrollbars(ddisp);
}
- display_set_active(ddisp);
+ /* TODO: Find out if display_set_active is needed for the GDK_CONFIGURE event */
+ /* This is prevented for the integrated UI because it causes the diagram
+ showing in the diagram notebook to change on a resize event */
+ if (is_integrated_ui () == 0)
+ display_set_active(ddisp);
break;
case GDK_FOCUS_CHANGE: {
_______________________________________________
Dia-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/dia-list
FAQ at http://live.gnome.org/Dia/Faq
Main page at http://live.gnome.org/Dia