[gitg] Implement selection mode for dash view



commit 69af08620963e2872eca1a45ee82c27a2d0930fd
Author: Jesse van den Kieboom <jessevdk gnome org>
Date:   Tue Jul 15 10:04:25 2014 +0200

    Implement selection mode for dash view

 gitg/gitg-window.vala                             |  144 ++++++++++++++++++++-
 gitg/resources/ui/gitg-window.ui                  |   35 +++++-
 libgitg-ext/Makefile.am                           |    1 +
 libgitg-ext/gitg-ext-selectable.vala              |   43 ++++++
 libgitg/gitg-repository-list-box.vala             |  118 +++++++++++++++--
 libgitg/resources/gitg-repository-list-box-row.ui |   21 ++--
 6 files changed, 336 insertions(+), 26 deletions(-)
---
diff --git a/gitg/gitg-window.vala b/gitg/gitg-window.vala
index be1db33..c61c2a3 100644
--- a/gitg/gitg-window.vala
+++ b/gitg/gitg-window.vala
@@ -31,6 +31,7 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
        private Gee.HashMap<string, string> d_environment;
        private bool d_busy;
        private Gtk.Dialog? d_dialog;
+       private Gtk.Widget? d_select_actions;
 
        private UIElements<GitgExt.Activity> d_activities;
 
@@ -44,7 +45,13 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
        private MenuModel d_dash_model;
        private MenuModel d_activities_model;
 
+       [GtkChild]
+       private Gtk.Grid d_grid_main;
 
+       [GtkChild]
+       private Gtk.ToggleButton d_select_button;
+       [GtkChild]
+       private Gtk.Button d_select_cancel_button;
 
        [GtkChild]
        private Gtk.Button d_dash_button;
@@ -126,6 +133,7 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
                {"reload", on_reload_activated},
                {"author-details-global", on_global_author_details_activated},
                {"author-details-repo", on_repo_author_details_activated},
+               {"select", on_select_activated, null, "false", null}
        };
 
        [GtkCallback]
@@ -212,9 +220,11 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
 
                d_header_bar.remove(d_activities_switcher);
                d_header_bar.remove(d_search_button);
+               d_header_bar.remove(d_select_button);
                d_header_bar.remove(d_gear_menu);
 
                d_header_bar.pack_end(d_gear_menu);
+               d_header_bar.pack_end(d_select_button);
                d_header_bar.pack_end(d_search_button);
                d_header_bar.pack_end(d_activities_switcher);
 
@@ -234,6 +244,12 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
                                                    typeof(int),
                                                    i);
                }
+
+               Gtk.BindingEntry.add_signal(bset,
+                                           Gdk.Key.Escape,
+                                           0,
+                                           "cancel",
+                                           0);
        }
 
        private void on_close_activated()
@@ -338,6 +354,7 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
                        d_dash_button.hide();
                        d_gear_menu.menu_model = d_dash_model;
                        d_search_button.visible = true;
+                       d_select_button.visible = true;
                }
 
                d_activities.update();
@@ -458,12 +475,18 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
        {
                notify_property("current_activity");
 
-               d_search_button.visible = (d_activities.current.supports_search);
+               d_search_button.visible = (d_activities.current is GitgExt.Searchable);
+               d_select_button.visible = (d_activities.current is GitgExt.Selectable);
 
                if (!d_search_button.visible)
                {
                        d_search_button.active = false;
                }
+
+               if (!d_select_button.visible)
+               {
+                       d_select_button.active = false;
+               }
        }
 
        private void activate_default_activity()
@@ -718,6 +741,125 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
                        }
                }
        }
+
+       private void remove_selected_repositories()
+       {
+               foreach (var sel in d_dash_view.selection)
+               {
+                       sel.request_remove();
+               }
+       }
+
+       private Gtk.Widget make_dash_select_actions()
+       {
+               var ab = new Gtk.ActionBar();
+
+               var del = new Gtk.Button.with_mnemonic(_("_Delete"));
+               del.sensitive = false;
+               del.show();
+
+               del.clicked.connect(() => {
+                       remove_selected_repositories();
+                       d_select_button.active = false;
+               });
+
+               d_dash_view.bind_property("has-selection",
+                                         del,
+                                         "sensitive");
+
+               ab.pack_end(del);
+
+               return ab;
+       }
+
+       private void on_select_activated(SimpleAction action)
+       {
+               if (d_mode != Mode.DASH && !(d_activities.current is GitgExt.Selectable))
+               {
+                       return;
+               }
+
+               var state = action.get_state().get_boolean();
+               var nstate = !state;
+
+               Gtk.Widget? select_actions = null;
+
+               if (d_mode == Mode.ACTIVITY)
+               {
+                       var selectable = d_activities.current as GitgExt.Selectable;
+
+                       if (selectable == null)
+                       {
+                               return;
+                       }
+
+                       if (nstate)
+                       {
+                               selectable.mode = GitgExt.SelectionMode.SELECT;
+                       }
+                       else
+                       {
+                               selectable.mode = GitgExt.SelectionMode.NORMAL;
+                       }
+               }
+               else
+               {
+                       d_dash_view.is_selection = nstate;
+
+                       if (nstate)
+                       {
+                               select_actions = make_dash_select_actions();
+                       }
+               }
+
+               var ctx = d_header_bar.get_style_context();
+
+               if (nstate)
+               {
+                       ctx.add_class("selection-mode");
+
+                       d_select_actions = select_actions;
+
+                       if (d_select_actions != null)
+                       {
+                               d_grid_main.attach(d_select_actions, 0, 3, 1, 1);
+                               d_select_actions.show();
+                       }
+               }
+               else
+               {
+                       ctx.remove_class("selection-mode");
+
+                       if (d_select_actions != null)
+                       {
+                               d_select_actions.destroy();
+                               d_select_actions = null;
+                       }
+               }
+
+               d_header_bar.show_close_button = !nstate;
+               d_search_button.visible = !nstate;
+               d_gear_menu.visible = !nstate;
+               d_select_button.visible = !nstate;
+               d_select_cancel_button.visible = nstate;
+
+               action.set_state(new Variant.boolean(nstate));
+       }
+
+       [GtkCallback]
+       private void on_select_cancel_button_clicked()
+       {
+               d_select_button.active = false;
+       }
+
+       [Signal(action = true)]
+       public virtual signal void cancel()
+       {
+               if (d_select_button.active)
+               {
+                       d_select_button.active = false;
+               }
+       }
 }
 
 }
diff --git a/gitg/resources/ui/gitg-window.ui b/gitg/resources/ui/gitg-window.ui
index c9eabd9..aa6348e 100644
--- a/gitg/resources/ui/gitg-window.ui
+++ b/gitg/resources/ui/gitg-window.ui
@@ -64,6 +64,27 @@
           </packing>
         </child>
         <child>
+          <object class="GtkToggleButton" id="d_select_button">
+            <property name="visible">True</property>
+            <property name="valign">center</property>
+            <property name="can_focus">False</property>
+            <property name="action_name">win.select</property>
+            <style>
+              <class name="image-button"/>
+            </style>
+            <child>
+              <object class="GtkImage" id="select_image">
+                <property name="visible">True</property>
+                <property name="icon_size">1</property>
+                <property name="icon_name">object-select-symbolic</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="pack_type">end</property>
+          </packing>
+        </child>
+        <child>
           <object class="GtkStackSwitcher" id="d_activities_switcher">
             <property name="visible">False</property>
           </object>
@@ -94,10 +115,22 @@
             <property name="pack_type">end</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkButton" id="d_select_cancel_button">
+            <property name="visible">False</property>
+            <property name="can_focus">False</property>
+            <property name="label">_Cancel</property>
+            <property name="use_underline">True</property>
+            <signal name="clicked" handler="on_select_cancel_button_clicked"/>
+          </object>
+          <packing>
+            <property name="pack_type">end</property>
+          </packing>
+        </child>
       </object>
     </child>
     <child>
-      <object class="GtkGrid" id="grid1">
+      <object class="GtkGrid" id="d_grid_main">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <child>
diff --git a/libgitg-ext/Makefile.am b/libgitg-ext/Makefile.am
index f02e5ea..6493cf0 100644
--- a/libgitg-ext/Makefile.am
+++ b/libgitg-ext/Makefile.am
@@ -58,6 +58,7 @@ libgitg_ext_libgitg_ext_1_0_la_VALASOURCES =          \
        libgitg-ext/gitg-ext-command-line.vala          \
        libgitg-ext/gitg-ext-preferences.vala           \
        libgitg-ext/gitg-ext-searchable.vala            \
+       libgitg-ext/gitg-ext-selectable.vala            \
        libgitg-ext/gitg-ext-ui.vala                    \
        libgitg-ext/gitg-ext-user-query.vala            \
        libgitg/libgitg-1.0.vapi
diff --git a/libgitg-ext/gitg-ext-selectable.vala b/libgitg-ext/gitg-ext-selectable.vala
new file mode 100644
index 0000000..ef82b99
--- /dev/null
+++ b/libgitg-ext/gitg-ext-selectable.vala
@@ -0,0 +1,43 @@
+/*
+ * This file is part of gitg
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gitg 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.
+ *
+ * gitg 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 gitg. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace GitgExt
+{
+
+public enum SelectionMode
+{
+       NORMAL,
+       SELECT
+}
+
+/**
+ * gitg Selectable interface.
+ *
+ * The Selectable interface can be implemented when an activity supports a
+ * selection mode.
+ */
+public interface Selectable : Object, Activity
+{
+       public abstract SelectionMode mode { set; }
+
+}
+
+}
+
+// ex: ts=4 noet
diff --git a/libgitg/gitg-repository-list-box.vala b/libgitg/gitg-repository-list-box.vala
index 9d18e72..824e9e1 100644
--- a/libgitg/gitg-repository-list-box.vala
+++ b/libgitg/gitg-repository-list-box.vala
@@ -25,7 +25,7 @@ namespace Gitg
                private string? d_filter_text;
 
                [GtkTemplate (ui = "/org/gnome/gitg/gtk/gitg-repository-list-box-row.ui")]
-               private class Row : Gtk.ListBoxRow
+               public class Row : Gtk.ListBoxRow
                {
                        private Repository? d_repository;
                        private DateTime d_time;
@@ -44,10 +44,49 @@ namespace Gitg
                        [GtkChild]
                        private Gtk.Spinner d_spinner;
                        [GtkChild]
-                       private Gtk.Button d_remove_button;
+                       private Gtk.CheckButton d_remove_check_button;
+                       [GtkChild]
+                       private Gtk.Revealer d_remove_revealer;
 
                        public signal void request_remove();
 
+                       private bool d_is_selection;
+
+                       public bool is_selection
+                       {
+                               get
+                               {
+                                       return d_is_selection;
+                               }
+
+                               set
+                               {
+                                       if (d_is_selection != value)
+                                       {
+                                               d_is_selection = value;
+
+                                               d_remove_revealer.reveal_child = d_is_selection;
+
+                                               d_remove_check_button.active = false;
+                                       }
+                               }
+                       }
+
+                       [Notify]
+                       public new bool is_selected
+                       {
+                               get; set;
+                       }
+
+                       construct
+                       {
+                               d_remove_check_button.bind_property("active",
+                                                                   this,
+                                                                   "is-selected",
+                                                                   BindingFlags.BIDIRECTIONAL |
+                                                                   BindingFlags.SYNC_CREATE);
+                       }
+
                        public Repository? repository
                        {
                                get { return d_repository; }
@@ -70,10 +109,8 @@ namespace Gitg
 
                        public bool can_remove
                        {
-                               set
-                               {
-                                       d_remove_button.sensitive = value;
-                               }
+                               get { return d_remove_check_button.sensitive; }
+                               set { d_remove_check_button.sensitive = value; }
                        }
 
                        public DateTime time
@@ -139,19 +176,27 @@ namespace Gitg
                        {
                                Object(repository_name: name, branch_name: branch_name, has_remote: 
has_remote);
                        }
-
-                       [GtkCallback]
-                       private void remove_button_clicked(Gtk.Button remove)
-                       {
-                               request_remove();
-                       }
                }
 
                public signal void repository_activated(Repository repository);
                public signal void show_error(string primary_message, string secondary_message);
 
+               public bool is_selection { get; set; }
+
                protected override void row_activated(Gtk.ListBoxRow row)
                {
+                       if (is_selection)
+                       {
+                               var r = row as Row;
+
+                               if (r != null && r.is_selection)
+                               {
+                                       r.is_selected = !r.is_selected;
+                               }
+
+                               return;
+                       }
+
                        var r = (Row)row;
 
                        if (r.repository != null)
@@ -294,6 +339,17 @@ namespace Gitg
 
                                if (f != null)
                                {
+                                       bind_property("is-selection",
+                                                     row,
+                                                     "is-selection");
+                               }
+
+                               if (f != null)
+                               {
+                                       row.notify["is-selected"].connect(() => {
+                                               notify_property("has-selection");
+                                       });
+
                                        row.request_remove.connect(() => {
                                                try
                                                {
@@ -326,6 +382,44 @@ namespace Gitg
                        }
                }
 
+               public Row[] selection
+               {
+                       owned get
+                       {
+                               var ret = new Row[0];
+
+                               foreach (var row in get_children())
+                               {
+                                       var r = row as Row;
+
+                                       if (r != null && r.can_remove && r.is_selected)
+                                       {
+                                               ret += r;
+                                       }
+                               }
+
+                               return ret;
+                       }
+               }
+
+               public bool has_selection
+               {
+                       get
+                       {
+                               foreach (var row in get_children())
+                               {
+                                       var r = row as Row;
+
+                                       if (r != null && r.can_remove && r.is_selected)
+                                       {
+                                               return true;
+                                       }
+                               }
+
+                               return false;
+                       }
+               }
+
                class CloneProgress : Ggit.RemoteCallbacks
                {
                        private Row d_row;
diff --git a/libgitg/resources/gitg-repository-list-box-row.ui 
b/libgitg/resources/gitg-repository-list-box-row.ui
index 751156b..c74c5e8 100644
--- a/libgitg/resources/gitg-repository-list-box-row.ui
+++ b/libgitg/resources/gitg-repository-list-box-row.ui
@@ -17,24 +17,21 @@
             <property name="margin_bottom">12</property>
             <property name="column_spacing">10</property>
             <child>
-              <object class="GtkButton" id="d_remove_button">
+              <object class="GtkRevealer" id="d_remove_revealer">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="has_focus">False</property>
-                <property name="is_focus">False</property>
+                <property name="has_focus">True</property>
                 <property name="vexpand">False</property>
                 <property name="valign">center</property>
-                <property name="relief">none</property>
-                <property name="tooltip_text" translatable="yes">Remove the repository from the list (does 
not delete the repository from disk)</property>
-                <signal name="clicked" handler="remove_button_clicked" swapped="no"/>
-                <style>
-                  <class name="image-button"/>
-                </style>
+                <property name="transition_type">slide-left</property>
                 <child>
-                  <object class="GtkImage" id="delete_image">
+                  <object class="GtkCheckButton" id="d_remove_check_button">
                     <property name="visible">True</property>
-                    <property name="pixel_size">16</property>
-                    <property name="icon_name">list-remove-symbolic</property>
+                    <property name="can_focus">True</property>
+                    <property name="has_focus">False</property>
+                    <property name="vexpand">False</property>
+                    <property name="valign">center</property>
+                    <property name="tooltip_text" translatable="yes">Remove the repository from the list 
(does not delete the repository from disk)</property>
                   </object>
                 </child>
               </object>


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