From 53529683a772252ed745640715ad08ca9d5c212a Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Sat, 15 May 2021 19:14:45 +0100 Subject: [PATCH 01/28] Add ChooseProjectButton class --- src/Services/GitManager.vala | 8 ++ src/Widgets/ChooseProjectButton.vala | 206 +++++++++++++++++++++++++++ src/meson.build | 1 + 3 files changed, 215 insertions(+) create mode 100644 src/Widgets/ChooseProjectButton.vala diff --git a/src/Services/GitManager.vala b/src/Services/GitManager.vala index 162765f246..db073165a4 100644 --- a/src/Services/GitManager.vala +++ b/src/Services/GitManager.vala @@ -37,6 +37,9 @@ namespace Scratch.Services { return instance; } + public signal void project_added (string root_path); + public signal void project_removed (string root_path); + private GitManager () {} public MonitoredRepository? add_project (GLib.File root_folder) { @@ -50,6 +53,7 @@ namespace Scratch.Services { var monitored_repo = new MonitoredRepository (git_repo); project_gitrepo_map.@set (root_path, monitored_repo); + project_added (root_path); return project_gitrepo_map.@get (root_path); } catch (Error e) { debug ("Error opening git repo for %s, means this probably isn't one: %s", root_path, e.message); @@ -63,5 +67,9 @@ namespace Scratch.Services { project_gitrepo_map.unset (root_path); } } + + public string[] get_project_paths () { + return project_gitrepo_map.keys.to_array (); + } } } diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala new file mode 100644 index 0000000000..b745a3f161 --- /dev/null +++ b/src/Widgets/ChooseProjectButton.vala @@ -0,0 +1,206 @@ +/*- + * Copyright (c) 2017 elementary LLC. (https://elementary.io) + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + * + * Authored by: Corentin Noël + */ + +public class Code.ChooseProjectButton : Gtk.ToggleButton { + public string text { + set { + label_widget.label = value; + } + } + + public GLib.Icon? icon { + owned get { + return img.gicon; + } + set { + img.gicon = value; + } + } + + private Scratch.Services.GitManager manager; + + private Gtk.Image img; + private Gtk.Label label_widget; + private Gtk.ListBox project_selection_listbox; + + construct { + img = new Gtk.Image () { + icon_size = Gtk.IconSize.SMALL_TOOLBAR + }; + + label_widget = new Gtk.Label (null) { + ellipsize = Pango.EllipsizeMode.END + }; + + var grid = new Gtk.Grid () { + halign = Gtk.Align.CENTER, + margin_start = 6, + margin_end = 6 + }; + grid.add (img); + grid.add (label_widget); + add (grid); + + // get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED); + + manager = Scratch.Services.GitManager.get_instance (); + + icon = new ThemedIcon ("git-symbolic"); + tooltip_text = _("Active Git project"); + + create_project_popover (); + } + + private void create_project_popover () { + project_selection_listbox = new Gtk.ListBox () { + selection_mode = Gtk.SelectionMode.SINGLE + }; + var project_selection_filter = new Gtk.SearchEntry () { + margin = 12, + margin_bottom = 6, + placeholder_text = _("Filter projects") + }; + project_selection_listbox.set_sort_func ((row1, row2) => { + return ((ProjectEntry) row1).project_name.collate (((ProjectEntry) row2).project_name); + }); + + project_selection_listbox.set_filter_func ((row) => { + //Both are lowercased so that the case doesn't matter when comparing. + return (((ProjectEntry) row).project_name.down ().contains (project_selection_filter.text.down ().strip ())); + }); + + project_selection_filter.changed.connect (() => { + project_selection_listbox.invalidate_filter (); + }); + + var project_scrolled = new Gtk.ScrolledWindow (null, null) { + hscrollbar_policy = Gtk.PolicyType.NEVER, + height_request = 350, + expand = true, + margin_top = 3, + margin_bottom = 3 + }; + + project_scrolled.add (project_selection_listbox); + + var paths = manager.get_project_paths (); + unowned SList group = null; + foreach (unowned string path in paths) { + var entry = new ProjectEntry (path, group); + group = entry.get_radio_group (); + project_selection_listbox.add (entry); + } + + var popover_content = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); + popover_content.add (project_selection_filter); + popover_content.add (project_scrolled); + + popover_content.show_all (); + + var project_popover = new Gtk.Popover (this) { + position = Gtk.PositionType.BOTTOM + }; + + project_popover.add (popover_content); + this.bind_property ("active", project_popover, "visible", GLib.BindingFlags.BIDIRECTIONAL); + + project_selection_listbox.row_activated.connect ((row) => { + var project_entry = ((ProjectEntry) row); + select_project (project_entry); + }); + } + + private void select_project (ProjectEntry project_entry) { + project_selection_listbox.select_row (project_entry); + this.text = project_entry.project_name; + project_entry.selected = true; + } + + public void set_document (Scratch.Services.Document doc) { + var path = doc.file.get_path (); + project_selection_listbox.get_children ().foreach ((child) => { + var project_entry = ((ProjectEntry) child); + if (path.has_prefix (project_entry.project_path)) { + select_project (project_entry); + } + }); + } + + public class ProjectEntry : Gtk.ListBoxRow { + public string project_path { get; construct; } + public string project_name { + owned get { + return Path.get_basename (project_path); + } + } + + public unowned SList group { get; construct; } + + public bool active { + get { + return project_radio.active; + } + + set { + project_radio.active = value; + } + } + + public bool selected { + get { + return project_radio.active; + } + + set { + project_radio.toggled.disconnect (radio_toggled); + project_radio.active = value; + project_radio.toggled.connect (radio_toggled); + } + } + + private Gtk.RadioButton project_radio; + public ProjectEntry (string project_path, SList group) { + Object ( + group: group, + project_path: project_path + ); + } + + class construct { + set_css_name (Gtk.STYLE_CLASS_MENUITEM); + } + + construct { + project_radio = new Gtk.RadioButton.with_label (group, project_name); + + add (project_radio); + project_radio.toggled.connect (radio_toggled); + } + + private void radio_toggled () { + if (project_radio.active) { + activate (); + } + } + + public unowned SList get_radio_group () { + return project_radio.get_group (); + } + } +} diff --git a/src/meson.build b/src/meson.build index c7c5c0e5d0..d55fd05e3b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -34,6 +34,7 @@ code_files = files( 'Services/PluginManager.vala', 'Services/Settings.vala', 'Services/TemplateManager.vala', + 'Widgets/ChooseProjectButton.vala', 'Widgets/DocumentView.vala', 'Widgets/FormatBar.vala', 'Widgets/HeaderBar.vala', From 7a2b03cdffb7300ce784d3f3bd63ec22fe72a1d0 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Sun, 16 May 2021 10:04:52 +0100 Subject: [PATCH 02/28] Add ChooseProjectButton to HeaderBar and react to add/remove project --- src/FolderManager/ProjectFolderItem.vala | 5 +- src/Services/GitManager.vala | 1 + src/Widgets/ChooseProjectButton.vala | 85 ++++++++++++------------ src/Widgets/HeaderBar.vala | 5 ++ 4 files changed, 51 insertions(+), 45 deletions(-) diff --git a/src/FolderManager/ProjectFolderItem.vala b/src/FolderManager/ProjectFolderItem.vala index f287c43628..9e45824bee 100644 --- a/src/FolderManager/ProjectFolderItem.vala +++ b/src/FolderManager/ProjectFolderItem.vala @@ -97,7 +97,10 @@ namespace Scratch.FolderManager { public override Gtk.Menu? get_context_menu () { var close_item = new Gtk.MenuItem.with_label (_("Close Folder")); - close_item.activate.connect (() => { closed (); }); + close_item.activate.connect (() => { + closed (); + Scratch.Services.GitManager.get_instance ().remove_project (file.file); + }); var close_all_except_item = new Gtk.MenuItem.with_label (_("Close Other Folders")); close_all_except_item.activate.connect (() => { close_all_except (); }); diff --git a/src/Services/GitManager.vala b/src/Services/GitManager.vala index db073165a4..4c8bb6b054 100644 --- a/src/Services/GitManager.vala +++ b/src/Services/GitManager.vala @@ -65,6 +65,7 @@ namespace Scratch.Services { var root_path = root_folder.get_path (); if (project_gitrepo_map.has_key (root_path)) { project_gitrepo_map.unset (root_path); + project_removed (root_path); } } diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index b745a3f161..6b68762f8d 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -18,36 +18,27 @@ */ public class Code.ChooseProjectButton : Gtk.ToggleButton { - public string text { - set { - label_widget.label = value; - } - } - - public GLib.Icon? icon { - owned get { - return img.gicon; - } - set { - img.gicon = value; - } - } - + private const string NO_PROJECT_SELECTED = N_("No Project Selected"); private Scratch.Services.GitManager manager; - private Gtk.Image img; private Gtk.Label label_widget; private Gtk.ListBox project_selection_listbox; + private ProjectEntry? last_entry = null; + + private Scratch.Services.Document? current_doc = null; construct { img = new Gtk.Image () { + gicon = new ThemedIcon ("git-symbolic"), icon_size = Gtk.IconSize.SMALL_TOOLBAR }; - label_widget = new Gtk.Label (null) { + label_widget = new Gtk.Label (_(NO_PROJECT_SELECTED)) { ellipsize = Pango.EllipsizeMode.END }; + tooltip_text = _("Active Git project"); + var grid = new Gtk.Grid () { halign = Gtk.Align.CENTER, margin_start = 6, @@ -57,17 +48,6 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { grid.add (label_widget); add (grid); - // get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED); - - manager = Scratch.Services.GitManager.get_instance (); - - icon = new ThemedIcon ("git-symbolic"); - tooltip_text = _("Active Git project"); - - create_project_popover (); - } - - private void create_project_popover () { project_selection_listbox = new Gtk.ListBox () { selection_mode = Gtk.SelectionMode.SINGLE }; @@ -80,7 +60,7 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { return ((ProjectEntry) row1).project_name.collate (((ProjectEntry) row2).project_name); }); - project_selection_listbox.set_filter_func ((row) => { + project_selection_listbox.set_filter_func ((row) => { //Both are lowercased so that the case doesn't matter when comparing. return (((ProjectEntry) row).project_name.down ().contains (project_selection_filter.text.down ().strip ())); }); @@ -99,14 +79,6 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { project_scrolled.add (project_selection_listbox); - var paths = manager.get_project_paths (); - unowned SList group = null; - foreach (unowned string path in paths) { - var entry = new ProjectEntry (path, group); - group = entry.get_radio_group (); - project_selection_listbox.add (entry); - } - var popover_content = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); popover_content.add (project_selection_filter); popover_content.add (project_scrolled); @@ -124,11 +96,38 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { var project_entry = ((ProjectEntry) row); select_project (project_entry); }); + + manager = Scratch.Services.GitManager.get_instance (); + manager.project_added.connect (add_project); + + manager.project_removed.connect ((project_path) => { + project_selection_listbox.get_children ().foreach ((child) => { + project_selection_listbox.remove (child); + }); + + label_widget.label = _(NO_PROJECT_SELECTED); + foreach (string path in manager.get_project_paths ()) { + add_project (path); + } + + set_document (current_doc); + }); + } + + private void add_project (string project_path) { + var project_entry = new ProjectEntry (project_path); + if (last_entry != null) { + project_entry.project_radio.join_group (last_entry.project_radio); + } + + last_entry = project_entry; + project_selection_listbox.add (project_entry); + select_project (project_entry); } private void select_project (ProjectEntry project_entry) { project_selection_listbox.select_row (project_entry); - this.text = project_entry.project_name; + label_widget.label = project_entry.project_name; project_entry.selected = true; } @@ -150,7 +149,7 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { } } - public unowned SList group { get; construct; } + public Gtk.RadioButton project_radio { get; construct; } public bool active { get { @@ -174,10 +173,8 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { } } - private Gtk.RadioButton project_radio; - public ProjectEntry (string project_path, SList group) { + public ProjectEntry (string project_path) { Object ( - group: group, project_path: project_path ); } @@ -187,10 +184,10 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { } construct { - project_radio = new Gtk.RadioButton.with_label (group, project_name); - + project_radio = new Gtk.RadioButton.with_label (null, project_name); add (project_radio); project_radio.toggled.connect (radio_toggled); + show_all (); } private void radio_toggled () { diff --git a/src/Widgets/HeaderBar.vala b/src/Widgets/HeaderBar.vala index a3ef598ae9..74f9ec7e39 100644 --- a/src/Widgets/HeaderBar.vala +++ b/src/Widgets/HeaderBar.vala @@ -27,6 +27,7 @@ namespace Scratch.Widgets { public Gtk.ToggleButton find_button; public Gtk.Button templates_button; public Code.FormatBar format_bar; + public Code.ChooseProjectButton choose_project_button; private const string STYLE_SCHEME_HIGH_CONTRAST = "classic"; private const string STYLE_SCHEME_LIGHT = "solarized-light"; @@ -42,6 +43,8 @@ namespace Scratch.Widgets { construct { var app_instance = (Scratch.Application) GLib.Application.get_default (); + choose_project_button = new Code.ChooseProjectButton (); + var open_button = new Gtk.Button.from_icon_name ("document-open", Gtk.IconSize.LARGE_TOOLBAR); open_button.action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_OPEN; open_button.tooltip_markup = Granite.markup_accel_tooltip ( @@ -190,6 +193,7 @@ namespace Scratch.Widgets { }; set_custom_title (format_bar); + pack_start (choose_project_button); pack_start (open_button); pack_start (templates_button); pack_start (save_button); @@ -277,6 +281,7 @@ namespace Scratch.Widgets { public void set_document_focus (Scratch.Services.Document doc) { format_bar.set_document (doc); + choose_project_button.set_document (doc); } } } From 298139ece2230ef9f9fb4944e6d1eae8d47093c7 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Sun, 16 May 2021 10:18:10 +0100 Subject: [PATCH 03/28] ChooseProjectButton.vala: Update header --- src/Widgets/ChooseProjectButton.vala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 6b68762f8d..7573032090 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017 elementary LLC. (https://elementary.io) + * Copyright (c) 2021 elementary Inc. (https://elementary.io) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,7 +14,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Authored by: Corentin Noël */ public class Code.ChooseProjectButton : Gtk.ToggleButton { From 2ee3d6f98c5b9923ce928012f1151b72d8864cdf Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Sun, 16 May 2021 10:19:37 +0100 Subject: [PATCH 04/28] Fix lint --- src/FolderManager/ProjectFolderItem.vala | 2 +- src/Widgets/ChooseProjectButton.vala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FolderManager/ProjectFolderItem.vala b/src/FolderManager/ProjectFolderItem.vala index 9e45824bee..77b251f902 100644 --- a/src/FolderManager/ProjectFolderItem.vala +++ b/src/FolderManager/ProjectFolderItem.vala @@ -97,7 +97,7 @@ namespace Scratch.FolderManager { public override Gtk.Menu? get_context_menu () { var close_item = new Gtk.MenuItem.with_label (_("Close Folder")); - close_item.activate.connect (() => { + close_item.activate.connect (() => { closed (); Scratch.Services.GitManager.get_instance ().remove_project (file.file); }); diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 7573032090..2edf30cc48 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -142,7 +142,7 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { public class ProjectEntry : Gtk.ListBoxRow { public string project_path { get; construct; } - public string project_name { + public string project_name { owned get { return Path.get_basename (project_path); } From 197be39cea06af43b1bfb5856b167052921cb27d Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Sun, 16 May 2021 17:42:07 +0100 Subject: [PATCH 05/28] Use HeaderBar active project new-branch action --- src/Dialogs/NewBranchDialog.vala | 81 ++++++++++++---------------- src/FolderManager/FileView.vala | 37 ++----------- src/MainWindow.vala | 38 +++++++------ src/Widgets/ChooseProjectButton.vala | 21 ++++++++ src/Widgets/HeaderBar.vala | 10 ++++ 5 files changed, 91 insertions(+), 96 deletions(-) diff --git a/src/Dialogs/NewBranchDialog.vala b/src/Dialogs/NewBranchDialog.vala index 87af296d84..13cf69807b 100644 --- a/src/Dialogs/NewBranchDialog.vala +++ b/src/Dialogs/NewBranchDialog.vala @@ -20,8 +20,7 @@ */ public class Scratch.Dialogs.NewBranchDialog : Granite.MessageDialog { - public FolderManager.ProjectFolderItem? active_project { get; construct; } - public unowned List project_list { get; construct; } + public FolderManager.ProjectFolderItem active_project { get; construct; } private Granite.ValidatedEntry new_branch_name_entry; public string new_branch_name { @@ -30,66 +29,54 @@ public class Scratch.Dialogs.NewBranchDialog : Granite.MessageDialog { } } - public NewBranchDialog (FolderManager.ProjectFolderItem? project, List project_list) { + public NewBranchDialog (FolderManager.ProjectFolderItem project) { Object ( transient_for: ((Gtk.Application)(GLib.Application.get_default ())).get_active_window (), active_project: project, - project_list: project_list, image_icon: new ThemedIcon ("git") ); } construct { - if (active_project != null) { - assert (active_project.is_git_repo); - primary_text = _("Create a new branch of “%s/%s”").printf ( - active_project.file.file.get_basename (), - active_project.get_current_branch_name () - ); - ///TRANSLATORS "Git" is a proper name and must not be translated - secondary_text = _("The branch name must comply with Git rules and must not already exist."); - badge_icon = new ThemedIcon ("list-add"); - - new_branch_name_entry = new Granite.ValidatedEntry () { - activates_default = true - }; + assert (active_project.is_git_repo); + add_button (_("Cancel"), Gtk.ResponseType.CANCEL); + primary_text = _("Create a new branch of “%s/%s”").printf ( + active_project.file.file.get_basename (), + active_project.get_current_branch_name () + ); + ///TRANSLATORS "Git" is a proper name and must not be translated + secondary_text = _("The branch name must meet Git requirements and must not already exist."); + badge_icon = new ThemedIcon ("list-add"); - custom_bin.add (new_branch_name_entry); + new_branch_name_entry = new Granite.ValidatedEntry () { + activates_default = true + }; - var create_button = (Gtk.Button) add_button (_("Create Branch"), Gtk.ResponseType.APPLY); - create_button.can_default = true; - create_button.has_default = true; - create_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); + custom_bin.add (new_branch_name_entry); - new_branch_name_entry.bind_property ( - "is-valid", create_button, "sensitive", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE - ); + var create_button = (Gtk.Button) add_button (_("Create Branch"), Gtk.ResponseType.APPLY); + create_button.can_default = true; + create_button.has_default = true; + create_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); - new_branch_name_entry.changed.connect (() => { - unowned var new_name = new_branch_name_entry.text; - if (!active_project.is_valid_new_branch_name (new_name)) { - new_branch_name_entry.is_valid = false; - return; - } + new_branch_name_entry.bind_property ( + "is-valid", create_button, "sensitive", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE + ); - if (active_project.has_local_branch_name (new_name)) { - new_branch_name_entry.is_valid = false; - return; - } + new_branch_name_entry.changed.connect (() => { + unowned var new_name = new_branch_name_entry.text; + if (!active_project.is_valid_new_branch_name (new_name)) { + new_branch_name_entry.is_valid = false; + return; + } - //Do we need to check remote branches as well? - new_branch_name_entry.is_valid = true; - }); - } else { - primary_text = _("You must have an active git project before creating a new branch."); - badge_icon = new ThemedIcon ("dialog-warning"); - if (project_list.length () == 0) { - secondary_text = _("Open a git project folder in the sidebar."); - } else { - secondary_text = _("Open a document in a git project folder in the sidebar or use a project context menu."); + if (active_project.has_local_branch_name (new_name)) { + new_branch_name_entry.is_valid = false; + return; } - } - add_button (_("Cancel"), Gtk.ResponseType.CANCEL); + //Do we need to check remote branches as well? + new_branch_name_entry.is_valid = true; + }); } } diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index e81011a212..e5e287d2bd 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -163,50 +163,21 @@ namespace Scratch.FolderManager { } } - public void new_branch (GLib.File? current_doc_file) { - GLib.List project_list; + public void new_branch (string active_project_path) { string? branch_name = null; - unowned var active_project = get_active_project (current_doc_file, out project_list); - var dialog = new Dialogs.NewBranchDialog (active_project, project_list); + unowned var active_project = (ProjectFolderItem)(find_path (root, active_project_path)); + var dialog = new Dialogs.NewBranchDialog (active_project); dialog.show_all (); if (dialog.run () == Gtk.ResponseType.APPLY) { branch_name = dialog.new_branch_name; } dialog.destroy (); - if (active_project != null && branch_name != null) { + if (branch_name != null) { active_project.new_branch (branch_name); } } - public unowned ProjectFolderItem? get_active_project (GLib.File? active_file, out List project_list) { - unowned ProjectFolderItem? project = null; - project_list = null; - foreach (var child in root.children) { - project = (ProjectFolderItem)child; - if (!project.is_git_repo) { - // Ignore sidebar folders that are not git repos - continue; - } - - if (active_file != null) - if (project.file.file.equal (active_file) || - project.file.file.get_relative_path (active_file) != null) { - - return project; - } - - project_list.prepend (project); - } - - if (project_list.length () == 1) { - //There was only one project so use that - return project_list.data; - } - - return null; - } - private void add_folder (File folder, bool expand) { if (is_open (folder)) { warning ("Folder '%s' is already open.", folder.path); diff --git a/src/MainWindow.vala b/src/MainWindow.vala index a254adccda..4dbc0a3aeb 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -1006,22 +1006,28 @@ namespace Scratch { } private void action_new_branch (SimpleAction action, Variant? param) { - string path = ""; - File? file = null; - if (param != null) { - path = param.get_string (); - } - - if (path == "") { - var current_doc = get_current_document (); - if (current_doc != null) { - file = current_doc.file; - } - } else { - file = File.new_for_path (path); - } - - folder_manager_view.new_branch (file); + folder_manager_view.new_branch (get_target_path_for_git_actions (param)); } + + private string? get_target_path_for_git_actions (Variant? path_variant) { + string? path = ""; + if (path_variant != null) { + path = path_variant.get_string (); + } + + if (path == "") { // Happens when keyboard accelerator is used + path = toolbar.active_project_path; + if (path == null) { + var current_doc = get_current_document (); + if (current_doc != null) { + path = current_doc.file.get_path (); + } else { + return null; // Cannot determine target project + } + } + } + + return path; + } } } diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 2edf30cc48..2d81153f13 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -140,6 +140,27 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { }); } + public void set_active_path (string active_path) { + project_selection_listbox.get_children ().foreach ((child) => { + var project_entry = ((ProjectEntry) child); + if (active_path.has_prefix (project_entry.project_path)) { + select_project (project_entry); + } + }); + } + + public string? get_active_path () { + string? active_path = null; + project_selection_listbox.get_children ().foreach ((child) => { + var project_entry = ((ProjectEntry) child); + if (project_entry.active) { + active_path = project_entry.project_path; + } + }); + + return active_path; + } + public class ProjectEntry : Gtk.ListBoxRow { public string project_path { get; construct; } public string project_name { diff --git a/src/Widgets/HeaderBar.vala b/src/Widgets/HeaderBar.vala index 74f9ec7e39..72c5874378 100644 --- a/src/Widgets/HeaderBar.vala +++ b/src/Widgets/HeaderBar.vala @@ -29,6 +29,16 @@ namespace Scratch.Widgets { public Code.FormatBar format_bar; public Code.ChooseProjectButton choose_project_button; + public string? active_project_path { + owned get { + return choose_project_button.get_active_path (); + } + + set { + choose_project_button.set_active_path (value); + } + } + private const string STYLE_SCHEME_HIGH_CONTRAST = "classic"; private const string STYLE_SCHEME_LIGHT = "solarized-light"; private const string STYLE_SCHEME_DARK = "solarized-dark"; From 5af4ed9973abeadf23341f6e07d61112d7e8fad5 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Sun, 16 May 2021 17:48:50 +0100 Subject: [PATCH 06/28] Use ChooseProjectButton active project for find-global action --- src/MainWindow.vala | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 4dbc0a3aeb..708852eabd 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -876,19 +876,7 @@ namespace Scratch { } private void action_find_global (SimpleAction action, Variant? param) { - string path = ""; - if (param != null) { - path = param.get_string (); - } - - if (path == "") { - var current_doc = get_current_document (); - if (current_doc != null) { - path = current_doc.file.get_path (); - } - } - - folder_manager_view.search_global (path); + folder_manager_view.search_global (get_target_path_for_git_actions (param)); } private void set_search_text () { From 7aefcaa4fea59ced1d8337f1a7873285f0cf15b1 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Sun, 16 May 2021 18:09:36 +0100 Subject: [PATCH 07/28] Fix closing all except * FileView responsible for removing project from GitManager when closed --- src/FolderManager/FileView.vala | 9 ++++++--- src/FolderManager/ProjectFolderItem.vala | 1 - 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index e5e287d2bd..263fcec088 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -187,20 +187,23 @@ namespace Scratch.FolderManager { return; } - var folder_root = new ProjectFolderItem (folder, this); + var folder_root = new ProjectFolderItem (folder, this); // Constructor adds project to GitManager this.root.add (folder_root); folder_root.expanded = expand; folder_root.closed.connect (() => { close_all_docs_from_path (folder_root.file.path); root.remove (folder_root); + Scratch.Services.GitManager.get_instance ().remove_project (folder_root.file.file); write_settings (); }); folder_root.close_all_except.connect (() => { foreach (var child in root.children) { - if (child != folder_root) { - root.remove (child); + var project_folder_item = (ProjectFolderItem)child; + if (project_folder_item != folder_root) { + root.remove (project_folder_item); + Scratch.Services.GitManager.get_instance ().remove_project (project_folder_item.file.file); } } diff --git a/src/FolderManager/ProjectFolderItem.vala b/src/FolderManager/ProjectFolderItem.vala index 77b251f902..ea4914f341 100644 --- a/src/FolderManager/ProjectFolderItem.vala +++ b/src/FolderManager/ProjectFolderItem.vala @@ -99,7 +99,6 @@ namespace Scratch.FolderManager { var close_item = new Gtk.MenuItem.with_label (_("Close Folder")); close_item.activate.connect (() => { closed (); - Scratch.Services.GitManager.get_instance ().remove_project (file.file); }); var close_all_except_item = new Gtk.MenuItem.with_label (_("Close Other Folders")); From 84737c15c620eed80f23db63fb741b56db39d0c0 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Mon, 17 May 2021 09:26:36 +0100 Subject: [PATCH 08/28] ChooseProjectButton: Expand horizontally, add top & bottom margins --- src/Widgets/ChooseProjectButton.vala | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 2d81153f13..79dddc9bc1 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -27,21 +27,20 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { private Scratch.Services.Document? current_doc = null; construct { + margin_top = margin_bottom = 6; + hexpand = true; + img = new Gtk.Image () { gicon = new ThemedIcon ("git-symbolic"), icon_size = Gtk.IconSize.SMALL_TOOLBAR }; - label_widget = new Gtk.Label (_(NO_PROJECT_SELECTED)) { - ellipsize = Pango.EllipsizeMode.END - }; + label_widget = new Gtk.Label (_(NO_PROJECT_SELECTED)); tooltip_text = _("Active Git project"); var grid = new Gtk.Grid () { - halign = Gtk.Align.CENTER, - margin_start = 6, - margin_end = 6 + halign = Gtk.Align.START }; grid.add (img); grid.add (label_widget); From aae4b4e6fa44b06bbcf08a242a6901c18c98931d Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 19 May 2021 13:44:46 +0100 Subject: [PATCH 09/28] ChooseProjectButton: Limit width to 24 chars --- src/Widgets/ChooseProjectButton.vala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 79dddc9bc1..e3b77c8736 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -28,14 +28,16 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { construct { margin_top = margin_bottom = 6; - hexpand = true; img = new Gtk.Image () { gicon = new ThemedIcon ("git-symbolic"), icon_size = Gtk.IconSize.SMALL_TOOLBAR }; - label_widget = new Gtk.Label (_(NO_PROJECT_SELECTED)); + label_widget = new Gtk.Label (_(NO_PROJECT_SELECTED)) { + width_chars = 24, + xalign = 0.0f + }; tooltip_text = _("Active Git project"); From c9a8a16dda2cd612ea3cc8d6028b221cbc9818b6 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 19 May 2021 14:35:07 +0100 Subject: [PATCH 10/28] ChooseProjectButton: Set max chars and ellipsize --- src/Widgets/ChooseProjectButton.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index e3b77c8736..9eee1141af 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -36,6 +36,8 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { label_widget = new Gtk.Label (_(NO_PROJECT_SELECTED)) { width_chars = 24, + ellipsize = Pango.EllipsizeMode.END, + max_width_chars = 24, xalign = 0.0f }; From 21ae87e8a90421dee0ce2ab7f493f5b51cb60180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20For=C3=A9?= Date: Wed, 19 May 2021 10:53:58 -0600 Subject: [PATCH 11/28] ChooseProjectButton: use max_content_height for scrolled (#1038) --- src/Widgets/ChooseProjectButton.vala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 9eee1141af..17dba9f7a8 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -73,10 +73,11 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { var project_scrolled = new Gtk.ScrolledWindow (null, null) { hscrollbar_policy = Gtk.PolicyType.NEVER, - height_request = 350, expand = true, margin_top = 3, - margin_bottom = 3 + margin_bottom = 3, + max_content_height = 350, + propagate_natural_height = true }; project_scrolled.add (project_selection_listbox); From 0881614916f00c059aaaaa294a1c834e79fd43fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20For=C3=A9?= Date: Wed, 19 May 2021 11:34:08 -0600 Subject: [PATCH 12/28] ChooseProjectButton: bind ProjectEntry radio to active (#1040) --- src/Widgets/ChooseProjectButton.vala | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 17dba9f7a8..ca540b81f4 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -166,6 +166,7 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { } public class ProjectEntry : Gtk.ListBoxRow { + public bool active; public string project_path { get; construct; } public string project_name { owned get { @@ -175,16 +176,6 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { public Gtk.RadioButton project_radio { get; construct; } - public bool active { - get { - return project_radio.active; - } - - set { - project_radio.active = value; - } - } - public bool selected { get { return project_radio.active; @@ -210,8 +201,10 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { construct { project_radio = new Gtk.RadioButton.with_label (null, project_name); add (project_radio); - project_radio.toggled.connect (radio_toggled); show_all (); + + bind_property ("active", project_radio, "active", BindingFlags.BIDIRECTIONAL); + project_radio.toggled.connect (radio_toggled); } private void radio_toggled () { From 9154111b8e5f6915dcf3ed7291bcf2acf8cff75f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20For=C3=A9?= Date: Wed, 19 May 2021 11:34:40 -0600 Subject: [PATCH 13/28] ChooseProjectButton: valign center (#1037) --- src/Widgets/ChooseProjectButton.vala | 2 -- src/Widgets/HeaderBar.vala | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index ca540b81f4..cec1f952ee 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -27,8 +27,6 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { private Scratch.Services.Document? current_doc = null; construct { - margin_top = margin_bottom = 6; - img = new Gtk.Image () { gicon = new ThemedIcon ("git-symbolic"), icon_size = Gtk.IconSize.SMALL_TOOLBAR diff --git a/src/Widgets/HeaderBar.vala b/src/Widgets/HeaderBar.vala index 72c5874378..fd70bae6be 100644 --- a/src/Widgets/HeaderBar.vala +++ b/src/Widgets/HeaderBar.vala @@ -53,7 +53,9 @@ namespace Scratch.Widgets { construct { var app_instance = (Scratch.Application) GLib.Application.get_default (); - choose_project_button = new Code.ChooseProjectButton (); + choose_project_button = new Code.ChooseProjectButton () { + valign = Gtk.Align.CENTER + }; var open_button = new Gtk.Button.from_icon_name ("document-open", Gtk.IconSize.LARGE_TOOLBAR); open_button.action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_OPEN; From fdcbf79b399d9797d05dc5685ba064eeb3e5dfc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20For=C3=A9?= Date: Wed, 19 May 2021 11:39:30 -0600 Subject: [PATCH 14/28] ChooseProjectButton: subclass menubutton (#1039) --- src/Widgets/ChooseProjectButton.vala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index cec1f952ee..6809bc8da7 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -16,7 +16,7 @@ * */ -public class Code.ChooseProjectButton : Gtk.ToggleButton { +public class Code.ChooseProjectButton : Gtk.MenuButton { private const string NO_PROJECT_SELECTED = N_("No Project Selected"); private Scratch.Services.GitManager manager; private Gtk.Image img; @@ -91,7 +91,8 @@ public class Code.ChooseProjectButton : Gtk.ToggleButton { }; project_popover.add (popover_content); - this.bind_property ("active", project_popover, "visible", GLib.BindingFlags.BIDIRECTIONAL); + + popover = project_popover; project_selection_listbox.row_activated.connect ((row) => { var project_entry = ((ProjectEntry) row); From 86ba6f6b8045c933e083db1e54bf2c2237102152 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 19 May 2021 18:43:45 +0100 Subject: [PATCH 15/28] ChooseProjectButton.vala: Lose unused code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_radio_group () Co-authored-by: Daniel Foré --- src/Widgets/ChooseProjectButton.vala | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 6809bc8da7..0917ceb598 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -211,9 +211,4 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { activate (); } } - - public unowned SList get_radio_group () { - return project_radio.get_group (); - } - } } From c1040c8697a6e2af66ea9df63b16cab0c15c90e1 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 19 May 2021 18:47:32 +0100 Subject: [PATCH 16/28] Show project path in tooltip --- src/Widgets/ChooseProjectButton.vala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 0917ceb598..814c401f81 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -39,7 +39,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { xalign = 0.0f }; - tooltip_text = _("Active Git project"); + tooltip_text = _("Active Git project: %s").printf (_(NO_PROJECT_SELECTED)); var grid = new Gtk.Grid () { halign = Gtk.Align.START @@ -130,6 +130,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { private void select_project (ProjectEntry project_entry) { project_selection_listbox.select_row (project_entry); label_widget.label = project_entry.project_name; + label_widget.tooltip_text = _("Active Git project: %s").printf (project_entry.project_path); project_entry.selected = true; } From cb09a3f999c9d04a0901ce467d0228fe97c5efd5 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 19 May 2021 18:56:00 +0100 Subject: [PATCH 17/28] Replace missing brace --- src/Widgets/ChooseProjectButton.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 814c401f81..a2539aa4ba 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -212,4 +212,5 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { activate (); } } + } } From b1765ce3d51786a2ce6403206ebdce5a0dea9598 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 19 May 2021 18:57:45 +0100 Subject: [PATCH 18/28] ProjectEntry: Rename to ProjectRow --- src/Widgets/ChooseProjectButton.vala | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index a2539aa4ba..04d2c3bd27 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -22,7 +22,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { private Gtk.Image img; private Gtk.Label label_widget; private Gtk.ListBox project_selection_listbox; - private ProjectEntry? last_entry = null; + private ProjectRow? last_entry = null; private Scratch.Services.Document? current_doc = null; @@ -57,12 +57,12 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { placeholder_text = _("Filter projects") }; project_selection_listbox.set_sort_func ((row1, row2) => { - return ((ProjectEntry) row1).project_name.collate (((ProjectEntry) row2).project_name); + return ((ProjectRow) row1).project_name.collate (((ProjectRow) row2).project_name); }); project_selection_listbox.set_filter_func ((row) => { //Both are lowercased so that the case doesn't matter when comparing. - return (((ProjectEntry) row).project_name.down ().contains (project_selection_filter.text.down ().strip ())); + return (((ProjectRow) row).project_name.down ().contains (project_selection_filter.text.down ().strip ())); }); project_selection_filter.changed.connect (() => { @@ -95,7 +95,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { popover = project_popover; project_selection_listbox.row_activated.connect ((row) => { - var project_entry = ((ProjectEntry) row); + var project_entry = ((ProjectRow) row); select_project (project_entry); }); @@ -117,7 +117,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { } private void add_project (string project_path) { - var project_entry = new ProjectEntry (project_path); + var project_entry = new ProjectRow (project_path); if (last_entry != null) { project_entry.project_radio.join_group (last_entry.project_radio); } @@ -127,7 +127,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { select_project (project_entry); } - private void select_project (ProjectEntry project_entry) { + private void select_project (ProjectRow project_entry) { project_selection_listbox.select_row (project_entry); label_widget.label = project_entry.project_name; label_widget.tooltip_text = _("Active Git project: %s").printf (project_entry.project_path); @@ -137,7 +137,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { public void set_document (Scratch.Services.Document doc) { var path = doc.file.get_path (); project_selection_listbox.get_children ().foreach ((child) => { - var project_entry = ((ProjectEntry) child); + var project_entry = ((ProjectRow) child); if (path.has_prefix (project_entry.project_path)) { select_project (project_entry); } @@ -146,7 +146,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { public void set_active_path (string active_path) { project_selection_listbox.get_children ().foreach ((child) => { - var project_entry = ((ProjectEntry) child); + var project_entry = ((ProjectRow) child); if (active_path.has_prefix (project_entry.project_path)) { select_project (project_entry); } @@ -156,7 +156,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { public string? get_active_path () { string? active_path = null; project_selection_listbox.get_children ().foreach ((child) => { - var project_entry = ((ProjectEntry) child); + var project_entry = ((ProjectRow) child); if (project_entry.active) { active_path = project_entry.project_path; } @@ -165,7 +165,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { return active_path; } - public class ProjectEntry : Gtk.ListBoxRow { + public class ProjectRow : Gtk.ListBoxRow { public bool active; public string project_path { get; construct; } public string project_name { @@ -188,7 +188,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { } } - public ProjectEntry (string project_path) { + public ProjectRow (string project_path) { Object ( project_path: project_path ); From fb0cbcaf13881db14a910f7154b26a08781eb6cc Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 19 May 2021 19:03:25 +0100 Subject: [PATCH 19/28] Remove duplicated code --- src/Widgets/ChooseProjectButton.vala | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 04d2c3bd27..cfcbe86c5c 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -135,13 +135,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { } public void set_document (Scratch.Services.Document doc) { - var path = doc.file.get_path (); - project_selection_listbox.get_children ().foreach ((child) => { - var project_entry = ((ProjectRow) child); - if (path.has_prefix (project_entry.project_path)) { - select_project (project_entry); - } - }); + set_active_path (doc.file.get_path ()); } public void set_active_path (string active_path) { From f3efbf7da18bcc2323da58d11a18904d9cc86712 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 19 May 2021 19:04:27 +0100 Subject: [PATCH 20/28] Update src/Widgets/ChooseProjectButton.vala MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniel Foré --- src/Widgets/ChooseProjectButton.vala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index cfcbe86c5c..16c0005dc9 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -94,6 +94,10 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { popover = project_popover; + var hsizegroup = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL); + hsizegroup.add_widget (this); + hsizegroup.add_widget (project_selection_listbox); + project_selection_listbox.row_activated.connect ((row) => { var project_entry = ((ProjectRow) row); select_project (project_entry); From 99248a183f5dd9cb685c71fbe9915c2ecd9085ac Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 19 May 2021 19:06:52 +0100 Subject: [PATCH 21/28] Update src/Widgets/ChooseProjectButton.vala: Explict get/set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniel Foré --- src/Widgets/ChooseProjectButton.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 16c0005dc9..b2ad5bda8d 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -164,7 +164,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { } public class ProjectRow : Gtk.ListBoxRow { - public bool active; + public bool active { get; set; } public string project_path { get; construct; } public string project_name { owned get { From 014c05d7585524fb46ff76b9cb0e2fc02595eb86 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 19 May 2021 19:14:02 +0100 Subject: [PATCH 22/28] More concise names --- src/Widgets/ChooseProjectButton.vala | 36 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index b2ad5bda8d..84afb5bfea 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -21,7 +21,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { private Scratch.Services.GitManager manager; private Gtk.Image img; private Gtk.Label label_widget; - private Gtk.ListBox project_selection_listbox; + private Gtk.ListBox project_listbox; private ProjectRow? last_entry = null; private Scratch.Services.Document? current_doc = null; @@ -48,25 +48,25 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { grid.add (label_widget); add (grid); - project_selection_listbox = new Gtk.ListBox () { + project_listbox = new Gtk.ListBox () { selection_mode = Gtk.SelectionMode.SINGLE }; - var project_selection_filter = new Gtk.SearchEntry () { + var project_filter = new Gtk.SearchEntry () { margin = 12, margin_bottom = 6, placeholder_text = _("Filter projects") }; - project_selection_listbox.set_sort_func ((row1, row2) => { + project_listbox.set_sort_func ((row1, row2) => { return ((ProjectRow) row1).project_name.collate (((ProjectRow) row2).project_name); }); - project_selection_listbox.set_filter_func ((row) => { + project_listbox.set_filter_func ((row) => { //Both are lowercased so that the case doesn't matter when comparing. - return (((ProjectRow) row).project_name.down ().contains (project_selection_filter.text.down ().strip ())); + return (((ProjectRow) row).project_name.down ().contains (project_filter.text.down ().strip ())); }); - project_selection_filter.changed.connect (() => { - project_selection_listbox.invalidate_filter (); + project_filter.changed.connect (() => { + project_listbox.invalidate_filter (); }); var project_scrolled = new Gtk.ScrolledWindow (null, null) { @@ -78,10 +78,10 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { propagate_natural_height = true }; - project_scrolled.add (project_selection_listbox); + project_scrolled.add (project_listbox); var popover_content = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); - popover_content.add (project_selection_filter); + popover_content.add (project_filter); popover_content.add (project_scrolled); popover_content.show_all (); @@ -96,9 +96,9 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { var hsizegroup = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL); hsizegroup.add_widget (this); - hsizegroup.add_widget (project_selection_listbox); + hsizegroup.add_widget (project_listbox); - project_selection_listbox.row_activated.connect ((row) => { + project_listbox.row_activated.connect ((row) => { var project_entry = ((ProjectRow) row); select_project (project_entry); }); @@ -107,8 +107,8 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { manager.project_added.connect (add_project); manager.project_removed.connect ((project_path) => { - project_selection_listbox.get_children ().foreach ((child) => { - project_selection_listbox.remove (child); + project_listbox.get_children ().foreach ((child) => { + project_listbox.remove (child); }); label_widget.label = _(NO_PROJECT_SELECTED); @@ -127,12 +127,12 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { } last_entry = project_entry; - project_selection_listbox.add (project_entry); + project_listbox.add (project_entry); select_project (project_entry); } private void select_project (ProjectRow project_entry) { - project_selection_listbox.select_row (project_entry); + project_listbox.select_row (project_entry); label_widget.label = project_entry.project_name; label_widget.tooltip_text = _("Active Git project: %s").printf (project_entry.project_path); project_entry.selected = true; @@ -143,7 +143,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { } public void set_active_path (string active_path) { - project_selection_listbox.get_children ().foreach ((child) => { + project_listbox.get_children ().foreach ((child) => { var project_entry = ((ProjectRow) child); if (active_path.has_prefix (project_entry.project_path)) { select_project (project_entry); @@ -153,7 +153,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { public string? get_active_path () { string? active_path = null; - project_selection_listbox.get_children ().foreach ((child) => { + project_listbox.get_children ().foreach ((child) => { var project_entry = ((ProjectRow) child); if (project_entry.active) { active_path = project_entry.project_path; From 4219468344b93527deb7ad1c9bda24f543e53195 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 19 May 2021 19:17:51 +0100 Subject: [PATCH 23/28] Reduce scope if `img` --- src/Widgets/ChooseProjectButton.vala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 84afb5bfea..1f2096c930 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -19,7 +19,6 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { private const string NO_PROJECT_SELECTED = N_("No Project Selected"); private Scratch.Services.GitManager manager; - private Gtk.Image img; private Gtk.Label label_widget; private Gtk.ListBox project_listbox; private ProjectRow? last_entry = null; @@ -27,7 +26,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { private Scratch.Services.Document? current_doc = null; construct { - img = new Gtk.Image () { + var img = new Gtk.Image () { gicon = new ThemedIcon ("git-symbolic"), icon_size = Gtk.IconSize.SMALL_TOOLBAR }; From 122028ab55e636396f2fbdd88f9273abe844d52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20For=C3=A9?= Date: Thu, 20 May 2021 03:07:30 -0600 Subject: [PATCH 24/28] ChooseProjectButton: use a liststore to populate project list (#1042) * ChooseProjectButton: use a liststore to populate project list * scope down manager * smaller diff * remove unused method --- src/Services/GitManager.vala | 29 ++++++++++++++------- src/Widgets/ChooseProjectButton.vala | 39 ++++++++-------------------- 2 files changed, 30 insertions(+), 38 deletions(-) diff --git a/src/Services/GitManager.vala b/src/Services/GitManager.vala index 4c8bb6b054..e71fd021f6 100644 --- a/src/Services/GitManager.vala +++ b/src/Services/GitManager.vala @@ -20,6 +20,8 @@ namespace Scratch.Services { public class GitManager : Object { + public ListStore project_liststore { get; private set; } + static Gee.HashMap project_gitrepo_map; static GitManager? instance; @@ -37,10 +39,9 @@ namespace Scratch.Services { return instance; } - public signal void project_added (string root_path); - public signal void project_removed (string root_path); - - private GitManager () {} + private GitManager () { + project_liststore = new ListStore (typeof (File)); + } public MonitoredRepository? add_project (GLib.File root_folder) { var root_path = root_folder.get_path (); @@ -53,7 +54,7 @@ namespace Scratch.Services { var monitored_repo = new MonitoredRepository (git_repo); project_gitrepo_map.@set (root_path, monitored_repo); - project_added (root_path); + project_liststore.insert_sorted (root_folder, (CompareDataFunc) project_sort_func); return project_gitrepo_map.@get (root_path); } catch (Error e) { debug ("Error opening git repo for %s, means this probably isn't one: %s", root_path, e.message); @@ -61,16 +62,24 @@ namespace Scratch.Services { } } + [CCode (instance_pos = -1)] + private int project_sort_func (File a, File b) { + return Path.get_basename (a.get_path ()).collate (Path.get_basename (b.get_path ())); + } + public void remove_project (GLib.File root_folder) { var root_path = root_folder.get_path (); + + uint position; + if (project_liststore.find (root_folder, out position)) { + project_liststore.remove (position); + } else { + critical ("Can't remove: %s", root_path); + } + if (project_gitrepo_map.has_key (root_path)) { project_gitrepo_map.unset (root_path); - project_removed (root_path); } } - - public string[] get_project_paths () { - return project_gitrepo_map.keys.to_array (); - } } } diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 1f2096c930..5892a89e4b 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -18,13 +18,10 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { private const string NO_PROJECT_SELECTED = N_("No Project Selected"); - private Scratch.Services.GitManager manager; private Gtk.Label label_widget; private Gtk.ListBox project_listbox; private ProjectRow? last_entry = null; - private Scratch.Services.Document? current_doc = null; - construct { var img = new Gtk.Image () { gicon = new ThemedIcon ("git-symbolic"), @@ -55,9 +52,6 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { margin_bottom = 6, placeholder_text = _("Filter projects") }; - project_listbox.set_sort_func ((row1, row2) => { - return ((ProjectRow) row1).project_name.collate (((ProjectRow) row2).project_name); - }); project_listbox.set_filter_func ((row) => { //Both are lowercased so that the case doesn't matter when comparing. @@ -97,37 +91,26 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { hsizegroup.add_widget (this); hsizegroup.add_widget (project_listbox); + project_listbox.bind_model ( + Scratch.Services.GitManager.get_instance ().project_liststore, + create_project_row + ); + project_listbox.row_activated.connect ((row) => { var project_entry = ((ProjectRow) row); select_project (project_entry); }); - - manager = Scratch.Services.GitManager.get_instance (); - manager.project_added.connect (add_project); - - manager.project_removed.connect ((project_path) => { - project_listbox.get_children ().foreach ((child) => { - project_listbox.remove (child); - }); - - label_widget.label = _(NO_PROJECT_SELECTED); - foreach (string path in manager.get_project_paths ()) { - add_project (path); - } - - set_document (current_doc); - }); } - private void add_project (string project_path) { - var project_entry = new ProjectRow (project_path); + private Gtk.Widget create_project_row (GLib.Object object) { + unowned var project_folder = (File) object; + var project_row = new ProjectRow (project_folder.get_path ()); if (last_entry != null) { - project_entry.project_radio.join_group (last_entry.project_radio); + project_row.project_radio.join_group (last_entry.project_radio); } + last_entry = project_row; - last_entry = project_entry; - project_listbox.add (project_entry); - select_project (project_entry); + return project_row; } private void select_project (ProjectRow project_entry) { From 02570fbb0be31bfa73847d5c1292103e9c608e21 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Thu, 20 May 2021 10:23:06 +0100 Subject: [PATCH 25/28] Update src/Widgets/HeaderBar.vala: remove unused setter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniel Foré --- src/Widgets/HeaderBar.vala | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Widgets/HeaderBar.vala b/src/Widgets/HeaderBar.vala index fd70bae6be..f954560c0a 100644 --- a/src/Widgets/HeaderBar.vala +++ b/src/Widgets/HeaderBar.vala @@ -33,10 +33,6 @@ namespace Scratch.Widgets { owned get { return choose_project_button.get_active_path (); } - - set { - choose_project_button.set_active_path (value); - } } private const string STYLE_SCHEME_HIGH_CONTRAST = "classic"; From 219c9858fef3d5ce037b85d809507e88adc79437 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Thu, 20 May 2021 17:40:18 +0100 Subject: [PATCH 26/28] GitManager: source of truth for active_project_path (#1044) --- src/MainWindow.vala | 2 +- src/Services/GitManager.vala | 1 + src/Widgets/ChooseProjectButton.vala | 13 +------------ src/Widgets/HeaderBar.vala | 6 ------ 4 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 708852eabd..cf6f8fedd6 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -1004,7 +1004,7 @@ namespace Scratch { } if (path == "") { // Happens when keyboard accelerator is used - path = toolbar.active_project_path; + path = Services.GitManager.get_instance ().active_project_path; if (path == null) { var current_doc = get_current_document (); if (current_doc != null) { diff --git a/src/Services/GitManager.vala b/src/Services/GitManager.vala index e71fd021f6..74ba6b96ec 100644 --- a/src/Services/GitManager.vala +++ b/src/Services/GitManager.vala @@ -21,6 +21,7 @@ namespace Scratch.Services { public class GitManager : Object { public ListStore project_liststore { get; private set; } + public string active_project_path { get; set; default = "";} static Gee.HashMap project_gitrepo_map; static GitManager? instance; diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 5892a89e4b..9b2beb3a54 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -118,6 +118,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { label_widget.label = project_entry.project_name; label_widget.tooltip_text = _("Active Git project: %s").printf (project_entry.project_path); project_entry.selected = true; + Scratch.Services.GitManager.get_instance ().active_project_path = project_entry.project_path; } public void set_document (Scratch.Services.Document doc) { @@ -133,18 +134,6 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { }); } - public string? get_active_path () { - string? active_path = null; - project_listbox.get_children ().foreach ((child) => { - var project_entry = ((ProjectRow) child); - if (project_entry.active) { - active_path = project_entry.project_path; - } - }); - - return active_path; - } - public class ProjectRow : Gtk.ListBoxRow { public bool active { get; set; } public string project_path { get; construct; } diff --git a/src/Widgets/HeaderBar.vala b/src/Widgets/HeaderBar.vala index f954560c0a..de045cefcd 100644 --- a/src/Widgets/HeaderBar.vala +++ b/src/Widgets/HeaderBar.vala @@ -29,12 +29,6 @@ namespace Scratch.Widgets { public Code.FormatBar format_bar; public Code.ChooseProjectButton choose_project_button; - public string? active_project_path { - owned get { - return choose_project_button.get_active_path (); - } - } - private const string STYLE_SCHEME_HIGH_CONTRAST = "classic"; private const string STYLE_SCHEME_LIGHT = "solarized-light"; private const string STYLE_SCHEME_DARK = "solarized-dark"; From 0685c5a3fc484bb44e59ce1c7cd5efc431a63006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20For=C3=A9?= Date: Thu, 20 May 2021 11:46:38 -0600 Subject: [PATCH 27/28] ChooseProjectButton: simplify ProjectRow click handling (#1041) * ChooseProjectButton: simplify ProjectRow click handling * actual fix --- src/Widgets/ChooseProjectButton.vala | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 9b2beb3a54..bbe128171d 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -117,7 +117,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { project_listbox.select_row (project_entry); label_widget.label = project_entry.project_name; label_widget.tooltip_text = _("Active Git project: %s").printf (project_entry.project_path); - project_entry.selected = true; + project_entry.active = true; Scratch.Services.GitManager.get_instance ().active_project_path = project_entry.project_path; } @@ -145,18 +145,6 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { public Gtk.RadioButton project_radio { get; construct; } - public bool selected { - get { - return project_radio.active; - } - - set { - project_radio.toggled.disconnect (radio_toggled); - project_radio.active = value; - project_radio.toggled.connect (radio_toggled); - } - } - public ProjectRow (string project_path) { Object ( project_path: project_path @@ -173,13 +161,11 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { show_all (); bind_property ("active", project_radio, "active", BindingFlags.BIDIRECTIONAL); - project_radio.toggled.connect (radio_toggled); - } - private void radio_toggled () { - if (project_radio.active) { + project_radio.button_release_event.connect (() => { activate (); - } + return Gdk.EVENT_PROPAGATE; + }); } } } From 6bf871642fec1b9cc0db5873a15c3db68f78c7a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20For=C3=A9?= Date: Fri, 21 May 2021 11:26:53 -0600 Subject: [PATCH 28/28] Allow non-git projects to fix global search (#1045) --- src/FolderManager/FileView.vala | 7 ++++++- src/Services/GitManager.vala | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index 263fcec088..fccdd65b2f 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -164,8 +164,13 @@ namespace Scratch.FolderManager { } public void new_branch (string active_project_path) { - string? branch_name = null; unowned var active_project = (ProjectFolderItem)(find_path (root, active_project_path)); + if (active_project == null || !active_project.is_git_repo) { + Gdk.beep (); + return; + } + + string? branch_name = null; var dialog = new Dialogs.NewBranchDialog (active_project); dialog.show_all (); if (dialog.run () == Gtk.ResponseType.APPLY) { diff --git a/src/Services/GitManager.vala b/src/Services/GitManager.vala index 74ba6b96ec..0318c6420f 100644 --- a/src/Services/GitManager.vala +++ b/src/Services/GitManager.vala @@ -45,6 +45,8 @@ namespace Scratch.Services { } public MonitoredRepository? add_project (GLib.File root_folder) { + project_liststore.insert_sorted (root_folder, (CompareDataFunc) project_sort_func); + var root_path = root_folder.get_path (); try { var git_repo = Ggit.Repository.open (root_folder); @@ -55,7 +57,6 @@ namespace Scratch.Services { var monitored_repo = new MonitoredRepository (git_repo); project_gitrepo_map.@set (root_path, monitored_repo); - project_liststore.insert_sorted (root_folder, (CompareDataFunc) project_sort_func); return project_gitrepo_map.@get (root_path); } catch (Error e) { debug ("Error opening git repo for %s, means this probably isn't one: %s", root_path, e.message);