[gitg] Implement selection mode for dash view
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg] Implement selection mode for dash view
- Date: Tue, 15 Jul 2014 08:06:25 +0000 (UTC)
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]