[gimp] app: Add support for multiple items selection



commit ebe9e51b62a61d903d2ecc908c469d45b7fd3e83
Author: Aurimas Juška <aurimas juska gmail com>
Date:   Sun Mar 7 18:54:20 2010 +0200

    app: Add support for multiple items selection
    
    Implemented infrastructure for multiple selection support.
    GimpContainerTreeView actually provides such functionality.
    All other GimpContainerViews should work as before.

 app/actions/actions.c               |   16 ++++
 app/actions/actions.h               |    1 +
 app/actions/brushes-actions.c       |    5 ++
 app/actions/gradients-actions.c     |    5 ++
 app/actions/palettes-actions.c      |    5 ++
 app/actions/patterns-actions.c      |    5 ++
 app/widgets/gimpcontainertreeview.c |  136 ++++++++++++++++++++++++++++-------
 app/widgets/gimpcontainerview.c     |   76 +++++++++++++++++++
 app/widgets/gimpcontainerview.h     |    9 ++-
 9 files changed, 229 insertions(+), 29 deletions(-)
---
diff --git a/app/actions/actions.c b/app/actions/actions.c
index 3e39eef..0040bcf 100644
--- a/app/actions/actions.c
+++ b/app/actions/actions.c
@@ -431,6 +431,22 @@ action_data_get_widget (gpointer data)
   return dialogs_get_toolbox ();
 }
 
+gint
+action_data_sel_count (gpointer data)
+{
+  if (GIMP_IS_CONTAINER_EDITOR (data))
+    {
+      GimpContainerEditor  *editor;
+
+      editor = GIMP_CONTAINER_EDITOR (data);
+      return gimp_container_view_get_selected (editor->view, NULL);
+    }
+  else
+    {
+      return 0;
+    }
+}
+
 gdouble
 action_select_value (GimpActionSelectType  select_type,
                      gdouble               value,
diff --git a/app/actions/actions.h b/app/actions/actions.h
index 6db2db3..8a9c354 100644
--- a/app/actions/actions.h
+++ b/app/actions/actions.h
@@ -31,6 +31,7 @@ GimpImage        * action_data_get_image   (gpointer              data);
 GimpDisplay      * action_data_get_display (gpointer              data);
 GimpDisplayShell * action_data_get_shell   (gpointer              data);
 GtkWidget        * action_data_get_widget  (gpointer              data);
+gint               action_data_sel_count   (gpointer              data);
 
 gdouble            action_select_value     (GimpActionSelectType  select_type,
                                             gdouble               value,
diff --git a/app/actions/brushes-actions.c b/app/actions/brushes-actions.c
index d5b9c39..97d4d43 100644
--- a/app/actions/brushes-actions.c
+++ b/app/actions/brushes-actions.c
@@ -115,6 +115,11 @@ brushes_actions_update (GimpActionGroup *group,
     {
       brush = gimp_context_get_brush (context);
 
+      if (action_data_sel_count (user_data) > 1)
+        {
+          brush = NULL;
+        }
+
       if (brush)
         {
           data = GIMP_DATA (brush);
diff --git a/app/actions/gradients-actions.c b/app/actions/gradients-actions.c
index a990190..98833bb 100644
--- a/app/actions/gradients-actions.c
+++ b/app/actions/gradients-actions.c
@@ -116,6 +116,11 @@ gradients_actions_update (GimpActionGroup *group,
     {
       gradient = gimp_context_get_gradient (context);
 
+      if (action_data_sel_count (user_data) > 1)
+        {
+          gradient = NULL;
+        }
+
       if (gradient)
         {
           data = GIMP_DATA (gradient);
diff --git a/app/actions/palettes-actions.c b/app/actions/palettes-actions.c
index 4a46acb..3f6eb21 100644
--- a/app/actions/palettes-actions.c
+++ b/app/actions/palettes-actions.c
@@ -122,6 +122,11 @@ palettes_actions_update (GimpActionGroup *group,
     {
       palette = gimp_context_get_palette (context);
 
+      if (action_data_sel_count (user_data) > 1)
+        {
+          palette = NULL;
+        }
+
       if (palette)
         {
           data = GIMP_DATA (palette);
diff --git a/app/actions/patterns-actions.c b/app/actions/patterns-actions.c
index 87ed336..3f16ac6 100644
--- a/app/actions/patterns-actions.c
+++ b/app/actions/patterns-actions.c
@@ -115,6 +115,11 @@ patterns_actions_update (GimpActionGroup *group,
     {
       pattern = gimp_context_get_pattern (context);
 
+      if (action_data_sel_count (user_data) > 1)
+        {
+          pattern = NULL;
+        }
+
       if (pattern)
         {
           data = GIMP_DATA (pattern);
diff --git a/app/widgets/gimpcontainertreeview.c b/app/widgets/gimpcontainertreeview.c
index 8ee76ac..6e56b51 100644
--- a/app/widgets/gimpcontainertreeview.c
+++ b/app/widgets/gimpcontainertreeview.c
@@ -99,6 +99,11 @@ static GimpViewable *gimp_container_tree_view_drag_viewable     (GtkWidget
 static GdkPixbuf    *gimp_container_tree_view_drag_pixbuf       (GtkWidget                   *widget,
                                                                  gpointer                     data);
 
+static gboolean      gimp_container_tree_view_get_selected_single (GimpContainerTreeView  *tree_view,
+                                                                   GtkTreeIter            *iter);
+static gint          gimp_container_tree_view_get_selected        (GimpContainerView    *view,
+                                                                   GList               **items);
+
 
 G_DEFINE_TYPE_WITH_CODE (GimpContainerTreeView, gimp_container_tree_view,
                          GIMP_TYPE_CONTAINER_BOX,
@@ -147,6 +152,7 @@ gimp_container_tree_view_view_iface_init (GimpContainerViewInterface *iface)
   iface->select_item   = gimp_container_tree_view_select_item;
   iface->clear_items   = gimp_container_tree_view_clear_items;
   iface->set_view_size = gimp_container_tree_view_set_view_size;
+  iface->get_selected  = gimp_container_tree_view_get_selected;
 
   iface->insert_data_free = (GDestroyNotify) gtk_tree_iter_free;
 }
@@ -249,6 +255,9 @@ gimp_container_tree_view_constructor (GType                  type,
 
   tree_view->priv->selection = gtk_tree_view_get_selection (tree_view->view);
 
+  gtk_tree_selection_set_mode (tree_view->priv->selection,
+                               GTK_SELECTION_MULTIPLE);
+
   g_signal_connect (tree_view->priv->selection, "changed",
                     G_CALLBACK (gimp_container_tree_view_selection_changed),
                     tree_view);
@@ -334,8 +343,7 @@ gimp_container_tree_view_menu_position (GtkMenu  *menu,
       *y += allocation.y;
     }
 
-  if (gtk_tree_selection_get_selected (tree_view->priv->selection, NULL,
-                                       &selected_iter))
+  if (gimp_container_tree_view_get_selected_single (tree_view, &selected_iter))
     {
       GtkTreePath  *path;
       GdkRectangle  cell_rect;
@@ -680,8 +688,8 @@ gimp_container_tree_view_reorder_item (GimpContainerView *view,
       else
         container = gimp_container_view_get_container (view);
 
-      selected = gtk_tree_selection_get_selected (tree_view->priv->selection,
-                                                  NULL, &selected_iter);
+      selected = gimp_container_tree_view_get_selected_single (tree_view,
+                                                               &selected_iter);
 
       if (selected)
         {
@@ -780,11 +788,11 @@ gimp_container_tree_view_select_item (GimpContainerView *view,
                                       gpointer           insert_data)
 {
   GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
-  GtkTreeIter           *iter      = (GtkTreeIter *) insert_data;
 
-  if (iter)
+  if (viewable && insert_data)
     {
       GtkTreePath *path;
+      GtkTreeIter *iter = (GtkTreeIter *) insert_data;
 
       path = gtk_tree_model_get_path (tree_view->model, iter);
 
@@ -803,8 +811,10 @@ gimp_container_tree_view_select_item (GimpContainerView *view,
 
       gtk_tree_path_free (path);
     }
-  else
+  else if (insert_data == NULL)
     {
+      /* viewable == NULL && insert_data != NULL means multiple selection.
+       * viewable == NULL && insert_data == NULL means no selection. */
       gtk_tree_selection_unselect_all (tree_view->priv->selection);
     }
 
@@ -922,7 +932,7 @@ gimp_container_tree_view_name_canceled (GtkCellRendererText   *cell,
 {
   GtkTreeIter iter;
 
-  if (gtk_tree_selection_get_selected (tree_view->priv->selection, NULL, &iter))
+  if (gimp_container_tree_view_get_selected_single (tree_view, &iter))
     {
       GimpViewRenderer *renderer;
       gchar            *name;
@@ -946,20 +956,12 @@ static void
 gimp_container_tree_view_selection_changed (GtkTreeSelection      *selection,
                                             GimpContainerTreeView *tree_view)
 {
-  GtkTreeIter iter;
+  GimpContainerView    *view = GIMP_CONTAINER_VIEW (tree_view);
+  GList                *items;
 
-  if (gtk_tree_selection_get_selected (selection, NULL, &iter))
-    {
-      GimpViewRenderer *renderer;
-
-      gtk_tree_model_get (tree_view->model, &iter,
-                          GIMP_CONTAINER_TREE_VIEW_COLUMN_RENDERER, &renderer,
-                          -1);
-
-      gimp_container_view_item_selected (GIMP_CONTAINER_VIEW (tree_view),
-                                         renderer->viewable);
-      g_object_unref (renderer);
-    }
+  gimp_container_tree_view_get_selected (view, &items);
+  gimp_container_view_multi_selected (view, items);
+  g_list_free (items);
 }
 
 static GtkCellRenderer *
@@ -1028,6 +1030,7 @@ gimp_container_tree_view_button_press (GtkWidget             *widget,
       GtkCellRenderer          *edit_cell    = NULL;
       GdkRectangle              column_area;
       GtkTreeIter               iter;
+      gboolean                  handled = TRUE;
 
       gtk_tree_model_get_iter (tree_view->model, &iter, path);
 
@@ -1100,12 +1103,9 @@ gimp_container_tree_view_button_press (GtkWidget             *widget,
         case 1:
           if (bevent->type == GDK_BUTTON_PRESS)
             {
-              gboolean success = TRUE;
-
               /*  don't select item if a toggle was clicked */
               if (! toggled_cell)
-                success = gimp_container_view_item_selected (container_view,
-                                                             renderer->viewable);
+                  handled = FALSE;
 
               /*  a callback invoked by selecting the item may have
                *  destroyed us, so check if the container is still there
@@ -1217,6 +1217,8 @@ gimp_container_tree_view_button_press (GtkWidget             *widget,
 
       gtk_tree_path_free (path);
       g_object_unref (renderer);
+
+      return handled;
     }
   else
     {
@@ -1229,9 +1231,9 @@ gimp_container_tree_view_button_press (GtkWidget             *widget,
         default:
           break;
         }
-    }
 
-  return TRUE;
+      return TRUE;
+    }
 }
 
 static gboolean
@@ -1333,3 +1335,83 @@ gimp_container_tree_view_drag_pixbuf (GtkWidget *widget,
 
   return NULL;
 }
+
+static gboolean
+gimp_container_tree_view_get_selected_single (GimpContainerTreeView  *tree_view,
+                                               GtkTreeIter            *iter)
+{
+  GtkTreeSelection         *selection;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view->view));
+
+  if (gtk_tree_selection_count_selected_rows (selection) == 1)
+    {
+      GList    *selected_rows;
+
+      selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
+
+      gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->model), iter,
+                               (GtkTreePath *) selected_rows->data);
+
+      g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
+      g_list_free (selected_rows);
+
+      return TRUE;
+    }
+  else
+    {
+      return FALSE;
+    }
+}
+
+static gint
+gimp_container_tree_view_get_selected (GimpContainerView    *view,
+                                       GList               **items)
+{
+  GimpContainerTreeView    *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
+  GtkTreeSelection         *selection;
+  gint                      selected_count;
+  GList                    *selected_rows;
+  GList                    *current_row;
+  GtkTreeIter               iter;
+  GimpViewRenderer         *renderer;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view->view));
+  selected_count = gtk_tree_selection_count_selected_rows (selection);
+
+  if (items == NULL)
+    {
+      /* just provide selected count */
+      return selected_count;
+    }
+
+  selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
+
+  *items = NULL;
+  for (current_row = g_list_first (selected_rows);
+       current_row;
+       current_row = g_list_next (current_row))
+    {
+      gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->model), &iter,
+                               (GtkTreePath *) current_row->data);
+
+      gtk_tree_model_get (tree_view->model, &iter,
+                          GIMP_CONTAINER_TREE_VIEW_COLUMN_RENDERER, &renderer,
+                          -1);
+
+      if (renderer->viewable)
+        {
+          *items = g_list_prepend (*items, renderer->viewable);
+        }
+
+      g_object_unref (renderer);
+    }
+
+  g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
+  g_list_free (selected_rows);
+
+  *items = g_list_reverse (*items);
+
+  return selected_count;
+}
+
diff --git a/app/widgets/gimpcontainerview.c b/app/widgets/gimpcontainerview.c
index 41a24e6..0de7ccf 100644
--- a/app/widgets/gimpcontainerview.c
+++ b/app/widgets/gimpcontainerview.c
@@ -37,6 +37,8 @@
 #include "gimpcontainerview.h"
 #include "gimpdnd.h"
 #include "gimpviewrenderer.h"
+#include "gimpuimanager.h"
+#include "gimpcontainertreeview.h"
 
 
 enum
@@ -128,6 +130,8 @@ static void  gimp_container_view_button_viewable_dropped (GtkWidget    *widget,
                                                           gint          y,
                                                           GimpViewable *viewable,
                                                           gpointer      data);
+static gint  gimp_container_view_real_get_selected (GimpContainerView    *view,
+                                                    GList               **list);
 
 
 static guint view_signals[LAST_SIGNAL] = { 0 };
@@ -210,6 +214,7 @@ gimp_container_view_iface_base_init (GimpContainerViewInterface *view_iface)
   view_iface->rename_item       = NULL;
   view_iface->clear_items       = gimp_container_view_real_clear_items;
   view_iface->set_view_size     = NULL;
+  view_iface->get_selected      = gimp_container_view_real_get_selected;
 
   view_iface->insert_data_free  = NULL;
   view_iface->model_is_tree     = FALSE;
@@ -728,6 +733,76 @@ gimp_container_view_item_selected (GimpContainerView *view,
   return success;
 }
 
+gboolean
+gimp_container_view_multi_selected (GimpContainerView *view,
+                                    GList             *items)
+{
+  guint                     selected_count;
+  gboolean                  success = FALSE;
+
+  g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), FALSE);
+
+  selected_count = g_list_length (items);
+
+  if (selected_count == 0)
+    {
+      /* do nothing */
+    }
+  else if (selected_count == 1)
+    {
+      success = gimp_container_view_item_selected (view, items->data);
+    }
+  else
+    {
+      success = FALSE;
+      g_signal_emit (view, view_signals[SELECT_ITEM], 0,
+                     NULL, items, &success);
+    }
+
+  return success;
+}
+
+gint
+gimp_container_view_get_selected (GimpContainerView  *view,
+                                  GList             **list)
+{
+  g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), 0);
+
+  return GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->get_selected (view, list);
+}
+
+static gint
+gimp_container_view_real_get_selected (GimpContainerView    *view,
+                                       GList               **list)
+{
+  GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
+  GType                     children_type;
+  GimpObject               *object;
+
+  if (list)
+    {
+      *list = NULL;
+    }
+
+  if (!private->container
+      || !private->context)
+    {
+      return 0;
+    }
+
+  children_type = gimp_container_get_children_type (private->container);
+  object = gimp_context_get_by_type (private->context,
+                                     children_type);
+
+  if (list
+      && object)
+    {
+      *list = g_list_append (*list, object);
+    }
+
+  return object != NULL;
+}
+
 void
 gimp_container_view_item_activated (GimpContainerView *view,
                                     GimpViewable      *viewable)
@@ -1194,3 +1269,4 @@ gimp_container_view_button_viewable_dropped (GtkWidget    *widget,
       gtk_button_clicked (GTK_BUTTON (widget));
     }
 }
+
diff --git a/app/widgets/gimpcontainerview.h b/app/widgets/gimpcontainerview.h
index 1157f09..41b63a8 100644
--- a/app/widgets/gimpcontainerview.h
+++ b/app/widgets/gimpcontainerview.h
@@ -81,6 +81,9 @@ struct _GimpContainerViewInterface
                                   gpointer           insert_data);
   void     (* clear_items)       (GimpContainerView *view);
   void     (* set_view_size)     (GimpContainerView *view);
+  gint     (* get_selected)      (GimpContainerView  *view,
+                                  GList             **items);
+
 
   /*  the destroy notifier for private->hash_table's values  */
   GDestroyNotify  insert_data_free;
@@ -122,7 +125,8 @@ void      gimp_container_view_activate_item    (GimpContainerView *view,
                                                 GimpViewable      *viewable);
 void      gimp_container_view_context_item     (GimpContainerView *view,
                                                 GimpViewable      *viewable);
-
+gint      gimp_container_view_get_selected     (GimpContainerView  *view,
+                                                GList             **list);
 
 /*  protected  */
 
@@ -131,6 +135,8 @@ gpointer  gimp_container_view_lookup           (GimpContainerView *view,
 
 gboolean  gimp_container_view_item_selected    (GimpContainerView *view,
                                                 GimpViewable      *item);
+gboolean  gimp_container_view_multi_selected   (GimpContainerView *view,
+                                                GList             *items);
 void      gimp_container_view_item_activated   (GimpContainerView *view,
                                                 GimpViewable      *item);
 void      gimp_container_view_item_context     (GimpContainerView *view,
@@ -148,5 +154,4 @@ void      gimp_container_view_get_property       (GObject      *object,
                                                   GValue       *value,
                                                   GParamSpec   *pspec);
 
-
 #endif  /*  __GIMP_CONTAINER_VIEW_H__  */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]