[gitg/wip/actions: 8/26] Improve selection and implemented editing
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg/wip/actions: 8/26] Improve selection and implemented editing
- Date: Sat, 12 Jul 2014 08:56:13 +0000 (UTC)
commit 588d016464fd792cde13d2796ef78bbec8771bba
Author: Jesse van den Kieboom <jessevdk gmail com>
Date: Sat Jan 18 13:28:23 2014 +0100
Improve selection and implemented editing
gitg/commit/gitg-commit.vala | 56 +-----
gitg/history/gitg-history-refs-list.vala | 338 +++++++++++++++++++++++++++---
gitg/history/gitg-history.vala | 228 ++++++++++++++++-----
gitg/resources/ui/style.css | 9 +
libgitg/gitg-ref.vala | 12 +-
libgitg/gitg-repository.vala | 57 +++++
6 files changed, 569 insertions(+), 131 deletions(-)
---
diff --git a/gitg/commit/gitg-commit.vala b/gitg/commit/gitg-commit.vala
index 324b92e..0cb990a 100644
--- a/gitg/commit/gitg-commit.vala
+++ b/gitg/commit/gitg-commit.vala
@@ -661,61 +661,7 @@ namespace GitgCommit
private Ggit.Signature get_signature(string envname) throws Error
{
- string? user = null;
- string? email = null;
- DateTime? date = null;
-
- var env = application.environment;
-
- var nameenv = @"GIT_$(envname)_NAME";
- var emailenv = @"GIT_$(envname)_EMAIL";
- var dateenv = @"GIT_$(envname)_DATE";
-
- if (env.has_key(nameenv))
- {
- user = env[nameenv];
- }
-
- if (env.has_key(emailenv))
- {
- email = env[emailenv];
- }
-
- if (env.has_key(dateenv))
- {
- try
- {
- date = Gitg.Date.parse(env[dateenv]);
- }
- catch {}
- }
-
- if (date == null)
- {
- date = new DateTime.now_local();
- }
-
- var conf = application.repository.get_config();
-
- if (user == null)
- {
- try
- {
- user = conf.get_string("user.name");
- } catch {}
- }
-
- if (email == null)
- {
- try
- {
- email = conf.get_string("user.email");
- } catch {}
- }
-
- return new Ggit.Signature(user != null ? user : "",
- email != null ? email : "",
- date);
+ return application.repository.get_signature_with_environment(application.environment,
envname);
}
private void on_commit_clicked()
diff --git a/gitg/history/gitg-history-refs-list.vala b/gitg/history/gitg-history-refs-list.vala
index 95c2e11..4c953b3 100644
--- a/gitg/history/gitg-history-refs-list.vala
+++ b/gitg/history/gitg-history-refs-list.vala
@@ -55,6 +55,10 @@ private class RefRow : RefTyped, Gtk.Box
public Gitg.Ref? reference { get; set; }
+ private Gtk.Entry? d_editing_entry;
+ private uint d_idle_finish;
+ public signal void editing_done(string new_text, bool cancelled);
+
public Gitg.RefType ref_type
{
get { return reference != null ? reference.parsed_name.rtype : Gitg.RefType.NONE; }
@@ -178,6 +182,89 @@ private class RefRow : RefTyped, Gtk.Box
return t1.casefold().collate(t2.casefold());
}
+
+ public void begin_editing()
+ {
+ if (d_editing_entry != null)
+ {
+ return;
+ }
+
+ d_editing_entry = new Gtk.Entry();
+ d_editing_entry.set_width_chars(1);
+ d_editing_entry.get_style_context().add_class("ref_editing_entry");
+ d_editing_entry.show();
+
+ d_editing_entry.set_text(label_text());
+
+ d_label.hide();
+ pack_start(d_editing_entry);
+
+ d_editing_entry.grab_focus();
+ d_editing_entry.select_region(0, -1);
+
+ d_editing_entry.focus_out_event.connect(on_editing_focus_out);
+ d_editing_entry.key_press_event.connect(on_editing_key_press);
+ }
+
+ public override void dispose()
+ {
+ if (d_idle_finish != 0)
+ {
+ Source.remove(d_idle_finish);
+ d_idle_finish = 0;
+ }
+
+ base.dispose();
+ }
+
+ private void finish_editing(bool cancelled)
+ {
+ if (d_idle_finish != 0)
+ {
+ return;
+ }
+
+ d_editing_entry.focus_out_event.disconnect(on_editing_focus_out);
+ d_editing_entry.key_press_event.disconnect(on_editing_key_press);
+
+ d_idle_finish = Idle.add(() => {
+ d_idle_finish = 0;
+
+ var new_text = d_editing_entry.text;
+
+ d_editing_entry.destroy();
+ d_editing_entry = null;
+
+ d_label.show();
+
+ editing_done(new_text, cancelled);
+ return false;
+ });
+ }
+
+ private bool on_editing_focus_out(Gtk.Widget widget, Gdk.EventFocus event)
+ {
+ finish_editing(false);
+ return false;
+ }
+
+ private bool on_editing_key_press(Gtk.Widget widget, Gdk.EventKey event)
+ {
+ if (event.keyval == Gdk.Key.Escape)
+ {
+ finish_editing(true);
+ return true;
+ }
+ else if (event.keyval == Gdk.Key.KP_Enter ||
+ event.keyval == Gdk.Key.Return)
+ {
+ finish_editing(false);
+ return true;
+ }
+
+ return false;
+ }
}
private class RefHeader : RefTyped, Gtk.Label
@@ -213,6 +300,11 @@ private class RefHeader : RefTyped, Gtk.Label
margin_left += 12;
}
+ public bool is_sub_header_remote
+ {
+ get { return d_is_sub_header_remote; }
+ }
+
public int compare_to(RefHeader other)
{
// Both are headers of remote type
@@ -227,11 +319,24 @@ private class RefHeader : RefTyped, Gtk.Label
public class RefsList : Gtk.ListBox
{
- public signal void edited(Gitg.Ref reference, Gtk.TreePath path, string text);
- public signal void ref_activated(Gitg.Ref? r);
-
private Gitg.Repository? d_repository;
- private Gee.HashMap<string, RefHeader> d_remote_headers;
+ private Gee.HashMap<Gitg.Ref, RefRow> d_ref_map;
+
+ public signal void editing_done(Gitg.Ref reference, string new_text, bool cancelled);
+
+ private class RemoteHeader
+ {
+ public RefHeader header;
+ public Gee.HashSet<Gitg.Ref> references;
+
+ public RemoteHeader(RefHeader h)
+ {
+ header = h;
+ references = new Gee.HashSet<Gitg.Ref>();
+ }
+ }
+
+ private Gee.HashMap<string, RemoteHeader> d_header_map;
public Gitg.Repository? repository
{
@@ -249,7 +354,12 @@ public class RefsList : Gtk.ListBox
construct
{
- d_remote_headers = new Gee.HashMap<string, RefHeader>();
+ d_header_map = new Gee.HashMap<string, RemoteHeader>();
+ d_ref_map = new Gee.HashMap<Gitg.Ref, RefRow>();
+ selection_mode = Gtk.SelectionMode.BROWSE;
+
+ row_selected.connect(on_row_selected);
+
set_sort_func(sort_rows);
}
@@ -293,7 +403,8 @@ public class RefsList : Gtk.ListBox
private void clear()
{
- d_remote_headers = new Gee.HashMap<string, RefHeader>();
+ d_header_map = new Gee.HashMap<string, RemoteHeader>();
+ d_ref_map = new Gee.HashMap<Gitg.Ref, RefRow>();
foreach (var child in get_children())
{
@@ -309,22 +420,66 @@ public class RefsList : Gtk.ListBox
add(header);
}
- private RefHeader add_remote_header(string name)
+ private void add_remote_header(string name)
{
var header = new RefHeader.remote(name);
header.show();
+ d_header_map[name] = new RemoteHeader(header);
add(header);
-
- return header;
}
- private void add_ref(Gitg.Ref? reference)
+ private void add_ref_row(Gitg.Ref? reference)
{
var row = new RefRow(reference);
row.show();
add(row);
+
+ if (reference != null)
+ {
+ d_ref_map[reference] = row;
+ }
+ }
+
+ public void add_ref(Gitg.Ref reference)
+ {
+ if (d_ref_map.has_key(reference))
+ {
+ return;
+ }
+
+ if (reference.parsed_name.rtype == Gitg.RefType.REMOTE)
+ {
+ var remote = reference.parsed_name.remote_name;
+
+ if (!d_header_map.has_key(remote))
+ {
+ add_remote_header(remote);
+ }
+
+ d_header_map[remote].references.add(reference);
+ }
+
+ add_ref_row(reference);
+ }
+
+ public void replace_ref(Gitg.Ref old_ref, Gitg.Ref new_ref)
+ {
+ bool select = false;
+
+ if (d_ref_map.has_key(old_ref))
+ {
+ select = (get_selected_row().get_child() == d_ref_map[old_ref]);
+ }
+
+ remove_ref(old_ref);
+ add_ref(new_ref);
+
+ if (select)
+ {
+ select_row(d_ref_map[new_ref].get_parent() as Gtk.ListBoxRow);
+ }
}
// Checks if the provided reference is a symbolic ref with the name HEAD.
@@ -349,6 +504,31 @@ public class RefsList : Gtk.ListBox
return name == "HEAD";
}
+ public void remove_ref(Gitg.Ref reference)
+ {
+ if (!d_ref_map.has_key(reference))
+ {
+ return;
+ }
+
+ d_ref_map[reference].get_parent().destroy();
+ d_ref_map.unset(reference);
+
+ if (reference.parsed_name.rtype == Gitg.RefType.REMOTE)
+ {
+ var remote = reference.parsed_name.remote_name;
+ var remote_header = d_header_map[remote];
+
+ remote_header.references.remove(reference);
+
+ if (remote_header.references.is_empty)
+ {
+ remote_header.header.get_parent().destroy();
+ d_header_map.unset(remote);
+ }
+ }
+ }
+
public void refresh()
{
clear();
@@ -358,7 +538,7 @@ public class RefsList : Gtk.ListBox
return;
}
- add_ref(null);
+ add_ref_row(null);
add_header(Gitg.RefType.BRANCH, _("Branches"));
add_header(Gitg.RefType.REMOTE, _("Remotes"));
@@ -381,35 +561,143 @@ public class RefsList : Gtk.ListBox
return 0;
}
- if (r.parsed_name.rtype == Gitg.RefType.REMOTE)
+ add_ref(r);
+ return 0;
+ });
+ } catch {}
+ }
+
+ private RefRow? get_ref_row(Gtk.ListBoxRow? row)
+ {
+ if (row == null)
+ {
+ return null;
+ }
+
+ return row.get_child() as RefRow;
+ }
+
+ private RefHeader? get_ref_header(Gtk.ListBoxRow row)
+ {
+ return row.get_child() as RefHeader;
+ }
+
+ public Gee.List<Gitg.Ref> all
+ {
+ owned get
+ {
+ var ret = new Gee.LinkedList<Gitg.Ref>();
+
+ foreach (var child in get_children())
+ {
+ var r = get_ref_row(child as Gtk.ListBoxRow);
+
+ if (r != null && r.reference != null)
{
- var remote = r.parsed_name.remote_name;
+ ret.add(r.reference);
+ }
+ }
+
+ try
+ {
+ if (d_repository.is_head_detached())
+ {
+ ret.add(d_repository.get_head());
+ }
+ } catch {}
+
+ return ret;
+ }
+ }
+
+ [Notify]
+ public Gee.List<Gitg.Ref> selection
+ {
+ owned get
+ {
+ var row = get_selected_row();
+
+ if (row == null)
+ {
+ return all;
+ }
+
+ var ref_row = get_ref_row(row);
+ var ret = new Gee.LinkedList<Gitg.Ref>();
+
+ if (ref_row != null)
+ {
+ if (ref_row.reference == null)
+ {
+ return all;
+ }
+ else
+ {
+ ret.add(ref_row.reference);
+ }
+ }
+ else
+ {
+ var ref_header = get_ref_header(row);
+ bool found = false;
- if (!d_remote_headers.has_key(remote))
+ foreach (var child in get_children())
+ {
+ if (found)
{
- d_remote_headers[remote] = add_remote_header(remote);
+ var nrow = child as Gtk.ListBoxRow;
+ var nref_row = get_ref_row(nrow);
+
+ if (nref_row == null)
+ {
+ var nref_header = get_ref_header(nrow);
+
+ if (ref_header.is_sub_header_remote ||
+ nref_header.ref_type != ref_header.ref_type)
+ {
+ break;
+ }
+ }
+ else
+ {
+ ret.add(nref_row.reference);
+ }
+ }
+ else if (child == row)
+ {
+ found = true;
}
}
+ }
- add_ref(r);
- return 0;
- });
- } catch {}
+ return ret;
+ }
}
- private RefRow? get_ref_row(Gtk.ListBoxRow row)
+ private void on_row_selected(Gtk.ListBoxRow? row)
{
- return row.get_child() as RefRow;
+ notify_property("selection");
}
- protected override void row_activated(Gtk.ListBoxRow row)
+ private void on_row_editing_done(RefRow row, string new_text, bool cancelled)
{
- var r = get_ref_row(row);
+ editing_done(row.reference, new_text, cancelled);
+ row.editing_done.disconnect(on_row_editing_done);
+ }
- if (r != null)
+ public bool begin_editing(Gitg.Ref reference)
+ {
+ if (!d_ref_map.has_key(reference))
{
- ref_activated(r.reference);
+ return false;
}
+
+ var row = d_ref_map[reference];
+
+ row.editing_done.connect(on_row_editing_done);
+ row.begin_editing();
+
+ return true;
}
}
diff --git a/gitg/history/gitg-history.vala b/gitg/history/gitg-history.vala
index fbbde25..bd08bec 100644
--- a/gitg/history/gitg-history.vala
+++ b/gitg/history/gitg-history.vala
@@ -310,8 +310,13 @@ namespace GitgHistory
d_panels = new Gitg.UIElements<GitgExt.HistoryPanel>(extset,
d_main.stack_panel);
- d_main.refs_list.ref_activated.connect((r) => {
- update_walker(r);
+ d_main.refs_list.popup_menu.connect(on_refs_list_popup_menu);
+ d_main.refs_list.button_press_event.connect(on_refs_list_button_press_event);
+
+ d_main.refs_list.editing_done.connect(on_ref_edited);
+
+ d_main.refs_list.notify["selection"].connect(() => {
+ update_walker();
});
application.bind_property("repository", d_main.refs_list,
@@ -320,76 +325,199 @@ namespace GitgHistory
BindingFlags.SYNC_CREATE);
}
- private void update_walker(Gitg.Ref? head)
+ private void on_ref_edited(Gitg.Ref reference, string new_text, bool cancelled)
{
- Ggit.OId? id = null;
+ if (cancelled)
+ {
+ return;
+ }
+
+ string orig;
+ string? prefix;
+
+ var pn = reference.parsed_name;
- if (head != null)
+ if (pn.rtype == Gitg.RefType.REMOTE)
{
- id = head.get_target();
+ orig = pn.remote_branch;
+ prefix = pn.prefix + "/" + pn.remote_name + "/";
+ }
+ else
+ {
+ orig = pn.shortname;
+ prefix = pn.prefix;
+ }
- if (head.parsed_name.rtype == Gitg.RefType.TAG)
+ if (orig == new_text)
+ {
+ return;
+ }
+
+ if (!Ggit.Ref.is_valid_name(@"$prefix$new_text"))
+ {
+ var msg = _("The specified name ā%sā contains invalid
characters").printf(new_text);
+
+ application.show_infobar(_("Invalid name"),
+ msg,
+ Gtk.MessageType.ERROR);
+
+ return;
+ }
+
+ var branch = reference as Ggit.Branch;
+ Gitg.Ref? new_ref = null;
+
+ try
+ {
+ var repo = application.repository;
+ var appenv = application.environment;
+ var signature = repo.get_signature_with_environment(appenv);
+
+ if (branch != null)
{
- // See to resolve to the commit
- try
- {
- var t = application.repository.lookup<Ggit.Tag>(id);
+ var msg = _("rename: branch %s to %s").printf(branch.get_name(),
+ new_text);
+
+ new_ref = branch.move(new_text,
+ Ggit.CreateFlags.NONE,
+ signature,
+ msg) as Gitg.Ref;
+ }
+ else
+ {
+ var msg = _("rename: ref %s to %s").printf(reference.get_name(),
+ new_text);
- id = t.get_target_id();
- } catch {}
+ new_ref = reference.rename(new_text,
+ false,
+ signature,
+ msg) as Gitg.Ref;
}
}
+ catch (Error e)
+ {
+ application.show_infobar(_("Failed to rename"),
+ e.message,
+ Gtk.MessageType.ERROR);
+
+ return;
+ }
+
+ d_main.refs_list.replace_ref(reference, new_ref);
+ }
- if (id != null)
+ private void add_ref_action(Gee.LinkedList<GitgExt.RefAction> actions, GitgExt.RefAction?
action)
+ {
+ if (action.visible)
{
- d_commit_list_model.set_include(new Ggit.OId[] { id });
+ actions.add(action);
}
- else
+ }
+
+ private bool refs_list_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 references = d_main.refs_list.selection;
+
+ if (references.is_empty || references.first() != references.last())
{
- var included = new Ggit.OId[] {};
- var repo = application.repository;
+ return false;
+ }
- try
- {
- repo.references_foreach_name((nm) => {
- Gitg.Ref? r;
+ var reference = references.first();
- try
- {
- r = repo.lookup_reference(nm);
- } catch { return 0; }
+ var rename = new Gitg.RefActionRename(application.action_interface,
+ reference);
- try
- {
- var resolved = r.resolve();
-
- try
- {
- var t =
repo.lookup<Ggit.Tag>(resolved.get_target());
- included += t.get_target_id();
- }
- catch
- {
- included += resolved.get_target();
- }
- } catch {}
-
- return 0;
- });
- } catch {}
+ 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.refs_list.begin_editing(action.reference as Gitg.Ref);
+ }
+ private bool on_refs_list_popup_menu(Gtk.Widget widget)
+ {
+ return refs_list_popup_menu(widget, null);
+ }
+
+ private bool on_refs_list_button_press_event(Gtk.Widget widget, Gdk.EventButton event)
+ {
+ Gdk.Event *ev = (Gdk.Event *)(&event);
+
+ if (!ev->triggers_context_menu())
+ {
+ return false;
+ }
+
+ var row = d_main.refs_list.get_row_at_y((int)event.y);
+ d_main.refs_list.select_row(row);
+
+ return refs_list_popup_menu(widget, event);
+ }
+
+ private void update_walker()
+ {
+ d_selected.clear();
+
+ foreach (var r in d_main.refs_list.selection)
+ {
try
{
- if (repo.is_head_detached())
+ var resolved = r.resolve();
+
+ if (resolved.is_tag())
{
- var resolved = repo.get_head().resolve();
- included += resolved.get_target();
+ var t =
application.repository.lookup<Ggit.Tag>(resolved.get_target());
+ d_selected.add(t.get_target_id());
}
- } catch {}
-
- d_commit_list_model.set_include(included);
+ else
+ {
+ d_selected.add(resolved.get_target());
+ }
+ }
+ catch {}
}
+ d_commit_list_model.set_include(d_selected.to_array());
d_commit_list_model.reload();
}
}
diff --git a/gitg/resources/ui/style.css b/gitg/resources/ui/style.css
index f8cabee..a74aac6 100644
--- a/gitg/resources/ui/style.css
+++ b/gitg/resources/ui/style.css
@@ -76,6 +76,15 @@ GitgHistoryPaned panel-switcher {
background-color: @theme_bg_color;
}
+GitgHistoryPaned GtkEntry.ref_editing_entry {
+ padding: 0;
+ border: 0;
+}
+
+GitgHistoryPaned GtkEntry.ref_editing_entry:selected {
+ background-color: lighter(@theme_selected_bg_color);
+}
+
.progress-bin {
background-color: shade (@theme_bg_color, 0.9);
}
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)
diff --git a/libgitg/gitg-repository.vala b/libgitg/gitg-repository.vala
index c9c8028..150725a 100644
--- a/libgitg/gitg-repository.vala
+++ b/libgitg/gitg-repository.vala
@@ -165,6 +165,63 @@ public class Repository : Ggit.Repository
return d_stage;
}
}
+
+ public Ggit.Signature get_signature_with_environment(Gee.Map<string, string> env, string envname =
"COMMITER") throws Error
+ {
+ string? user = null;
+ string? email = null;
+ DateTime? date = null;
+
+ var nameenv = @"GIT_$(envname)_NAME";
+ var emailenv = @"GIT_$(envname)_EMAIL";
+ var dateenv = @"GIT_$(envname)_DATE";
+
+ if (env.has_key(nameenv))
+ {
+ user = env[nameenv];
+ }
+
+ if (env.has_key(emailenv))
+ {
+ email = env[emailenv];
+ }
+
+ if (env.has_key(dateenv))
+ {
+ try
+ {
+ date = Gitg.Date.parse(env[dateenv]);
+ }
+ catch {}
+ }
+
+ if (date == null)
+ {
+ date = new DateTime.now_local();
+ }
+
+ var conf = get_config();
+
+ if (user == null)
+ {
+ try
+ {
+ user = conf.get_string("user.name");
+ } catch {}
+ }
+
+ if (email == null)
+ {
+ try
+ {
+ email = conf.get_string("user.email");
+ } catch {}
+ }
+
+ return new Ggit.Signature(user != null ? user : "",
+ email != null ? email : "",
+ date);
+ }
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]