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

Reply via email to