[gitg/wip/actions] wip
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg/wip/actions] wip
- Date: Thu, 9 Jan 2014 11:15:44 +0000 (UTC)
commit f0f4eab96c88876024478c47da39f2c745785508
Author: Jesse van den Kieboom <jessevdk gmail com>
Date: Wed Jan 8 14:16:47 2014 +0100
wip
gitg/Makefile.am | 3 +-
gitg/gitg-ref-action-delete.vala | 29 +-
gitg/gitg-ref-action-rename.vala | 25 +-
gitg/gitg-window.vala | 7 +-
gitg/history/gitg-history-navigation-store.vala | 484 +++++++++++++++++
gitg/history/gitg-history-navigation-view.vala | 234 +++++++++
gitg/history/gitg-history-navigation.vala | 581 ---------------------
gitg/history/gitg-history.vala | 193 +++++++-
gitg/resources/gitg-resources.xml | 1 +
gitg/resources/ui/gitg-history-navigation-view.ui | 54 ++
libgitg-ext/gitg-ext-action.vala | 24 +-
libgitg-ext/gitg-ext-application.vala | 5 +
libgitg/gitg-ref.vala | 12 +-
13 files changed, 1043 insertions(+), 609 deletions(-)
---
diff --git a/gitg/Makefile.am b/gitg/Makefile.am
index 7311510..3839356 100644
--- a/gitg/Makefile.am
+++ b/gitg/Makefile.am
@@ -64,7 +64,8 @@ gitg_gitg_VALASOURCES = \
gitg/preferences/gitg-preferences-interface.vala \
gitg/preferences/gitg-preferences-history.vala \
gitg/history/gitg-history.vala \
- gitg/history/gitg-history-navigation.vala \
+ gitg/history/gitg-history-navigation-view.vala \
+ gitg/history/gitg-history-navigation-store.vala \
gitg/history/gitg-history-paned.vala \
gitg/commit/gitg-commit.vala \
gitg/commit/gitg-commit-paned.vala \
diff --git a/gitg/gitg-ref-action-delete.vala b/gitg/gitg-ref-action-delete.vala
index e70ae87..cbc961e 100644
--- a/gitg/gitg-ref-action-delete.vala
+++ b/gitg/gitg-ref-action-delete.vala
@@ -20,22 +20,43 @@
namespace Gitg
{
-class RefActionDelete : GitgExt.RefAction, GitgExt.Action, Object
+class RefActionDelete : GitgExt.Action, GitgExt.RefAction, Object
{
- public Ggit.Ref reference { get; construct set; }
+ // Do this to pull in config.h before glib.h (for gettext...)
+ private const string version = Gitg.Config.VERSION;
+
public GitgExt.ActionInterface action_interface { get; construct set; }
+ public Ggit.Ref reference { get; construct set; }
+
+ public RefActionDelete(GitgExt.ActionInterface action_interface, Ggit.Ref reference)
+ {
+ Object(action_interface: action_interface, reference: reference);
+ }
public string label
{
- get { return "Delete"; }
+ get { return _("Delete"); }
}
public bool enabled
{
+ get
+ {
+ var r = reference as Gitg.Ref;
+ var rtype = r.parsed_name.rtype;
+
+ return rtype == RefType.BRANCH
+ || rtype == RefType.TAG
+ || rtype == RefType.REMOTE;
+ }
+ }
+
+ public bool visible
+ {
get { return true; }
}
- public void activate()
+ public void activated()
{
}
}
diff --git a/gitg/gitg-ref-action-rename.vala b/gitg/gitg-ref-action-rename.vala
index 4362b35..a83e19c 100644
--- a/gitg/gitg-ref-action-rename.vala
+++ b/gitg/gitg-ref-action-rename.vala
@@ -20,23 +20,38 @@
namespace Gitg
{
-class RefActionRename : GitgExt.RefAction, GitgExt.Action, Object
+class RefActionRename : GitgExt.Action, GitgExt.RefAction, Object
{
- public Ggit.Ref reference { get; construct set; }
+ // Do this to pull in config.h before glib.h (for gettext...)
+ private const string version = Gitg.Config.VERSION;
+
public GitgExt.ActionInterface action_interface { get; construct set; }
+ public Ggit.Ref reference { get; construct set; }
+
+ public RefActionRename(GitgExt.ActionInterface action_interface, Ggit.Ref reference)
+ {
+ Object(action_interface: action_interface, reference: reference);
+ }
public string label
{
- get { return "Rename"; }
+ get { return _("Rename"); }
}
- public bool enabled
+ public bool visible
{
get { return true; }
}
- public void activate()
+ public bool enabled
{
+ get
+ {
+ var r = reference as Gitg.Ref;
+ var rtype = r.parsed_name.rtype;
+
+ return rtype == RefType.BRANCH || rtype == RefType.TAG;
+ }
}
}
diff --git a/gitg/gitg-window.vala b/gitg/gitg-window.vala
index eedb457..0a19121 100644
--- a/gitg/gitg-window.vala
+++ b/gitg/gitg-window.vala
@@ -21,7 +21,7 @@ namespace Gitg
{
[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-window.ui")]
-public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
+public class Window : Gtk.ApplicationWindow, GitgExt.Application, GitgExt.ActionInterface, Initable
{
private Settings d_state_settings;
private Settings d_interface_settings;
@@ -566,6 +566,11 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
{
owned get { return d_environment; }
}
+
+ public GitgExt.ActionInterface action_interface
+ {
+ owned get { return this; }
+ }
}
}
diff --git a/gitg/history/gitg-history-navigation-store.vala b/gitg/history/gitg-history-navigation-store.vala
new file mode 100644
index 0000000..0fa2e28
--- /dev/null
+++ b/gitg/history/gitg-history-navigation-store.vala
@@ -0,0 +1,484 @@
+/*
+ * 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 GitgHistory
+{
+ [Flags]
+ private enum Hint
+ {
+ NONE = 0,
+ DEFAULT = 1 << 0,
+ SEPARATOR = 1 << 1,
+ HEADER_BRANCHES = 1 << 2,
+ HEADER_REMOTES = 1 << 3,
+ HEADER_REMOTE = 1 << 4,
+ HEADER_TAGS = 1 << 5,
+ HEADER = HEADER_BRANCHES
+ | HEADER_REMOTES
+ | HEADER_REMOTE
+ | HEADER_TAGS
+ }
+
+ private enum Column
+ {
+ ICON_NAME,
+ NAME,
+ TEXT,
+ HINT,
+ REF,
+ BUSY
+ }
+
+ public class NavigationStore : Gtk.TreeStore
+ {
+ // Do this to pull in config.h before glib.h (for gettext...)
+ private const string version = Gitg.Config.VERSION;
+
+ private List<Gitg.Ref> d_all;
+ private Gitg.Repository? d_repository;
+
+ public NavigationStore(Gitg.Repository? repo)
+ {
+ Object(repository: repo);
+ }
+
+ construct
+ {
+ set_column_types({typeof(string),
+ typeof(string),
+ typeof(string),
+ typeof(uint),
+ typeof(uint),
+ typeof(Gitg.Ref),
+ typeof(uint)
+ });
+ }
+
+ public List<Gitg.Ref> all
+ {
+ get { return d_all; }
+ }
+
+ [Notify]
+ public Gitg.Repository repository
+ {
+ get { return d_repository; }
+ set
+ {
+ d_repository = value;
+ reload();
+ }
+ }
+
+ public bool show_expanders
+ {
+ get { return false; }
+ }
+
+ private static int sort_refs(Gitg.Ref a, Gitg.Ref b)
+ {
+ return a.parsed_name.shortname.ascii_casecmp(b.parsed_name.shortname);
+ }
+
+ private static int sort_remote_refs(Gitg.Ref a, Gitg.Ref b)
+ {
+ return a.parsed_name.remote_branch.ascii_casecmp(b.parsed_name.remote_branch);
+ }
+
+ private bool find_header(out Gtk.TreeIter iter, Hint header_type)
+ {
+ header_type &= Hint.HEADER;
+
+ if (!get_iter_first(out iter))
+ {
+ return false;
+ }
+
+ while (true)
+ {
+ Hint hint = Hint.NONE;
+
+ @get(iter, Column.HINT, out hint);
+
+ if ((hint & header_type) != 0)
+ {
+ return true;
+ }
+
+ if (!iter_next(ref iter))
+ {
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ private bool find_parent_iter(out Gtk.TreeIter iter, Gitg.Ref reference)
+ {
+ Hint header_type = Hint.NONE;
+
+ switch (reference.parsed_name.rtype)
+ {
+ case Gitg.RefType.BRANCH:
+ header_type = Hint.HEADER_BRANCHES;
+ break;
+ case Gitg.RefType.TAG:
+ header_type = Hint.HEADER_TAGS;
+ break;
+ case Gitg.RefType.REMOTE:
+ header_type = Hint.HEADER_REMOTES;
+ break;
+ default:
+ iter = Gtk.TreeIter();
+ return false;
+ }
+
+ return find_header(out iter, header_type);
+ }
+
+ private bool find_insert_before(out Gtk.TreeIter iter,
+ Gtk.TreeIter parent,
+ string text)
+ {
+ if (!iter_children(out iter, parent))
+ {
+ return false;
+ }
+
+ while (true)
+ {
+ string cmptext;
+ @get(iter, Column.TEXT, out cmptext);
+
+ if (text < cmptext)
+ {
+ return true;
+ }
+
+ if (!iter_next(ref iter))
+ {
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ private void add_ref_internal(Gtk.TreeIter? parent,
+ Gitg.Ref reference,
+ bool append)
+ {
+ var pn = reference.parsed_name;
+ string text;
+ string name = pn.name;
+ string? icon_name = null;
+ Hint hint = Hint.NONE;
+
+ if (pn.rtype == Gitg.RefType.REMOTE)
+ {
+ text = pn.remote_branch;
+ }
+ else
+ {
+ text = pn.shortname;
+ }
+
+ var branch = reference as Ggit.Branch;
+
+ if (branch != null)
+ {
+ try
+ {
+ if (branch.is_head())
+ {
+ icon_name = "object-select-symbolic";
+ hint |= Hint.DEFAULT;
+ }
+ } catch {}
+ }
+
+ Gtk.TreeIter? par = null;
+
+ if (parent == null)
+ {
+ find_parent_iter(out par, reference);
+ }
+ else
+ {
+ par = parent;
+ }
+
+ Gtk.TreeIter iter;
+ Gtk.TreeIter before = Gtk.TreeIter();
+
+ if (append || !find_insert_before(out before, par, text))
+ {
+ base.append(out iter, par);
+ }
+ else
+ {
+ base.insert_before(out iter, par, before);
+ }
+
+ @set(iter,
+ Column.ICON_NAME, icon_name,
+ Column.NAME, name,
+ Column.TEXT, text,
+ Column.HINT, hint,
+ Column.REF, reference);
+ }
+
+ private void append_ref(Gtk.TreeIter? parent, Gitg.Ref reference)
+ {
+ add_ref_internal(parent, reference, true);
+ }
+
+ private void insert_ref(Gtk.TreeIter? parent, Gitg.Ref reference)
+ {
+ add_ref_internal(parent, reference, false);
+ }
+
+ private void make_header(out Gtk.TreeIter iter,
+ Gtk.TreeIter? parent,
+ string text,
+ Hint hint)
+ {
+ base.append(out iter, parent);
+
+ @set(iter,
+ Column.TEXT, text,
+ Column.HINT, hint);
+ }
+
+ private void populate(Gitg.Repository repo)
+ {
+ List<Gitg.Ref> branches = new List<Gitg.Ref>();
+ List<Gitg.Ref> tags = new List<Gitg.Ref>();
+
+ HashTable<string, Gee.LinkedList<Gitg.Ref>> remotes;
+ List<string> remotenames = new List<string>();
+
+ remotes = new HashTable<string, Gee.LinkedList<Gitg.Ref>>(str_hash, str_equal);
+ d_all = new List<Gitg.Ref>();
+
+ try
+ {
+ repo.references_foreach_name((nm) => {
+ Gitg.Ref? r;
+
+ try
+ {
+ r = repo.lookup_reference(nm);
+ } catch { return 0; }
+
+ d_all.prepend(r);
+
+ if (r.parsed_name.rtype == Gitg.RefType.BRANCH)
+ {
+ branches.insert_sorted(r, sort_refs);
+ }
+ else if (r.parsed_name.rtype == Gitg.RefType.TAG)
+ {
+ tags.insert_sorted(r, sort_refs);
+ }
+ else if (r.parsed_name.rtype == Gitg.RefType.REMOTE)
+ {
+ Gee.LinkedList<Gitg.Ref> lst;
+
+ string rname = r.parsed_name.remote_name;
+
+ if (!remotes.lookup_extended(rname, null, out lst))
+ {
+ Gee.LinkedList<Gitg.Ref> nlst = new
Gee.LinkedList<Gitg.Ref>();
+ nlst.insert(0, r);
+
+ remotes.insert(rname, nlst);
+ remotenames.insert_sorted(rname, (a, b) =>
a.ascii_casecmp(b));
+ }
+ else
+ {
+ lst.insert(0, r);
+ }
+ }
+
+ return 0;
+ });
+
+ if (repo.is_head_detached())
+ {
+ d_all.prepend(repo.get_head());
+ }
+ } catch {}
+
+ d_all.reverse();
+
+ //append_normal(_("All commits"), null, null, null, (nc) => activate_ref(null));
+ Gtk.TreeIter ibranches;
+ make_header(out ibranches, null, _("Branches"), Hint.HEADER_BRANCHES);
+
+ foreach (var item in branches)
+ {
+ append_ref(ibranches, item);
+ }
+
+ // Remotes
+ Gtk.TreeIter iremotes;
+ make_header(out iremotes, null, _("Remotes"), Hint.HEADER_REMOTES);
+
+ foreach (var rname in remotenames)
+ {
+ Gtk.TreeIter iremote;
+ make_header(out iremote, iremotes, rname, Hint.HEADER_REMOTE);
+
+ var rrefs = remotes.lookup(rname);
+
+ rrefs.sort((CompareDataFunc)sort_remote_refs);
+
+ foreach (var rref in remotes.lookup(rname))
+ {
+ append_ref(iremote, rref);
+ }
+ }
+
+ // Tags
+ Gtk.TreeIter itags;
+ make_header(out itags, null, _("Tags"), Hint.HEADER_TAGS);
+
+ foreach (var item in tags)
+ {
+ append_ref(itags, item);
+ }
+ }
+
+ public void reload()
+ {
+ if (d_repository != null)
+ {
+ clear();
+ populate(d_repository);
+ }
+ }
+
+ public bool remove_ref(Gitg.Ref reference)
+ {
+ Gtk.TreeIter iter;
+
+ if (get_iter_for_ref(out iter, reference))
+ {
+ if (remove(ref iter))
+ {
+ d_all.remove(reference);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public bool add_ref(Gitg.Ref reference)
+ {
+ insert_ref(null, reference);
+ d_all.append(reference);
+
+ return true;
+ }
+
+ public Gtk.TreePath? get_path_for_ref(Gitg.Ref reference)
+ {
+ return get_for_ref(null, reference);
+ }
+
+ public bool get_iter_for_ref(out Gtk.TreeIter iter, Gitg.Ref? reference)
+ {
+ return get_for_ref(out iter, reference) != null;
+ }
+
+ private Gtk.TreePath? get_for_ref(out Gtk.TreeIter iter, Gitg.Ref? reference)
+ {
+ Gtk.TreePath? ret = null;
+ Gtk.TreeIter liter = Gtk.TreeIter();
+
+ @foreach((model, path, i) => {
+ Gitg.Ref? obj = null;
+
+ @get(i, Column.REF, out obj);
+
+ if (obj == reference)
+ {
+ liter = i;
+ ret = path;
+
+ return true;
+ }
+
+ return false;
+ });
+
+ iter = liter;
+ return ret;
+ }
+
+ public void set_busy(Gitg.Ref reference, bool isbusy)
+ {
+ Gtk.TreeIter iter;
+
+ if (!get_iter_for_ref(out iter, reference))
+ {
+ return;
+ }
+
+ if (!isbusy)
+ {
+ @set(iter, Column.BUSY, 0);
+ return;
+ }
+
+ uint busy_now;
+ @get(iter, Column.BUSY, out busy_now);
+
+ if (busy_now != 0)
+ {
+ return;
+ }
+
+ @set(iter, Column.BUSY, 1);
+
+ Timeout.add(50, () => {
+ uint busy = 0;
+ @get(iter, Column.BUSY, out busy);
+
+ if (busy == 0)
+ {
+ return false;
+ }
+
+ if (busy == uint.MAX)
+ {
+ busy = 0;
+ }
+
+ @set(iter, Column.BUSY, busy + 1);
+ return true;
+ });
+ }
+ }
+}
+
+// ex: ts=4 noet
diff --git a/gitg/history/gitg-history-navigation-view.vala b/gitg/history/gitg-history-navigation-view.vala
new file mode 100644
index 0000000..0722175
--- /dev/null
+++ b/gitg/history/gitg-history-navigation-view.vala
@@ -0,0 +1,234 @@
+/*
+ * This file is part of gitg
+ *
+ * Copyright (C) 2012 - 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 GitgHistory
+{
+
+[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-history-navigation-view.ui")]
+public class NavigationView : Gtk.TreeView
+{
+ [GtkChild]
+ private Gtk.TreeViewColumn d_column;
+
+ [GtkChild]
+ private Gtk.CellRendererPixbuf d_renderer_icon;
+
+ [GtkChild]
+ private Gtk.CellRendererSpinner d_renderer_spinner;
+
+ [GtkChild]
+ private Gtk.CellRendererText d_renderer_text;
+
+ public signal void edited(Gitg.Ref reference, Gtk.TreePath path, string text);
+ public signal void ref_activated(Gitg.Ref? r);
+
+ construct
+ {
+ finish_ui();
+ }
+
+ private void finish_ui()
+ {
+ d_column.set_attributes(d_renderer_icon, "icon-name", Column.ICON_NAME);
+ d_column.set_attributes(d_renderer_text, "text", Column.TEXT);
+
+ d_column.set_cell_data_func(d_renderer_icon, (layout, cell, model, iter) => {
+ string? icon_name;
+ uint busy;
+
+ model.get(iter,
+ Column.ICON_NAME, out icon_name,
+ Column.BUSY, out busy);
+
+ cell.visible = (icon_name != null) && busy == 0;
+ });
+
+ d_column.set_cell_data_func(d_renderer_spinner, (layout, cell, model, iter) => {
+ uint busy;
+
+ model.get(iter, Column.BUSY, out busy);
+
+ var isbusy = busy > 0;
+
+ d_renderer_spinner.visible = isbusy;
+ d_renderer_spinner.active = isbusy;
+ d_renderer_spinner.pulse = busy;
+ });
+
+ d_column.set_cell_data_func(d_renderer_text, (layout, cell, model, iter) => {
+ Hint hint;
+ model.get(iter, Column.HINT, out hint);
+
+ if ((hint & Hint.HEADER) != 0)
+ {
+ d_renderer_text.ypad = 6;
+ d_renderer_text.weight = Pango.Weight.BOLD;
+ }
+ else
+ {
+ d_renderer_text.ypad = 0;
+ d_renderer_text.weight = Pango.Weight.NORMAL;
+ }
+ });
+
+ set_row_separator_func((model, iter) => {
+ Hint hint;
+ model.get(iter, Column.HINT, out hint);
+
+ return hint == Hint.SEPARATOR;
+ });
+
+ var selection = get_selection();
+
+ selection.set_select_function((sel, model, path, cursel) => {
+ Gtk.TreeIter iter;
+ model.get_iter(out iter, path);
+
+ uint hint;
+
+ model.get(iter, Column.HINT, out hint);
+
+ return (hint & Hint.HEADER) == 0;
+ });
+ }
+
+ public new NavigationStore model
+ {
+ get { return base.get_model() as NavigationStore; }
+ set { base.set_model(value); }
+ }
+
+ [GtkCallback]
+ private void on_renderer_text_edited(string path, string new_text)
+ {
+ Gtk.TreePath p = new Gtk.TreePath.from_string(path);
+ Gtk.TreeIter iter;
+
+ model.get_iter(out iter, p);
+
+ Gitg.Ref? ret = null;
+ model.get(iter, Column.REF, ref ret);
+
+ edited(ret, p, new_text);
+ }
+
+ private bool select_first_in(Gtk.TreeIter? parent, bool seldef)
+ {
+ Gtk.TreeIter iter;
+
+ if (!model.iter_children(out iter, parent))
+ {
+ return false;
+ }
+
+ while (true)
+ {
+ uint hint;
+ model.get(iter, Column.HINT, out hint);
+
+ if ((hint & Hint.HEADER) != 0)
+ {
+ if (select_first_in(iter, seldef))
+ {
+ return true;
+ }
+ }
+
+ if (!seldef || hint == Hint.DEFAULT)
+ {
+ get_selection().select_iter(iter);
+ return true;
+ }
+
+ if (!model.iter_next(ref iter))
+ {
+ return false;
+ }
+ }
+ }
+
+ public void select_first()
+ {
+ select_first_in(null, true) || select_first_in(null, false);
+ }
+
+ public void select()
+ {
+// if (model.selected_iter != null)
+// {
+// get_selection().select_iter(model.selected_iter);
+// model.selected_iter = null;
+// }
+// else
+// {
+ select_first();
+// }
+ }
+
+ public Gitg.Ref? selected_ref
+ {
+ owned get
+ {
+ Gtk.TreeModel model;
+ Gtk.TreeIter iter;
+
+ if (!get_selection().get_selected(out model, out iter))
+ {
+ return null;
+ }
+
+ Gitg.Ref? ret = null;
+ model.get(iter, Column.REF, out ret);
+
+ return ret;
+ }
+ }
+
+ public void edit(Gitg.Ref reference)
+ {
+ var path = model.get_path_for_ref(reference);
+
+ if (path != null)
+ {
+ set_cursor_on_cell(path, d_column, d_renderer_text, true);
+ }
+ }
+
+ protected override void row_activated(Gtk.TreePath path, Gtk.TreeViewColumn col)
+ {
+ Gtk.TreeIter iter;
+
+ if (!model.get_iter(out iter, path))
+ {
+ return;
+ }
+
+ Gitg.Ref? reference = null;
+ model.get(iter, Column.REF, out reference);
+
+ if (reference != null)
+ {
+ ref_activated(reference);
+ }
+ }
+}
+
+}
+
+// ex: ts=4 noet
diff --git a/gitg/history/gitg-history.vala b/gitg/history/gitg-history.vala
index 57bf6b8..59efb69 100644
--- a/gitg/history/gitg-history.vala
+++ b/gitg/history/gitg-history.vala
@@ -29,7 +29,7 @@ namespace GitgHistory
public GitgExt.Application? application { owned get; construct set; }
- private Navigation? d_navigation_model;
+ private NavigationStore? d_navigation_store;
private Gitg.CommitModel? d_commit_list_model;
private Gee.HashSet<Ggit.OId> d_selected;
private ulong d_insertsig;
@@ -88,10 +88,7 @@ namespace GitgHistory
d_selected = new Gee.HashSet<Ggit.OId>((Gee.HashDataFunc<Ggit.OId>)Ggit.OId.hash,
(Gee.EqualDataFunc<Ggit.OId>)Ggit.OId.equal);
- d_navigation_model = new Navigation(application.repository);
- d_navigation_model.ref_activated.connect((r) => {
- on_ref_activated(d_navigation_model, r);
- });
+ d_navigation_store = new NavigationStore(application.repository);
d_commit_list_model = new Gitg.CommitModel(application.repository);
d_commit_list_model.started.connect(on_commit_model_started);
@@ -99,7 +96,7 @@ namespace GitgHistory
update_sort_mode();
- application.bind_property("repository", d_navigation_model,
+ application.bind_property("repository", d_navigation_store,
"repository", BindingFlags.DEFAULT);
application.bind_property("repository", d_commit_list_model,
@@ -197,11 +194,6 @@ namespace GitgHistory
return -1;
}
- private void on_ref_activated(Navigation n, Gitg.Ref? r)
- {
- update_walker(n, r);
- }
-
public void activate()
{
d_main.navigation_view.expand_all();
@@ -212,7 +204,7 @@ namespace GitgHistory
{
double vadj = d_main.navigation_view.get_vadjustment().get_value();
- d_navigation_model.reload();
+ d_navigation_store.reload();
d_main.navigation_view.expand_all();
d_main.navigation_view.select();
@@ -225,7 +217,7 @@ namespace GitgHistory
{
d_main = new Paned();
- d_main.navigation_view.model = d_navigation_model;
+ d_main.navigation_view.model = d_navigation_store;
d_main.commit_list_view.model = d_commit_list_model;
d_main.commit_list_view.get_selection().changed.connect((sel) => {
@@ -243,9 +235,180 @@ namespace GitgHistory
d_panels = new Gitg.UIElements<GitgExt.HistoryPanel>(extset,
d_main.stack_panel);
+
+ d_main.navigation_view.popup_menu.connect(on_navigation_popup_menu);
+ d_main.navigation_view.button_press_event.connect(on_navigation_button_press_event);
+
+ d_main.navigation_view.edited.connect(on_ref_edited);
+
+ d_main.navigation_view.ref_activated.connect((r) => {
+ update_walker(r);
+ });
+ }
+
+ private void on_ref_edited(Gitg.Ref reference, Gtk.TreePath path, string newname)
+ {
+ string orig;
+ string? prefix;
+
+ var pn = reference.parsed_name;
+
+ if (pn.rtype == Gitg.RefType.REMOTE)
+ {
+ orig = pn.remote_branch;
+ prefix = pn.prefix + "/" + pn.remote_name;
+ }
+ else
+ {
+ orig = pn.shortname;
+ prefix = pn.prefix;
+ }
+
+ if (orig == newname)
+ {
+ return;
+ }
+
+ if (!Ggit.Ref.is_valid_name(@"$prefix/$newname"))
+ {
+ var msg = _("The specified name ā%sā contains invalid
characters").printf(newname);
+
+ application.show_infobar(_("Invalid name"),
+ msg,
+ Gtk.MessageType.ERROR);
+
+ return;
+ }
+
+ var branch = reference as Ggit.Branch;
+ Gitg.Ref? new_ref = null;
+
+ try
+ {
+ if (branch != null)
+ {
+ new_ref = branch.move(newname, Ggit.CreateFlags.NONE) as Gitg.Ref;
+ }
+ else
+ {
+ new_ref = reference.rename(newname, false) as Gitg.Ref;
+ }
+ }
+ catch (Error e)
+ {
+ application.show_infobar(_("Failed to rename"),
+ e.message,
+ Gtk.MessageType.ERROR);
+
+ return;
+ }
+
+ d_navigation_store.remove_ref(reference);
+ d_navigation_store.add_ref(new_ref);
+ }
+
+ private void add_ref_action(Gee.LinkedList<GitgExt.RefAction> actions, GitgExt.RefAction?
action)
+ {
+ if (action.visible)
+ {
+ actions.add(action);
+ }
+ }
+
+ private bool navigation_popup_menu(Gtk.Widget widget, Gdk.EventButton? event)
+ {
+ var button = (event == null ? 0 : event.button);
+ var time = (event == null ? Gtk.get_current_event_time() : event.time);
+
+ var actions = new Gee.LinkedList<GitgExt.RefAction>();
+ var reference = d_main.navigation_view.selected_ref;
+
+ if (reference == null)
+ {
+ return false;
+ }
+
+ var rename = new Gitg.RefActionRename(application.action_interface,
+ reference);
+
+ rename.activated.connect(() => { on_rename_activated(rename); });
+
+ add_ref_action(actions, rename);
+
+ add_ref_action(actions,
+ new Gitg.RefActionDelete(application.action_interface,
+ reference));
+
+ var exts = new Peas.ExtensionSet(Gitg.PluginsEngine.get_default(),
+ typeof(GitgExt.RefAction),
+ "action_interface",
+ application.action_interface,
+ "reference",
+ reference);
+
+ exts.foreach((extset, info, extension) => {
+ add_ref_action(actions, extension as GitgExt.RefAction);
+ });
+
+ if (actions.is_empty)
+ {
+ return false;
+ }
+
+ Gtk.Menu menu = new Gtk.Menu();
+
+ foreach (var ac in actions)
+ {
+ ac.populate_menu(menu);
+ }
+
+ menu.attach_to_widget(widget, null);
+ menu.popup(null, null, null, button, time);
+
+ return true;
+ }
+
+ private void on_rename_activated(Gitg.RefActionRename action)
+ {
+ d_main.navigation_view.edit(action.reference as Gitg.Ref);
+ }
+
+ private bool on_navigation_popup_menu(Gtk.Widget widget)
+ {
+ return navigation_popup_menu(widget, null);
+ }
+
+ private bool on_navigation_button_press_event(Gtk.Widget widget, Gdk.EventButton event)
+ {
+ Gdk.Event *ev = (Gdk.Event *)(&event);
+
+ if (!ev->triggers_context_menu())
+ {
+ return false;
+ }
+
+ Gtk.TreePath path;
+
+ if (d_main.navigation_view.get_path_at_pos((int)event.x,
+ (int)event.y,
+ out path,
+ null,
+ null,
+ null))
+ {
+ var sel = d_main.navigation_view.get_selection();
+
+ if (!sel.path_is_selected(path))
+ {
+ sel.unselect_all();
+ sel.select_path(path);
+ }
+ }
+
+ return navigation_popup_menu(widget, event);
}
- private void update_walker(Navigation n, Gitg.Ref? head)
+ private void update_walker(Gitg.Ref? head)
{
Ggit.OId? id = null;
@@ -277,7 +440,7 @@ namespace GitgHistory
var included = new Ggit.OId[] {};
// Simply push all the refs
- foreach (Gitg.Ref r in n.all)
+ foreach (Gitg.Ref r in d_navigation_store.all)
{
try
{
diff --git a/gitg/resources/gitg-resources.xml b/gitg/resources/gitg-resources.xml
index 6c4b21c..87d2112 100644
--- a/gitg/resources/gitg-resources.xml
+++ b/gitg/resources/gitg-resources.xml
@@ -11,6 +11,7 @@
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-clone-dialog.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-author-details-dialog.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-history-paned.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks">ui/gitg-history-navigation-view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-commit-paned.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-commit-dialog.ui</file>
<file compressed="true">ui/style.css</file>
diff --git a/gitg/resources/ui/gitg-history-navigation-view.ui
b/gitg/resources/ui/gitg-history-navigation-view.ui
new file mode 100644
index 0000000..3f9cc59
--- /dev/null
+++ b/gitg/resources/ui/gitg-history-navigation-view.ui
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.3 -->
+ <!-- interface-requires gitg 0.0 -->
+ <!-- interface-requires gd 1.0 -->
+ <template class="GitgHistoryNavigationView" parent="Gtk.TreeView">
+ <property name="visible">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="can_focus">True</property>
+ <property name="activate_on_single_click">True</property>
+ <property name="show_expanders">False</property>
+ <property name="level_indentation">12</property>
+ <child>
+ <object class="GtkTreeViewColumn" id="d_column">
+ <child>
+ <object class="GtkCellRendererText" id="d_renderer_pad">
+ <property name="xpad">6</property>
+ </object>
+ <cell-packing>
+ <property name="expand">False</property>
+ </cell-packing>
+ </child>
+ <child>
+ <object class="GtkCellRendererPixbuf" id="d_renderer_icon">
+ <property name="follow_state">True</property>
+ </object>
+ <cell-packing>
+ <property name="expand">False</property>
+ </cell-packing>
+ </child>
+ <child>
+ <object class="GtkCellRendererSpinner" id="d_renderer_spinner">
+ </object>
+ <cell-packing>
+ <property name="expand">False</property>
+ </cell-packing>
+ </child>
+ <child>
+ <object class="GtkCellRendererText" id="d_renderer_text">
+ <property name="editable">True</property>
+ <property name="ellipsize">middle</property>
+ <signal name="edited" handler="on_renderer_text_edited"/>
+ </object>
+ <cell-packing>
+ <property name="expand">True</property>
+ </cell-packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
+
+<!-- ex:set ts=2 et: -->
diff --git a/libgitg-ext/gitg-ext-action.vala b/libgitg-ext/gitg-ext-action.vala
index a1dcc27..d89a1a9 100644
--- a/libgitg-ext/gitg-ext-action.vala
+++ b/libgitg-ext/gitg-ext-action.vala
@@ -26,8 +26,30 @@ public interface Action : Object
public abstract string label { get; }
public abstract bool enabled { get; }
+ public abstract bool visible { get; }
- public abstract void activate();
+ public virtual signal void activated()
+ {
+ }
+
+ public virtual void populate_menu(Gtk.Menu menu)
+ {
+ var item = new Gtk.MenuItem.with_label(label);
+
+ if (enabled)
+ {
+ item.activate.connect(() => {
+ activated();
+ });
+ }
+ else
+ {
+ item.sensitive = false;
+ }
+
+ item.show();
+ menu.append(item);
+ }
}
}
diff --git a/libgitg-ext/gitg-ext-application.vala b/libgitg-ext/gitg-ext-application.vala
index cffeb12..e22f5d6 100644
--- a/libgitg-ext/gitg-ext-application.vala
+++ b/libgitg-ext/gitg-ext-application.vala
@@ -46,6 +46,11 @@ public interface Application : Object
public abstract GitgExt.Activity? current_activity { owned get; }
/**
+ * The application action interface.
+ */
+ public abstract GitgExt.ActionInterface action_interface { owned get; }
+
+ /**
* Set the current application main activity.
*
* @param id the id of the activity { link UIElement.id}.
diff --git a/libgitg/gitg-ref.vala b/libgitg/gitg-ref.vala
index 387348e..1cd8ede 100644
--- a/libgitg/gitg-ref.vala
+++ b/libgitg/gitg-ref.vala
@@ -48,6 +48,7 @@ public class ParsedRefName : Object
private string d_name;
private string d_remote_name;
private string d_remote_branch;
+ private string? d_prefix;
/**
* The type of ref.
@@ -92,6 +93,11 @@ public class ParsedRefName : Object
parse_name(name);
}
+ public string? prefix
+ {
+ get { return d_prefix; }
+ }
+
private void parse_name(string name)
{
d_name = name;
@@ -104,6 +110,7 @@ public class ParsedRefName : Object
};
d_shortname = name;
+ d_prefix = null;
for (var i = 0; i < prefixes.length; ++i)
{
@@ -112,15 +119,18 @@ public class ParsedRefName : Object
continue;
}
+ d_prefix = prefixes[i];
+
rtype = (RefType)(i + 1);
if (rtype == RefType.STASH)
{
+ d_prefix = "refs/";
d_shortname = "stash";
}
else
{
- d_shortname = d_name[prefixes[i].length:d_name.length];
+ d_shortname = d_name[d_prefix.length:d_name.length];
}
if (rtype == RefType.REMOTE)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]