[gitg] Remote branches can be checked out using double-click.



commit 754cde5e822cf21d4f6f5719b7f7aab6c3074863
Author: Armandas Jarušauskas <jarusauskas gmail com>
Date:   Tue Jun 9 20:50:31 2020 +0900

    Remote branches can be checked out using double-click.

 gitg/gitg-checkout-remote-branch-dialog.vala       | 141 +++++++++++++++++++
 gitg/gitg-ref-action-checkout.vala                 |  79 ++++++++++-
 gitg/history/gitg-history.vala                     |   2 +-
 gitg/meson.build                                   |   2 +
 gitg/resources/gitg-resources.xml.in               |   1 +
 .../ui/gitg-checkout-remote-branch-dialog.ui       | 152 +++++++++++++++++++++
 tests/gitg/checkout-remote-branch-dialog-mock.vala |  51 +++++++
 tests/gitg/meson.build                             |   1 +
 8 files changed, 424 insertions(+), 5 deletions(-)
---
diff --git a/gitg/gitg-checkout-remote-branch-dialog.vala b/gitg/gitg-checkout-remote-branch-dialog.vala
new file mode 100644
index 00000000..28195ae4
--- /dev/null
+++ b/gitg/gitg-checkout-remote-branch-dialog.vala
@@ -0,0 +1,141 @@
+/*
+ * This file is part of gitg
+ *
+ * Copyright (C) 2020 - Armandas Jarušauskas
+ *
+ * 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
+{
+
+[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-checkout-remote-branch-dialog.ui")]
+class CheckoutRemoteBranchDialog : Gtk.Dialog
+{
+       [GtkChild]
+       private Gtk.Button d_button_create;
+
+       [GtkChild]
+       private Gtk.Entry d_branch_name;
+
+       [GtkChild]
+       private Gtk.ComboBoxText d_remote_branch_name;
+
+       [GtkChild]
+       private Gtk.CheckButton d_track_remote;
+
+       private Gitg.Repository d_repository;
+       private Gitg.Ref d_remote_reference;
+
+       construct
+       {
+               d_branch_name.changed.connect(() => {
+                       d_button_create.sensitive = entries_valid();
+               });
+
+               d_remote_branch_name.changed.connect(() => {
+                       d_button_create.sensitive = entries_valid();
+               });
+
+               set_default(d_button_create);
+               set_default_response(Gtk.ResponseType.OK);
+       }
+
+       public CheckoutRemoteBranchDialog(Gtk.Window? parent, Gitg.Repository? repository, Gitg.Ref reference)
+       {
+               Object(use_header_bar : 1);
+
+               if (parent != null)
+               {
+                       set_transient_for(parent);
+               }
+
+               if (repository != null)
+               {
+                       d_repository = repository;
+               }
+
+               if (reference.is_remote())
+               {
+                       d_remote_reference = reference;
+               }
+       }
+
+       public string new_branch_name
+       {
+               owned get
+               {
+                       return d_branch_name.text.strip();
+               }
+       }
+
+       public string remote_branch_name
+       {
+               owned get
+               {
+                       return d_remote_branch_name.get_active_text();
+               }
+       }
+
+       public bool track_remote
+       {
+               get
+               {
+                       return d_track_remote.active;
+               }
+       }
+
+       public override void show()
+       {
+               base.show();
+
+               update_entries();
+       }
+
+       private bool entries_valid()
+       {
+               return (new_branch_name.length != 0) && (d_remote_branch_name.get_active_text() != null);
+       }
+
+       private void update_entries()
+       {
+               d_branch_name.set_text(d_remote_reference.parsed_name.remote_branch);
+
+               try
+               {
+                       d_repository.references_foreach_name((name) => {
+                               Gitg.Ref? reference;
+                               try
+                               {
+                                       reference = d_repository.lookup_reference(name);
+                               } catch { return 0; }
+
+                               if (!reference.is_remote() || (reference.get_reference_type() == 
Ggit.RefType.SYMBOLIC))
+                               {
+                                       return 0;
+                               }
+
+                               d_remote_branch_name.append(reference.parsed_name.shortname, 
reference.parsed_name.shortname);
+
+                               return 0;
+                       });
+               } catch {}
+
+               d_remote_branch_name.set_active_id(d_remote_reference.parsed_name.shortname);
+       }
+}
+
+}
+
+// ex: ts=4 noet
diff --git a/gitg/gitg-ref-action-checkout.vala b/gitg/gitg-ref-action-checkout.vala
index 834b095c..8a691d83 100644
--- a/gitg/gitg-ref-action-checkout.vala
+++ b/gitg/gitg-ref-action-checkout.vala
@@ -59,7 +59,7 @@ class RefActionCheckout : GitgExt.UIElement, GitgExt.Action, GitgExt.RefAction,
                {
                        try
                        {
-                               return reference.is_branch() && !((Ggit.Branch)reference).is_head();
+                               return (reference.is_branch() && !((Ggit.Branch)reference).is_head()) || 
reference.is_remote();
                        } catch {}
 
                        return false;
@@ -127,9 +127,80 @@ class RefActionCheckout : GitgExt.UIElement, GitgExt.Action, GitgExt.RefAction,
 
        public void activate()
        {
-               checkout.begin((obj, res) => {
-                       checkout.end(res);
-               });
+               if (reference.is_branch())
+               {
+                       checkout.begin();
+               }
+               else if (reference.is_remote())
+               {
+                       var dlg = new CheckoutRemoteBranchDialog((Gtk.Window)application, 
application.repository, reference);
+                       dlg.response.connect((d, resp) => {
+                               on_checkout_remote_branch_dialog_response(dlg, resp);
+                       });
+
+                       dlg.show();
+               }
+       }
+
+       private void on_checkout_remote_branch_dialog_response(Gitg.CheckoutRemoteBranchDialog dialog, int 
response_id) {
+               if (response_id == Gtk.ResponseType.OK)
+               {
+                       string? remote_branch_name = dialog.track_remote ? dialog.remote_branch_name : null;
+
+                       create_branch.begin(reference, dialog.new_branch_name, remote_branch_name, (obj, res) 
=> {
+                               var branch_ref = create_branch.end(res) as Gitg.Ref;
+
+                               if (branch_ref != null)
+                               {
+                                       action_interface.add_ref(branch_ref);
+                                       reference = branch_ref;
+                                       checkout.begin();
+                               }
+                       });
+               }
+
+               dialog.destroy();
+       }
+
+       private async Ggit.Branch? create_branch(Ggit.Ref reference, string new_branch_name, string? 
remote_branch_name)
+       {
+               Ggit.Branch? branch = null;
+
+               var repo = application.repository;
+
+               try
+               {
+                       Gitg.Commit commit = reference.lookup() as Gitg.Commit;
+                       branch = repo.create_branch(new_branch_name,
+                                                   commit,
+                                                   Ggit.CreateFlags.NONE);
+               }
+               catch (Error e)
+               {
+                       application.show_infobar(_("Failed to create branch"),
+                                                e.message,
+                                                Gtk.MessageType.ERROR);
+               }
+
+               if (branch != null)
+               {
+                       if (remote_branch_name != null) {
+                               try
+                               {
+                                       branch.set_upstream(remote_branch_name);
+                               }
+                               catch (Error e)
+                               {
+                                       application.show_infobar(
+                                          _("Failed to set the upstream branch %s for 
%s").printf(remote_branch_name,
+                                          new_branch_name),
+                                          e.message,
+                                          Gtk.MessageType.ERROR);
+                               }
+                       }
+               }
+
+               return branch;
        }
 }
 
diff --git a/gitg/history/gitg-history.vala b/gitg/history/gitg-history.vala
index 02582e2e..87289eb6 100644
--- a/gitg/history/gitg-history.vala
+++ b/gitg/history/gitg-history.vala
@@ -1123,7 +1123,7 @@ namespace GitgHistory
                                return;
                        }
 
-                       if (ref_row.reference.is_branch()) {
+                       if (ref_row.reference.is_branch() || ref_row.reference.is_remote()) {
                                var af = new ActionInterface(application, d_main.refs_list);
                                var checkout = new Gitg.RefActionCheckout(application, af, ref_row.reference);
                                checkout.activate();
diff --git a/gitg/meson.build b/gitg/meson.build
index 51b341e1..85688b65 100644
--- a/gitg/meson.build
+++ b/gitg/meson.build
@@ -33,6 +33,7 @@ sources = gitg_sources + files(
   'gitg-convert.vala',
   'gitg-create-branch-dialog.vala',
   'gitg-create-tag-dialog.vala',
+  'gitg-checkout-remote-branch-dialog.vala',
   'gitg-dash-view.vala',
   'gitg-dirs.vala',
   'gitg-notifications.vala',
@@ -109,6 +110,7 @@ resource_data = files(
   'resources/ui/gitg-shortcuts.ui',
   'resources/ui/gitg-simple-notification.ui',
   'resources/ui/gitg-window.ui',
+  'resources/ui/gitg-checkout-remote-branch-dialog.ui',
   'resources/ui/style.css',
   'resources/ui/style-@0@.css'.format(platform_name),
 )
diff --git a/gitg/resources/gitg-resources.xml.in b/gitg/resources/gitg-resources.xml.in
index a97175f5..1224cefe 100644
--- a/gitg/resources/gitg-resources.xml.in
+++ b/gitg/resources/gitg-resources.xml.in
@@ -23,6 +23,7 @@
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-simple-notification.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-remote-notification.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-shortcuts.ui</file>
+    <file compressed="true" preprocess="xml-stripblanks">ui/gitg-checkout-remote-branch-dialog.ui</file>
 
     <file compressed="true">ui/style.css</file>
     <file compressed="true">ui/style-@PLATFORM_NAME@.css</file>
diff --git a/gitg/resources/ui/gitg-checkout-remote-branch-dialog.ui 
b/gitg/resources/ui/gitg-checkout-remote-branch-dialog.ui
new file mode 100644
index 00000000..c003270b
--- /dev/null
+++ b/gitg/resources/ui/gitg-checkout-remote-branch-dialog.ui
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <template class="GitgCheckoutRemoteBranchDialog" parent="GtkDialog">
+    <property name="can_focus">False</property>
+    <property name="border_width">12</property>
+    <property name="title" translatable="yes">Checkout Remote Branch</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="headerbar">
+      <object class="GtkHeaderBar" id="dialog-header_bar">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="show_close_button">False</property>
+        <child>
+          <object class="GtkButton" id="button_cancel">
+            <property name="label" translatable="yes">_Cancel</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="use_underline">True</property>
+            <property name="valign">center</property>
+            <style>
+              <class name="text-button"/>
+            </style>
+          </object>
+          <packing>
+            <property name="pack_type">start</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="d_button_create">
+            <property name="label" translatable="yes">C_heckout</property>
+            <property name="visible">True</property>
+            <property name="sensitive">False</property>
+            <property name="can_focus">True</property>
+            <property name="can_default">True</property>
+            <property name="receives_default">True</property>
+            <property name="use_underline">True</property>
+            <style>
+              <class name="text-button"/>
+              <class name="suggested-action"/>
+            </style>
+          </object>
+          <packing>
+            <property name="pack_type">end</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkGrid" id="grid1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="row_spacing">6</property>
+            <property name="column_spacing">6</property>
+            <child>
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">end</property>
+                <property name="label" translatable="yes">Local branch _name:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">d_branch_name</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="d_branch_name">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hexpand">True</property>
+                <property name="activates_default">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">end</property>
+                <property name="label" translatable="yes">_Remote branch:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">d_remote_branch_name</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkComboBoxText" id="d_remote_branch_name">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hexpand">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="d_track_remote">
+                <property name="label" translatable="yes">_Track remote branch</property>
+                               <property name="use_underline">True</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="draw_indicator">True</property>
+                <property name="active">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-6">button_cancel</action-widget>
+      <action-widget response="-5">d_button_create</action-widget>
+    </action-widgets>
+  </template>
+</interface>
diff --git a/tests/gitg/checkout-remote-branch-dialog-mock.vala 
b/tests/gitg/checkout-remote-branch-dialog-mock.vala
new file mode 100644
index 00000000..69c9307c
--- /dev/null
+++ b/tests/gitg/checkout-remote-branch-dialog-mock.vala
@@ -0,0 +1,51 @@
+/*
+ * This file is part of gitg
+ *
+ * Copyright (C) 2020 - Armandas Jarušauskas
+ *
+ * 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 CheckoutRemoteBranchDialog : Gtk.Dialog
+{
+       public CheckoutRemoteBranchDialog(Gtk.Window? parent, Gitg.Repository? repository, Gitg.Ref reference)
+       {
+       }
+
+       public string new_branch_name {get; set; default = "test_branch"; }
+
+       public string remote_branch_name {get; set; default = "origin/test_branch"; }
+
+       public bool track_remote {get; set; default = true; }
+
+       public override void show()
+       {
+       }
+
+       private bool entries_valid()
+       {
+               return (new_branch_name.len() != 0) && (remote_branch_name.len() != 0);
+       }
+
+       private void update_entries()
+       {
+       }
+}
+
+}
+
+// ex: ts=4 noet
diff --git a/tests/gitg/meson.build b/tests/gitg/meson.build
index 87803dd6..445f71cd 100644
--- a/tests/gitg/meson.build
+++ b/tests/gitg/meson.build
@@ -4,6 +4,7 @@ sources = gitg_sources + support_sources + files(
   'notifications-mock.vala',
   'ref-action-interface-mock.vala',
   'simple-notification-mock.vala',
+  'checkout-remote-branch-dialog-mock.vala',
   'test-checkout-ref.vala',
   'test-cherry-pick-commit.vala',
   'test-merge-ref.vala',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]