[gitg/remote-operations: 1/4] Allow to add new remotes




commit be22b5370c40586bc1b03eee4cb85a6267b9b2eb
Author: Adwait Rawat <adwait rawat gmail com>
Date:   Tue Jun 18 13:19:52 2019 +0900

    Allow to add new remotes

 gitg/gitg-add-remote-action-dialog.vala            |  90 ++++++++++++
 gitg/gitg-add-remote-action.vala                   | 158 +++++++++++++++++++++
 gitg/history/gitg-history-refs-list.vala           |  25 +++-
 gitg/history/gitg-history.vala                     |  34 ++++-
 gitg/meson.build                                   |   3 +
 gitg/resources/gitg-resources.xml.in               |   1 +
 gitg/resources/ui/gitg-add-remote-action-dialog.ui | 139 ++++++++++++++++++
 libgitg-ext/gitg-ext-action.vala                   |   4 +
 8 files changed, 445 insertions(+), 9 deletions(-)
---
diff --git a/gitg/gitg-add-remote-action-dialog.vala b/gitg/gitg-add-remote-action-dialog.vala
new file mode 100644
index 00000000..7f7b40a9
--- /dev/null
+++ b/gitg/gitg-add-remote-action-dialog.vala
@@ -0,0 +1,90 @@
+/*
+ * This file is part of gitg
+ *
+ * Copyright (C) 2022 - Adwait Rawat
+ *
+ * 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-add-remote-action-dialog.ui")]
+class AddRemoteActionDialog : Gtk.Dialog
+{
+       [GtkChild]
+       private Gtk.Button d_button_create;
+
+       [GtkChild]
+       private Gtk.Entry d_entry_remote_name;
+
+       [GtkChild]
+       private Gtk.Entry d_entry_remote_url;
+
+       construct
+       {
+               d_entry_remote_name.changed.connect(() => {
+                       var is_name_valid = (d_entry_remote_name.text != "");
+
+                       d_entry_remote_url.changed.connect((e) => {
+                               var is_url_valid = (d_entry_remote_url.text != "");
+
+                               set_response_sensitive(Gtk.ResponseType.OK, is_name_valid && is_url_valid);
+                       });
+               });
+
+               set_default(d_button_create);
+               set_default_response(Gtk.ResponseType.OK);
+       }
+
+       public AddRemoteActionDialog(Gtk.Window? parent)
+       {
+               Object(use_header_bar : 1);
+
+               if (parent != null)
+               {
+                       set_transient_for(parent);
+               }
+       }
+
+       public string remote_name
+       {
+               owned get
+               {
+                       return d_entry_remote_name.text.strip();
+               }
+
+               set
+               {
+                  d_entry_remote_name.text = value.strip();
+               }
+       }
+
+       public string remote_url
+       {
+               owned get
+               {
+                       return d_entry_remote_url.text.strip();
+               }
+
+               set
+               {
+                  d_entry_remote_url.text = value.strip();
+               }
+       }
+}
+
+}
+
+// ex: ts=4 noet
diff --git a/gitg/gitg-add-remote-action.vala b/gitg/gitg-add-remote-action.vala
new file mode 100644
index 00000000..fb95faf0
--- /dev/null
+++ b/gitg/gitg-add-remote-action.vala
@@ -0,0 +1,158 @@
+/*
+ * This file is part of gitg
+ *
+ * Copyright (C) 2022 - Adwait Rawat
+ *
+ * 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 AddRemoteAction : GitgExt.UIElement, GitgExt.Action, 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; }
+       private Gitg.Remote? d_remote;
+       private Gitg.Repository? repo;
+       private string? remote_name;
+       private string? remote_url;
+
+       public AddRemoteAction(GitgExt.Application application)
+       {
+               Object(application: application);
+       }
+
+       public string id
+       {
+               owned get { return "/org/gnome/gitg/ref-actions/add-remote"; }
+       }
+
+       public string display_name
+       {
+               owned get { return _("Add Remote"); }
+       }
+
+       public string description
+       {
+               owned get { return _("Adds remote to the remotes list"); }
+       }
+
+       public async bool fetch()
+       {
+               var notification = new RemoteNotification(d_remote);
+               application.notifications.add(notification);
+
+               notification.text = _("Fetching from %s").printf(d_remote.get_url());
+
+               var updates = new Gee.ArrayList<string>();
+
+               var tip_updated_id = d_remote.tip_updated.connect((d_remote, name, a, b) => {
+                       /* Translators: new refers to a new remote reference having been fetched, */
+                       updates.add(@"%s (%s)".printf(name, _("new")));
+               });
+
+               try
+               {
+                       yield d_remote.fetch(null, null);
+               }
+               catch (Error e)
+               {
+                       try {
+                               notification.error(_("Failed to fetch from %s: 
%s").printf(d_remote.get_url(), e.message));
+                       }
+                       catch {}
+                       application.show_infobar(_("Failed to fetch added remote"),
+                                                e.message,
+                                                Gtk.MessageType.ERROR);
+               }
+               finally
+               {
+                       ((Object)d_remote).disconnect(tip_updated_id);
+               }
+
+               ((Gtk.ApplicationWindow)application).activate_action("reload", null);
+               if (updates.size != 0)
+               {
+                       notification.success(_("Fetched from %s: %s").printf(d_remote.get_url(), 
string.joinv(", ", updates.to_array())));
+               }
+               else
+               {
+                       add_remote(remote_name, remote_url);
+
+                       return false;
+               }
+
+               return true;
+       }
+
+       public void add_remote(owned string? name = "", owned string? url = "")
+       {
+               var dlg = new AddRemoteActionDialog((Gtk.Window)application);
+
+               remote_name = name;
+               remote_url = url;
+               dlg.remote_name = remote_name;
+               dlg.remote_url = remote_url;
+
+               dlg.response.connect((d, resp) => {
+                       if (resp == Gtk.ResponseType.OK)
+                       {
+                               Ggit.Remote? remote = null;
+                               d_remote = null;
+
+                               repo = application.repository;
+                               remote_name = dlg.remote_name;
+                               remote_url = dlg.remote_url;
+
+                               try
+                               {
+                                       remote = repo.create_remote(remote_name,
+                                                                   remote_url);
+                               }
+                               catch (Error e)
+                               {
+                                       add_remote(remote_name, remote_url);
+                                       application.show_infobar(_("Failed to add remote"),
+                                                                e.message,
+                                                                Gtk.MessageType.ERROR);
+                               }
+
+                               d_remote = application.remote_lookup.lookup(remote_name);
+
+                               if (remote != null)
+                               {
+                                       fetch.begin((obj,res) => {
+                                               fetch.end(res);
+                                       });
+                               }
+                       }
+
+                       dlg.destroy();
+               });
+
+               dlg.show();
+       }
+
+       public void activate()
+       {
+               add_remote();
+       }
+}
+
+}
+
+// ex:set ts=4 noet
diff --git a/gitg/history/gitg-history-refs-list.vala b/gitg/history/gitg-history-refs-list.vala
index 22831078..de411efc 100644
--- a/gitg/history/gitg-history-refs-list.vala
+++ b/gitg/history/gitg-history-refs-list.vala
@@ -43,7 +43,7 @@ private enum RefAnimation
        ANIMATE
 }
 
-private interface RefTyped : Object
+public interface RefTyped : Object
 {
        public abstract Gitg.RefType ref_type { get; }
 }
@@ -402,11 +402,12 @@ private class RefRow : RefTyped, Gtk.ListBoxRow
 }
 
 [GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-history-ref-header.ui")]
-private class RefHeader : RefTyped, Gtk.ListBoxRow
+public class RefHeader : RefTyped, Gtk.ListBoxRow
 {
        private Gitg.RefType d_rtype;
        private bool d_is_sub_header_remote;
        private string d_name;
+       public Gee.LinkedList<GitgExt.Action> actions { get; set; }
 
        public Gitg.RemoteState remote_state
        {
@@ -536,6 +537,15 @@ public class RefsList : Gtk.ListBox
        private RefHeader? d_all_tags;
        private RefRow.SortOrder d_ref_sort_order;
        private HeaderState[] d_expanded;
+       public RefHeader? branches_header { get { return d_all_branches; } }
+       public RefHeader? remotes_header { get { return d_all_remotes; } }
+       public RefHeader? tags_header { get { return d_all_tags; } }
+       private Gee.LinkedList<GitgExt.Action> d_branches_actions = null;
+       private Gee.LinkedList<GitgExt.Action> d_remotes_actions = null;
+       private Gee.LinkedList<GitgExt.Action> d_tags_actions = null;
+       public Gee.LinkedList<GitgExt.Action> branches_actions { get {return d_branches_actions;} set { 
d_branches_actions = value; refresh();} }
+       public Gee.LinkedList<GitgExt.Action> remotes_actions { get {return d_remotes_actions;} set { 
d_remotes_actions = value; refresh();} }
+       public Gee.LinkedList<GitgExt.Action> tags_actions { get {return d_tags_actions;} set { 
d_tags_actions = value; refresh();} }
 
        public signal void changed();
 
@@ -869,10 +879,11 @@ public class RefsList : Gtk.ListBox
                }
        }
 
-       private RefHeader add_header(Gitg.RefType ref_type, string name)
+       private RefHeader add_header(Gitg.RefType ref_type, string name, Gee.LinkedList<GitgExt.Action>? 
actions)
        {
                var header = new RefHeader(ref_type, name);
                init_header(header);
+               header.actions = actions;
 
                add(header);
                return header;
@@ -1176,9 +1187,9 @@ public class RefsList : Gtk.ListBox
                }
 
                d_all_commits = add_ref_row(null);
-               d_all_branches = add_header(Gitg.RefType.BRANCH, _("Branches"));
-               d_all_remotes = add_header(Gitg.RefType.REMOTE, _("Remotes"));
-               d_all_tags = add_header(Gitg.RefType.TAG, _("Tags"));
+               d_all_branches = add_header(Gitg.RefType.BRANCH, _("Branches"), branches_actions);
+               d_all_remotes = add_header(Gitg.RefType.REMOTE, _("Remotes"), remotes_actions);
+               d_all_tags = add_header(Gitg.RefType.TAG, _("Tags"), tags_actions);
 
                RefRow? head = null;
 
@@ -1412,7 +1423,7 @@ public class RefsList : Gtk.ListBox
                row.begin_editing((owned)done);
        }
 
-       private int y_in_window(int y, Gdk.Window origin)
+       public int y_in_window(int y, Gdk.Window origin)
        {
                while (origin != get_window())
                {
diff --git a/gitg/history/gitg-history.vala b/gitg/history/gitg-history.vala
index 87289eb6..ef27bb9a 100644
--- a/gitg/history/gitg-history.vala
+++ b/gitg/history/gitg-history.vala
@@ -627,6 +627,10 @@ namespace GitgHistory
 
                        d_commit_list_model.begin_clear.connect(on_commit_model_begin_clear);
                        d_commit_list_model.end_clear.connect(on_commit_model_end_clear);
+
+                       var actions = new Gee.LinkedList<GitgExt.Action>();
+                       actions.add(new Gitg.AddRemoteAction(application));
+                       d_main.refs_list.remotes_actions = actions;
                }
 
                private void update_walker_idle()
@@ -988,9 +992,12 @@ namespace GitgHistory
 
                private Gtk.Menu? on_refs_list_populate_menu(Gdk.EventButton? event)
                {
+                       Gtk.ListBoxRow selection = null;
                        if (event != null)
                        {
-                               var row = d_main.refs_list.get_row_at_y((int)event.y);
+                       var y = d_main.refs_list.y_in_window((int)event.y, event.window);
+                               var row = d_main.refs_list.get_row_at_y(y);
+                               selection = row;
                                d_main.refs_list.select_row(row);
                        }
 
@@ -998,7 +1005,30 @@ namespace GitgHistory
 
                        if (references.is_empty || references.first() != references.last())
                        {
-                               return null;
+                               Gee.LinkedList<GitgExt.Action> actions = null;
+                               if (selection != null && selection.get_type () == typeof(RefHeader)
+                                       && (actions = ((RefHeader)selection).actions) != null && actions.size 
0) {
+                                       var menu = new Gtk.Menu();
+
+                                       foreach (var ac in actions)
+                                       {
+                                               if (ac != null)
+                                               {
+                                                       ac.populate_menu(menu);
+                                               }
+                                               else
+                                               {
+                                                       var sep = new Gtk.SeparatorMenuItem();
+                                                       sep.show();
+                                                       menu.append(sep);
+                                               }
+                                       }
+
+                                       menu.set_data("gitg-ext-actions", actions);
+                                       return menu;
+                               } else {
+                                       return null;
+                               }
                        }
 
                        return popup_menu_for_ref(references.first());
diff --git a/gitg/meson.build b/gitg/meson.build
index 85688b65..937a01a3 100644
--- a/gitg/meson.build
+++ b/gitg/meson.build
@@ -46,6 +46,8 @@ sources = gitg_sources + files(
   'gitg-ref-action-fetch.vala',
   'gitg-ref-action-push.vala',
   'gitg-ref-action-rename.vala',
+  'gitg-add-remote-action-dialog.vala',
+  'gitg-add-remote-action.vala',
   'gitg-remote-manager.vala',
   'gitg-remote-notification.vala',
   'gitg-simple-notification.vala',
@@ -106,6 +108,7 @@ resource_data = files(
   'resources/ui/gitg-preferences-history.ui',
   'resources/ui/gitg-preferences-interface.ui',
   'resources/ui/gitg-preferences.ui',
+  'resources/ui/gitg-add-remote-action-dialog.ui',
   'resources/ui/gitg-remote-notification.ui',
   'resources/ui/gitg-shortcuts.ui',
   'resources/ui/gitg-simple-notification.ui',
diff --git a/gitg/resources/gitg-resources.xml.in b/gitg/resources/gitg-resources.xml.in
index 1224cefe..5248b951 100644
--- a/gitg/resources/gitg-resources.xml.in
+++ b/gitg/resources/gitg-resources.xml.in
@@ -7,6 +7,7 @@
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-preferences-commit.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-preferences-interface.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-preferences.ui</file>
+    <file compressed="true" preprocess="xml-stripblanks">ui/gitg-add-remote-action-dialog.ui</file>
     <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>
diff --git a/gitg/resources/ui/gitg-add-remote-action-dialog.ui 
b/gitg/resources/ui/gitg-add-remote-action-dialog.ui
new file mode 100644
index 00000000..a73f2f16
--- /dev/null
+++ b/gitg/resources/ui/gitg-add-remote-action-dialog.ui
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <template class="GitgAddRemoteActionDialog" parent="GtkDialog">
+    <property name="can_focus">False</property>
+    <property name="border_width">12</property>
+    <property name="title" translatable="yes">Create Remote</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">_Add</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">Remote _name:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">d_entry_remote_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_entry_remote_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 _URL:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">d_entry_remote_url</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="GtkEntry" id="d_entry_remote_url">
+                <property name="width_request">350</property>
+                <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">1</property>
+                <property name="width">1</property>
+                <property name="height">1</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="cancel">button_cancel</action-widget>
+      <action-widget response="ok">d_button_create</action-widget>
+    </action-widgets>
+  </template>
+</interface>
diff --git a/libgitg-ext/gitg-ext-action.vala b/libgitg-ext/gitg-ext-action.vala
index b05808ce..caddc864 100644
--- a/libgitg-ext/gitg-ext-action.vala
+++ b/libgitg-ext/gitg-ext-action.vala
@@ -46,6 +46,10 @@ public interface Action : UIElement
                item.show();
                menu.append(item);
        }
+
+       public virtual async bool fetch(){
+               return true;
+       }
 }
 
 }


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