From a9478a7ac2136e5e871236a7c5b280ef52297d74 Mon Sep 17 00:00:00 2001 From: Jesse van den Kieboom Date: Sun, 20 Jul 2014 16:32:26 +0300 Subject: [PATCH] Implement Create Branch --- gitg/Makefile.am | 3 + gitg/gitg-animated-paned.vala | 191 ++++++++++++++++++ gitg/gitg-commit-action-create-branch.vala | 106 ++++++++++ gitg/gitg-create-branch-dialog.vala | 60 ++++++ gitg/history/gitg-history-paned.vala | 101 ++++++++- gitg/history/gitg-history.vala | 107 +++++++++- gitg/resources/gitg-resources.xml | 1 + .../resources/ui/gitg-create-branch-dialog.ui | 108 ++++++++++ gitg/resources/ui/gitg-history-paned.ui | 4 +- libgitg-ext/gitg-ext-commit-action.vala | 4 +- po/POTFILES.in | 2 + po/POTFILES.skip | 1 + 12 files changed, 672 insertions(+), 16 deletions(-) create mode 100644 gitg/gitg-animated-paned.vala create mode 100644 gitg/gitg-commit-action-create-branch.vala create mode 100644 gitg/gitg-create-branch-dialog.vala create mode 100644 gitg/resources/ui/gitg-create-branch-dialog.ui diff --git a/gitg/Makefile.am b/gitg/Makefile.am index b8ed78b9..28ff9b9e 100644 --- a/gitg/Makefile.am +++ b/gitg/Makefile.am @@ -58,9 +58,12 @@ gitg_gitg_VALASOURCES = \ gitg/gitg-application.vala \ gitg/gitg-plugins-engine.vala \ gitg/gitg-popup-menu.vala \ + gitg/gitg-animated-paned.vala \ gitg/gitg-ui-elements.vala \ gitg/gitg-ref-action-rename.vala \ gitg/gitg-ref-action-delete.vala \ + gitg/gitg-commit-action-create-branch.vala \ + gitg/gitg-create-branch-dialog.vala \ gitg/preferences/gitg-preferences-commit.vala \ gitg/preferences/gitg-preferences-dialog.vala \ gitg/preferences/gitg-preferences-interface.vala \ diff --git a/gitg/gitg-animated-paned.vala b/gitg/gitg-animated-paned.vala new file mode 100644 index 00000000..716e0792 --- /dev/null +++ b/gitg/gitg-animated-paned.vala @@ -0,0 +1,191 @@ +/* + * 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 . + */ + +namespace Gitg +{ + +public enum SlideDirection +{ + IN, + OUT +} + +public enum SlidePanedChild +{ + FIRST, + SECOND +} + +public class AnimatedPaned : Gtk.Paned +{ + private int d_target_pos; + private int d_original_pos; + private int d_start_pos; + private int64 d_slide_start; + private int64 d_slide_duration; + private uint d_tick_id; + private SourceFunc? d_async_callback; + private SlideDirection d_direction; + private SlidePanedChild d_child; + + public uint transition_duration + { + get; + construct set; + default = 250; + } + + private bool on_animate_step(Gtk.Widget widget, Gdk.FrameClock clock) + { + var elapsed = (clock.get_frame_time() - d_slide_start); + var factor = (double)elapsed / (double)d_slide_duration; + + if (factor > 1) + { + factor = 1; + } + + var pos = (int)Math.round((d_target_pos - d_start_pos) * factor) + d_start_pos; + set_position(pos); + + if (pos == d_target_pos) + { + d_tick_id = 0; + + if (d_async_callback != null) + { + d_async_callback(); + } + + if (d_direction == SlideDirection.OUT) + { + if (d_child == SlidePanedChild.FIRST) + { + get_child1().hide(); + } + else + { + get_child2().hide(); + } + } + + return false; + } + + return true; + } + + public override void dispose() + { + if (d_tick_id != 0) + { + remove_tick_callback(d_tick_id); + d_tick_id = 0; + } + + base.dispose(); + } + + public bool is_animating + { + get { return d_tick_id != 0; } + } + + public void slide(SlidePanedChild child, + SlideDirection direction) + { + slide_async.begin(child, direction, (obj, res) => { + slide_async.end(res); + }); + } + + public async void slide_async(SlidePanedChild child, + SlideDirection direction) + { + if (d_tick_id == 0) + { + if (direction == SlideDirection.OUT) + { + d_original_pos = get_position(); + } + + d_tick_id = add_tick_callback(on_animate_step); + } + + d_slide_start = get_frame_clock().get_frame_time(); + d_start_pos = get_position(); + d_direction = direction; + d_child = child; + + double factor; + int w; + + if (orientation == Gtk.Orientation.VERTICAL) + { + w = get_allocated_height(); + } + else + { + w = get_allocated_width(); + } + + if (direction == SlideDirection.OUT) + { + if (child == SlidePanedChild.FIRST) + { + d_target_pos = 0; + } + else + { + d_target_pos = w; + } + + factor = ((double)d_target_pos - (double)d_start_pos) / + ((double)d_target_pos - (double)d_original_pos); + } + else + { + d_target_pos = d_original_pos; + + double div; + + if (child == SlidePanedChild.FIRST) + { + div = d_original_pos; + get_child1().show(); + } + else + { + div = d_original_pos - w; + get_child2().show(); + } + + factor = ((double)d_target_pos - (double)d_start_pos) / div; + } + + d_async_callback = slide_async.callback; + d_slide_duration = (int64)(factor * transition_duration) * 1000; + + yield; + } +} + +} + +// vi: ts=4 noet diff --git a/gitg/gitg-commit-action-create-branch.vala b/gitg/gitg-commit-action-create-branch.vala new file mode 100644 index 00000000..018db6ec --- /dev/null +++ b/gitg/gitg-commit-action-create-branch.vala @@ -0,0 +1,106 @@ +/* + * 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 . + */ + +namespace Gitg +{ + +class CommitActionCreateBranch : GitgExt.UIElement, GitgExt.Action, GitgExt.CommitAction, Object +{ + // Do this to pull in config.h before glib.h (for gettext...) + private const string version = Gitg.Config.VERSION; + + public GitgExt.Application? application { owned get; construct set; } + public GitgExt.RefActionInterface action_interface { get; construct set; } + public Gitg.Commit commit { get; construct set; } + + public CommitActionCreateBranch(GitgExt.Application application, + GitgExt.RefActionInterface action_interface, + Gitg.Commit commit) + { + Object(application: application, + action_interface: action_interface, + commit: commit); + } + + public string id + { + owned get { return "/org/gnome/gitg/commit-actions/create-branch"; } + } + + public string display_name + { + owned get { return _("Create Branch"); } + } + + public string description + { + owned get { return _("Create a new branch at the selected commit"); } + } + + public void activate() + { + var dlg = new CreateBranchDialog((Gtk.Window)application); + + dlg.response.connect((d, resp) => { + if (resp == Gtk.ResponseType.OK) + { + Ggit.Branch? branch = null; + Ggit.Signature? author = null; + + var repo = application.repository; + + try + { + author = repo.get_signature_with_environment(application.environment); + } catch {} + + var id = commit.get_id().to_string(); + + try + { + branch = repo.create_branch(dlg.new_branch_name, + commit, + Ggit.CreateFlags.NONE, + author, + @"branch: Created from $(id)"); + } + catch (Error e) + { + application.show_infobar(_("Failed to create branch"), + e.message, + Gtk.MessageType.ERROR); + } + + if (branch != null) + { + action_interface.add_ref((Gitg.Ref)branch); + } + } + + dlg.destroy(); + finished(); + }); + + dlg.show(); + } +} + +} + +// ex:set ts=4 noet diff --git a/gitg/gitg-create-branch-dialog.vala b/gitg/gitg-create-branch-dialog.vala new file mode 100644 index 00000000..edd3017b --- /dev/null +++ b/gitg/gitg-create-branch-dialog.vala @@ -0,0 +1,60 @@ +/* + * 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 . + */ + +namespace Gitg +{ + +[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-create-branch-dialog.ui")] +class CreateBranchDialog : Gtk.Dialog +{ + [GtkChild] + private Gtk.Button d_button_create; + + [GtkChild] + private Gtk.Entry d_entry_branch_name; + + construct + { + d_entry_branch_name.changed.connect(() => { + d_button_create.sensitive = (new_branch_name.length != 0); + }); + } + + public CreateBranchDialog(Gtk.Window? parent) + { + Object(use_header_bar : 1); + + if (parent != null) + { + set_transient_for(parent); + } + } + + public string new_branch_name + { + owned get + { + return d_entry_branch_name.text.strip(); + } + } +} + +} + +// ex: ts=4 noet diff --git a/gitg/history/gitg-history-paned.vala b/gitg/history/gitg-history-paned.vala index 81951a82..276a9494 100644 --- a/gitg/history/gitg-history-paned.vala +++ b/gitg/history/gitg-history-paned.vala @@ -21,13 +21,13 @@ namespace GitgHistory { [GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-history-paned.ui")] -class Paned : Gtk.Paned +class Paned : Gitg.AnimatedPaned { [GtkChild] private Gtk.Box d_box_sidebar; [GtkChild] - private Gtk.Paned d_paned_panels; + private Gitg.AnimatedPaned d_paned_panels; [GtkChild] private Gtk.StackSwitcher d_stack_switcher_panels; @@ -85,19 +85,95 @@ class Paned : Gtk.Paned } } + private void slide_in() + { + slide(Gitg.SlidePanedChild.FIRST, Gitg.SlideDirection.IN); + + Gitg.SlidePanedChild child; + + if (inner_orientation == Gtk.Orientation.HORIZONTAL) + { + child = Gitg.SlidePanedChild.FIRST; + } + else + { + child = Gitg.SlidePanedChild.SECOND; + } + + d_paned_panels.slide(child, Gitg.SlideDirection.IN); + } + + private void slide_out() + { + slide(Gitg.SlidePanedChild.FIRST, Gitg.SlideDirection.OUT); + + Gitg.SlidePanedChild child; + + if (inner_orientation == Gtk.Orientation.HORIZONTAL) + { + child = Gitg.SlidePanedChild.FIRST; + } + else + { + child = Gitg.SlidePanedChild.SECOND; + } + + d_paned_panels.slide(child, Gitg.SlideDirection.OUT); + } + + private GitgExt.SelectionMode d_selectable_mode; + + [Notify] + public GitgExt.SelectionMode selectable_mode + { + get { return d_selectable_mode; } + set + { + if (d_selectable_mode != value) + { + d_selectable_mode = value; + + if (d_selectable_mode == GitgExt.SelectionMode.NORMAL) + { + slide_in(); + } + else + { + slide_out(); + } + } + } + } + + private void store_paned_position(Gitg.AnimatedPaned paned, Settings settings, string key) + { + if (paned.is_animating) + { + return; + } + + if (!paned.get_child1().visible || !paned.get_child2().visible) + { + return; + } + + settings.set_int(key, paned.get_position()); + } + construct { var state_settings = new Settings("org.gnome.gitg.state.history"); - state_settings.bind("paned-sidebar-position", - this, - "position", - SettingsBindFlags.GET | SettingsBindFlags.SET); + position = state_settings.get_int("paned-sidebar-position"); + d_paned_panels.position = state_settings.get_int("paned-panels-position"); - state_settings.bind("paned-panels-position", - d_paned_panels, - "position", - SettingsBindFlags.GET | SettingsBindFlags.SET); + notify["position"].connect(() => { + store_paned_position(this, state_settings, "paned-sidebar-position"); + }); + + d_paned_panels.notify["position"].connect(() => { + store_paned_position(d_paned_panels, state_settings, "paned-panels-position"); + }); var interface_settings = new Settings("org.gnome.gitg.preferences.interface"); @@ -141,6 +217,11 @@ class Paned : Gtk.Paned { var ret = base.draw(context); + if (!get_child1().visible || !get_child2().visible) + { + return ret; + } + var window = d_box_sidebar.get_window(); var handlewin = get_handle_window(); diff --git a/gitg/history/gitg-history.vala b/gitg/history/gitg-history.vala index 6639c8b5..8b5cd944 100644 --- a/gitg/history/gitg-history.vala +++ b/gitg/history/gitg-history.vala @@ -22,7 +22,7 @@ namespace GitgHistory /* The main history view. This view shows the equivalent of git log, but * in a nice way with lanes, merges, ref labels etc. */ - public class Activity : Object, GitgExt.UIElement, GitgExt.Activity, GitgExt.History + public class Activity : Object, GitgExt.UIElement, GitgExt.Activity, GitgExt.Selectable, GitgExt.History { // Do this to pull in config.h before glib.h (for gettext...) private const string version = Gitg.Config.VERSION; @@ -39,6 +39,7 @@ namespace GitgHistory private Paned d_main; private Gitg.PopupMenu d_refs_list_popup; + private Gitg.PopupMenu d_commit_list_popup; private Gitg.UIElements d_panels; @@ -357,15 +358,30 @@ namespace GitgHistory update_walker(); }); + d_commit_list_popup = new Gitg.PopupMenu(d_main.commit_list_view); + d_commit_list_popup.populate_menu.connect(on_commit_list_populate_menu); + application.bind_property("repository", d_main.refs_list, "repository", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE); + + bind_property("selectable-mode", + d_main, + "selectable-mode", + BindingFlags.BIDIRECTIONAL); } - private void add_ref_action(Gee.LinkedList actions, GitgExt.RefAction? action) + private Gtk.Menu? on_commit_list_populate_menu(Gdk.EventButton? event) { - if (action.available) + selectable_mode = GitgExt.SelectionMode.SELECTION; + return null; + } + + private void add_ref_action(Gee.LinkedList actions, + GitgExt.RefAction? action) + { + if (action != null && action.available) { actions.add(action); } @@ -462,6 +478,91 @@ namespace GitgHistory d_commit_list_model.set_include(include); d_commit_list_model.reload(); } + + [Notify] + public GitgExt.SelectionMode selectable_mode + { + get; set; + } + + private void add_commit_action(Gee.LinkedList actions, + GitgExt.CommitAction? action) + { + if (action != null && action.available) + { + actions.add(action); + action.finished.connect(() => { + selectable_mode = GitgExt.SelectionMode.NORMAL; + }); + } + } + + public Gtk.Widget? action_widget + { + owned get + { + Gitg.Commit? commit = null; + + foreach_selected((c) => { + commit = (Gitg.Commit)c; + return false; + }); + + var af = new ActionInterface(application, d_main.refs_list); + + var actions = new Gee.LinkedList(); + + add_commit_action(actions, + new Gitg.CommitActionCreateBranch(application, + af, + commit)); + + var exts = new Peas.ExtensionSet(Gitg.PluginsEngine.get_default(), + typeof(GitgExt.CommitAction), + "application", + application, + "action_interface", + af, + "commit", + commit); + + exts.foreach((extset, info, extension) => { + add_commit_action(actions, extension as GitgExt.CommitAction); + }); + + var ab = new Gtk.ActionBar(); + ab.show(); + + var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6); + box.margin = 6; + box.homogeneous = true; + box.show(); + + foreach (var action in actions) + { + var widget = action.widget; + + if (widget == null) + { + var button = new Gtk.Button.with_label(action.display_name); + button.tooltip_text = action.description; + + button.clicked.connect(() => { + action.activate(); + }); + + widget = button; + } + + widget.show(); + box.add(widget); + } + + ab.set_center_widget(box); + + return ab; + } + } } } diff --git a/gitg/resources/gitg-resources.xml b/gitg/resources/gitg-resources.xml index 2eb37f51..a5bae93f 100644 --- a/gitg/resources/gitg-resources.xml +++ b/gitg/resources/gitg-resources.xml @@ -15,6 +15,7 @@ ui/gitg-history-ref-header.ui ui/gitg-commit-paned.ui ui/gitg-commit-dialog.ui + ui/gitg-create-branch-dialog.ui ui/style.css diff --git a/gitg/resources/ui/gitg-create-branch-dialog.ui b/gitg/resources/ui/gitg-create-branch-dialog.ui new file mode 100644 index 00000000..7219e3c4 --- /dev/null +++ b/gitg/resources/ui/gitg-create-branch-dialog.ui @@ -0,0 +1,108 @@ + + + + + diff --git a/gitg/resources/ui/gitg-history-paned.ui b/gitg/resources/ui/gitg-history-paned.ui index 05a022ff..ff709aff 100644 --- a/gitg/resources/ui/gitg-history-paned.ui +++ b/gitg/resources/ui/gitg-history-paned.ui @@ -3,7 +3,7 @@ -