Cleanly separate ref actions using interfaces

This commit is contained in:
Jesse van den Kieboom 2014-01-19 19:17:31 +01:00 committed by Jesse van den Kieboom
parent 456da855b2
commit 3750ed9fd0
12 changed files with 266 additions and 161 deletions

View file

@ -57,6 +57,7 @@ gitg_gitg_VALASOURCES = \
gitg/gitg-resource.vala \
gitg/gitg-application.vala \
gitg/gitg-plugins-engine.vala \
gitg/gitg-popup-menu.vala \
gitg/gitg-ui-elements.vala \
gitg/gitg-ref-action-rename.vala \
gitg/gitg-ref-action-delete.vala \
@ -65,6 +66,7 @@ gitg_gitg_VALASOURCES = \
gitg/preferences/gitg-preferences-interface.vala \
gitg/preferences/gitg-preferences-history.vala \
gitg/history/gitg-history.vala \
gitg/history/gitg-history-action-interface.vala \
gitg/history/gitg-history-refs-list.vala \
gitg/history/gitg-history-paned.vala \
gitg/commit/gitg-commit.vala \

86
gitg/gitg-popup-menu.vala Normal file
View file

@ -0,0 +1,86 @@
/*
* 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 Gitg
{
class PopupMenu : Object
{
public signal Gtk.Menu? populate_menu(Gdk.EventButton? event);
private Gtk.Widget? d_widget;
public PopupMenu(Gtk.Widget widget)
{
widget.button_press_event.connect(on_button_press_event);
widget.popup_menu.connect(on_popup_menu);
d_widget = widget;
}
public override void dispose()
{
if (d_widget != null)
{
d_widget.button_press_event.disconnect(on_button_press_event);
d_widget.popup_menu.disconnect(on_popup_menu);
d_widget = null;
}
}
private bool popup_menu(Gtk.Widget widget, Gdk.EventButton? event)
{
var menu = populate_menu(event);
if (menu == null)
{
return false;
}
var time = (event == null ? Gtk.get_current_event_time() : event.time);
var button = (event == null ? 0 : event.button);
menu.attach_to_widget(widget, null);
menu.popup(null, null, null, button, time);
return true;
}
private bool on_popup_menu(Gtk.Widget widget)
{
return popup_menu(widget, null);
}
private bool on_button_press_event(Gtk.Widget widget, Gdk.EventButton event)
{
Gdk.Event *ev = (Gdk.Event *)(&event);
if (!ev->triggers_context_menu())
{
return false;
}
return popup_menu(widget, event);
}
}
}
// ex:set ts=4 noet

View file

@ -25,10 +25,10 @@ class RefActionDelete : GitgExt.Action, GitgExt.RefAction, Object
// 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 GitgExt.RefActionInterface action_interface { get; construct set; }
public Gitg.Ref reference { get; construct set; }
public RefActionDelete(GitgExt.ActionInterface action_interface, Ggit.Ref reference)
public RefActionDelete(GitgExt.RefActionInterface action_interface, Gitg.Ref reference)
{
Object(action_interface: action_interface, reference: reference);
}
@ -42,12 +42,9 @@ class RefActionDelete : GitgExt.Action, GitgExt.RefAction, Object
{
get
{
var r = reference as Gitg.Ref;
var rtype = r.parsed_name.rtype;
return rtype == RefType.BRANCH
|| rtype == RefType.TAG
|| rtype == RefType.REMOTE;
return reference.is_branch()
|| reference.is_tag()
|| reference.is_remote();
}
}

View file

@ -25,10 +25,10 @@ class RefActionRename : GitgExt.Action, GitgExt.RefAction, Object
// 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 GitgExt.RefActionInterface action_interface { get; construct set; }
public Gitg.Ref reference { get; construct set; }
public RefActionRename(GitgExt.ActionInterface action_interface, Ggit.Ref reference)
public RefActionRename(GitgExt.RefActionInterface action_interface, Gitg.Ref reference)
{
Object(action_interface: action_interface, reference: reference);
}
@ -47,12 +47,81 @@ class RefActionRename : GitgExt.Action, GitgExt.RefAction, Object
{
get
{
var r = reference as Gitg.Ref;
var rtype = r.parsed_name.rtype;
return rtype == RefType.BRANCH || rtype == RefType.TAG;
return reference.is_branch()
|| reference.is_tag();
}
}
public void activated()
{
action_interface.edit_ref_name(reference, on_ref_name_editing_done);
}
private void on_ref_name_editing_done(string new_text, bool cancelled)
{
if (cancelled)
{
return;
}
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 == new_text)
{
return;
}
if (!Ggit.Ref.is_valid_name(@"$prefix$new_text"))
{
var msg = _("The specified name %s contains invalid characters").printf(new_text);
action_interface.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(new_text, Ggit.CreateFlags.NONE) as Gitg.Ref;
}
else
{
new_ref = reference.rename(new_text, false) as Gitg.Ref;
}
}
catch (Error e)
{
action_interface.application.show_infobar(_("Failed to rename"),
e.message,
Gtk.MessageType.ERROR);
return;
}
action_interface.application.repository.clear_refs_cache();
action_interface.replace_ref(reference, new_ref);
}
}
}

View file

@ -21,7 +21,7 @@ namespace Gitg
{
[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-window.ui")]
public class Window : Gtk.ApplicationWindow, GitgExt.Application, GitgExt.ActionInterface, Initable
public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
{
private Settings d_state_settings;
private Settings d_interface_settings;
@ -648,11 +648,6 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, GitgExt.Action
}
}
}
public GitgExt.ActionInterface action_interface
{
owned get { return this; }
}
}
}

View file

@ -0,0 +1,64 @@
/*
* 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
{
class ActionInterface : Object, GitgExt.RefActionInterface
{
public GitgExt.Application application { owned get; construct set; }
private RefsList d_refs_list;
public ActionInterface(GitgExt.Application application, RefsList refs_list)
{
Object(application: application);
d_refs_list = refs_list;
}
public void add_ref(Gitg.Ref reference)
{
d_refs_list.add_ref(reference);
}
public void remove_ref(Gitg.Ref reference)
{
d_refs_list.remove_ref(reference);
}
public void replace_ref(Gitg.Ref old_ref, Gitg.Ref new_ref)
{
d_refs_list.replace_ref(old_ref, new_ref);
}
public void set_busy(Gitg.Ref reference, bool busy)
{
// TODO
}
public void edit_ref_name(Gitg.Ref reference, owned GitgExt.RefNameEditingDone done)
{
d_refs_list.edit(reference, (owned)done);
}
}
}
// ex: ts=4 noet

View file

@ -38,6 +38,7 @@ namespace GitgHistory
private Settings d_settings;
private Paned d_main;
private Gitg.PopupMenu d_refs_list_popup;
private Gitg.UIElements<GitgExt.HistoryPanel> d_panels;
@ -310,10 +311,8 @@ namespace GitgHistory
d_panels = new Gitg.UIElements<GitgExt.HistoryPanel>(extset,
d_main.stack_panel);
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_refs_list_popup = new Gitg.PopupMenu(d_main.refs_list);
d_refs_list_popup.populate_menu.connect(on_refs_list_populate_menu);
d_main.refs_list.notify["selection"].connect(() => {
update_walker();
@ -325,87 +324,6 @@ namespace GitgHistory
BindingFlags.SYNC_CREATE);
}
private void on_ref_edited(Gitg.Ref reference, string new_text, bool cancelled)
{
if (cancelled)
{
return;
}
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 == 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)
{
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);
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);
}
private void add_ref_action(Gee.LinkedList<GitgExt.RefAction> actions, GitgExt.RefAction? action)
{
if (action.visible)
@ -414,36 +332,33 @@ namespace GitgHistory
}
}
private bool refs_list_popup_menu(Gtk.Widget widget, Gdk.EventButton? event)
private Gtk.Menu? on_refs_list_populate_menu(Gdk.EventButton? event)
{
var button = (event == null ? 0 : event.button);
var time = (event == null ? Gtk.get_current_event_time() : event.time);
if (event != null)
{
var row = d_main.refs_list.get_row_at_y((int)event.y);
d_main.refs_list.select_row(row);
}
var actions = new Gee.LinkedList<GitgExt.RefAction>();
var references = d_main.refs_list.selection;
if (references.is_empty || references.first() != references.last())
{
return false;
return null;
}
var reference = references.first();
var rename = new Gitg.RefActionRename(application.action_interface,
reference);
var af = new ActionInterface(application, d_main.refs_list);
rename.activated.connect(() => { on_rename_activated(rename); });
add_ref_action(actions, rename);
add_ref_action(actions,
new Gitg.RefActionDelete(application.action_interface,
reference));
add_ref_action(actions, new Gitg.RefActionRename(af, reference));
add_ref_action(actions, new Gitg.RefActionDelete(af, reference));
var exts = new Peas.ExtensionSet(Gitg.PluginsEngine.get_default(),
typeof(GitgExt.RefAction),
"action_interface",
application.action_interface,
af,
"reference",
reference);
@ -453,7 +368,7 @@ namespace GitgHistory
if (actions.is_empty)
{
return false;
return null;
}
Gtk.Menu menu = new Gtk.Menu();
@ -463,35 +378,9 @@ namespace GitgHistory
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);
// To keep actions alive as long as the menu is alive
menu.set_data("gitg-ext-actions", actions);
return menu;
}
private void update_walker()

View file

@ -43,7 +43,7 @@ libgitg_ext_libgitg_ext_1_0_la_LIBADD = \
libgitg_ext_libgitg_ext_1_0_la_VALASOURCES = \
libgitg-ext/gitg-ext-assembly-info.vala \
libgitg-ext/gitg-ext-action-interface.vala \
libgitg-ext/gitg-ext-ref-action-interface.vala \
libgitg-ext/gitg-ext-action.vala \
libgitg-ext/gitg-ext-commit-action.vala \
libgitg-ext/gitg-ext-ref-action.vala \

View file

@ -22,8 +22,6 @@ namespace GitgExt
public interface Action : Object
{
public abstract ActionInterface action_interface { get; construct set; }
public abstract string label { get; }
public abstract bool enabled { get; }
public abstract bool visible { get; }

View file

@ -45,11 +45,6 @@ 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.
*

View file

@ -20,8 +20,17 @@
namespace GitgExt
{
public interface ActionInterface : Object
public delegate void RefNameEditingDone(string new_name, bool cancelled);
public interface RefActionInterface : Object
{
public abstract Application application { owned get; construct set; }
public abstract void add_ref(Gitg.Ref reference);
public abstract void remove_ref(Gitg.Ref reference);
public abstract void replace_ref(Gitg.Ref old_ref, Gitg.Ref new_ref);
public abstract void set_busy(Gitg.Ref reference, bool busy);
public abstract void edit_ref_name(Gitg.Ref reference, owned RefNameEditingDone callback);
}
}

View file

@ -22,7 +22,8 @@ namespace GitgExt
public interface RefAction : Action
{
public abstract Ggit.Ref reference { get; construct set; }
public abstract RefActionInterface action_interface { get; construct set; }
public abstract Gitg.Ref reference { get; construct set; }
}
}