From 3aff2cc0c5e8a732fa10f1b89eae1c86064ebf94 Mon Sep 17 00:00:00 2001 From: Jeremy Paul Wootten Date: Sat, 9 Oct 2021 10:50:33 +0100 Subject: [PATCH 1/9] Hide non-active documents when project manually chosen --- src/FolderManager/FileView.vala | 52 ++++++++++++++++++++++-- src/FolderManager/ProjectFolderItem.vala | 1 + src/MainWindow.vala | 22 ++++++++-- src/Widgets/ChooseProjectButton.vala | 3 ++ 4 files changed, 71 insertions(+), 7 deletions(-) diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index fd8fdcd809..1e897fa0b2 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -19,14 +19,18 @@ */ namespace Scratch.FolderManager { + public delegate void DocumentCallback (ProjectFolderItem folder, Scratch.Services.Document doc); /** * SourceList that displays folders and their contents. */ public class FileView : Granite.Widgets.SourceList, Code.PaneSwitcher { + private GLib.Settings settings; + private Scratch.Services.GitManager git_manager; public signal void select (string file); - public signal void close_all_docs_from_path (string path); + public signal void close_all_docs_from_folder (ProjectFolderItem folder, DocumentCallback? callback = null); + public signal void restore_document (Scratch.Services.Document doc); // This is a workaround for SourceList silliness: you cannot remove an item // without it automatically selecting another one. @@ -42,6 +46,8 @@ namespace Scratch.FolderManager { item_selected.connect (on_item_selected); settings = new GLib.Settings ("io.elementary.code.folder-manager"); + + git_manager = Scratch.Services.GitManager.get_instance (); } private void on_item_selected (Granite.Widgets.SourceList.Item? item) { @@ -82,6 +88,44 @@ namespace Scratch.FolderManager { } } + public void collapse_other_projects (string? keep_open_path = null) { + unowned string path; + if (keep_open_path == null) { + path = git_manager.active_project_path; + } else { + path = keep_open_path; + git_manager.active_project_path = path; + } + + foreach (var child in root.children) { + var project_folder = ((ProjectFolderItem) child); + if (project_folder.expanded && project_folder.file.path != path) { + project_folder.expanded = false; + project_folder.restorable_doc_list = null; + close_all_docs_from_folder (project_folder, make_restorable); + } else { + project_folder.expanded = true; + restore_project_docs (project_folder); + } + } + } + + private void make_restorable (ProjectFolderItem folder, Scratch.Services.Document doc) { + folder.restorable_doc_list.prepend (doc); + } + + private void restore_project_docs (ProjectFolderItem folder) { + folder.restorable_doc_list.@foreach ((doc) => { + restore_document (doc); + }); + } + + public void restore_all_docs () { + foreach (var child in root.children) { + restore_project_docs (((ProjectFolderItem) child)); + } + } + public void order_folders () { var list = new Gee.ArrayList (); @@ -210,9 +254,9 @@ namespace Scratch.FolderManager { folder_root.expanded = expand; folder_root.closed.connect (() => { - close_all_docs_from_path (folder_root.file.path); + close_all_docs_from_folder (folder_root); root.remove (folder_root); - Scratch.Services.GitManager.get_instance ().remove_project (folder_root.file.file); + git_manager.remove_project (folder_root.file.file); write_settings (); }); @@ -221,7 +265,7 @@ namespace Scratch.FolderManager { 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); + git_manager.remove_project (project_folder_item.file.file); } } diff --git a/src/FolderManager/ProjectFolderItem.vala b/src/FolderManager/ProjectFolderItem.vala index edd216c8ea..bfbe513e52 100644 --- a/src/FolderManager/ProjectFolderItem.vala +++ b/src/FolderManager/ProjectFolderItem.vala @@ -33,6 +33,7 @@ namespace Scratch.FolderManager { public Scratch.Services.MonitoredRepository? monitored_repo { get; private set; default = null; } // Cache the visible item in the project. private List visible_item_list = null; + public List restorable_doc_list = null; public string top_level_path { get; construct; } public bool is_git_repo { get { diff --git a/src/MainWindow.vala b/src/MainWindow.vala index bb7f3142c3..7b3d38ec33 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -279,6 +279,10 @@ namespace Scratch { toolbar = new Scratch.Widgets.HeaderBar (); toolbar.title = title; + toolbar.choose_project_button.project_chosen.connect (() => { + folder_manager_view.collapse_other_projects (); + }); + // SearchBar search_bar = new Scratch.Widgets.SearchBar (this); search_revealer = new Gtk.Revealer (); @@ -335,15 +339,23 @@ namespace Scratch { } }); - folder_manager_view.close_all_docs_from_path.connect ((a) => { + folder_manager_view.close_all_docs_from_folder.connect ((folder_item, callback) => { var docs = document_view.docs.copy (); + var folder_path = folder_item.file.path; docs.foreach ((doc) => { - if (doc.file.get_path ().has_prefix (a)) { + if (doc.file.get_path ().has_prefix (folder_path)) { document_view.close_document (doc); + if (callback != null) { + callback (folder_item, doc); + } } }); }); + folder_manager_view.restore_document.connect ((doc) => { + document_view.open_document (doc, true, -1); + }); + folder_manager_view.restore_saved_state (); bottombar = new Gtk.Notebook (); @@ -559,7 +571,10 @@ namespace Scratch { folder_manager_view.open_folder (foldermanager_file); } - public void open_document (Scratch.Services.Document doc, bool focus = true, int cursor_position = 0) { + public void open_document (Scratch.Services.Document doc, + bool focus = true, + int cursor_position = 0) { + FolderManager.ProjectFolderItem? project = folder_manager_view.get_project_for_file (doc.file); doc.source_view.project = project; document_view.open_document (doc, focus, cursor_position); @@ -635,6 +650,7 @@ namespace Scratch { // For exit cleanup private void handle_quit () { + folder_manager_view.restore_all_docs (); document_view.save_opened_files (); update_saved_state (); } diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 369a8eb78f..a0fb6ce78c 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -22,6 +22,8 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { private Gtk.ListBox project_listbox; private ProjectRow? last_entry = null; + public signal void project_chosen (); + construct { var img = new Gtk.Image () { gicon = new ThemedIcon ("git-symbolic"), @@ -105,6 +107,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { project_listbox.row_activated.connect ((row) => { var project_entry = ((ProjectRow) row); select_project (project_entry); + project_chosen (); }); } From 4086f72942aa5fd94af4282cafa3ab22b5502683 Mon Sep 17 00:00:00 2001 From: Jeremy Paul Wootten Date: Mon, 11 Oct 2021 14:33:07 +0100 Subject: [PATCH 2/9] Use MainWindow action, add context menu items --- src/FolderManager/FileView.vala | 39 +++++--------- src/FolderManager/ProjectFolderItem.vala | 26 ++++++++- src/MainWindow.vala | 67 ++++++++++++++++++++---- 3 files changed, 95 insertions(+), 37 deletions(-) diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index 1e897fa0b2..29eee4ceb6 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -24,19 +24,23 @@ namespace Scratch.FolderManager { * SourceList that displays folders and their contents. */ public class FileView : Granite.Widgets.SourceList, Code.PaneSwitcher { - private GLib.Settings settings; private Scratch.Services.GitManager git_manager; public signal void select (string file); - public signal void close_all_docs_from_folder (ProjectFolderItem folder, DocumentCallback? callback = null); - public signal void restore_document (Scratch.Services.Document doc); + public signal void close_project_docs (string project_path); + public signal void restore_project_docs (string project_path); // This is a workaround for SourceList silliness: you cannot remove an item // without it automatically selecting another one. public bool ignore_next_select { get; set; default = false; } public string icon_name { get; set; } public string title { get; set; } + public string active_project_path { + get { + return git_manager.active_project_path; + } + } construct { width_request = 180; @@ -99,33 +103,18 @@ namespace Scratch.FolderManager { foreach (var child in root.children) { var project_folder = ((ProjectFolderItem) child); - if (project_folder.expanded && project_folder.file.path != path) { + if (project_folder.expanded && + project_folder.file.path != path) { + project_folder.expanded = false; - project_folder.restorable_doc_list = null; - close_all_docs_from_folder (project_folder, make_restorable); - } else { + close_project_docs (project_folder.file.path); + } else if (project_folder.file.path == path) { project_folder.expanded = true; - restore_project_docs (project_folder); + restore_project_docs (project_folder.file.path); } } } - private void make_restorable (ProjectFolderItem folder, Scratch.Services.Document doc) { - folder.restorable_doc_list.prepend (doc); - } - - private void restore_project_docs (ProjectFolderItem folder) { - folder.restorable_doc_list.@foreach ((doc) => { - restore_document (doc); - }); - } - - public void restore_all_docs () { - foreach (var child in root.children) { - restore_project_docs (((ProjectFolderItem) child)); - } - } - public void order_folders () { var list = new Gee.ArrayList (); @@ -254,7 +243,7 @@ namespace Scratch.FolderManager { folder_root.expanded = expand; folder_root.closed.connect (() => { - close_all_docs_from_folder (folder_root); + close_project_docs (folder_root.file.path); root.remove (folder_root); git_manager.remove_project (folder_root.file.file); write_settings (); diff --git a/src/FolderManager/ProjectFolderItem.vala b/src/FolderManager/ProjectFolderItem.vala index bfbe513e52..3e76ff14e0 100644 --- a/src/FolderManager/ProjectFolderItem.vala +++ b/src/FolderManager/ProjectFolderItem.vala @@ -33,7 +33,6 @@ namespace Scratch.FolderManager { public Scratch.Services.MonitoredRepository? monitored_repo { get; private set; default = null; } // Cache the visible item in the project. private List visible_item_list = null; - public List restorable_doc_list = null; public string top_level_path { get; construct; } public bool is_git_repo { get { @@ -113,6 +112,26 @@ namespace Scratch.FolderManager { close_all_except_item.activate.connect (() => { close_all_except (); }); close_all_except_item.sensitive = view.root.children.size > 1; + var hide_accellabel = new Granite.AccelLabel.from_action_name ( + _("Hide Open Documents"), + MainWindow.ACTION_PREFIX + MainWindow.ACTION_HIDE_PROJECT_DOCS + "::" + ); + var hide_item = new Gtk.MenuItem () { + action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_HIDE_PROJECT_DOCS, + action_target = new Variant.string (file.file.get_path ()) + }; + hide_item.add (hide_accellabel); + + var restore_accellabel = new Granite.AccelLabel.from_action_name ( + _("Restore Hidden Documents"), + MainWindow.ACTION_PREFIX + MainWindow.ACTION_RESTORE_PROJECT_DOCS + "::" + ); + var restore_item = new Gtk.MenuItem () { + action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_RESTORE_PROJECT_DOCS, + action_target = new Variant.string (file.file.get_path ()) + }; + restore_item.add (restore_accellabel); + var delete_item = new Gtk.MenuItem.with_label (_("Move to Trash")); delete_item.activate.connect (() => { closed (); @@ -125,7 +144,7 @@ namespace Scratch.FolderManager { ); var search_item = new Gtk.MenuItem () { - action_name = "win.action_find_global", + action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_FIND_GLOBAL, action_target = new Variant.string (file.file.get_path ()) }; search_item.add (search_accellabel); @@ -155,6 +174,9 @@ namespace Scratch.FolderManager { menu.append (new Gtk.SeparatorMenuItem ()); menu.append (close_item); menu.append (close_all_except_item); + menu.append (hide_item); + menu.append (restore_item); + menu.append (new Gtk.SeparatorMenuItem ()); menu.append (delete_item); menu.append (new Gtk.SeparatorMenuItem ()); menu.append (search_item); diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 7b3d38ec33..75ad65f0b2 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -34,6 +34,7 @@ namespace Scratch { public Scratch.Widgets.SearchBar search_bar; private Code.WelcomeView welcome_view; private FolderManager.FileView folder_manager_view; + private Gee.HashMultiMap project_doc_map; // Plugins private Scratch.Services.PluginsManager plugins; @@ -90,6 +91,8 @@ namespace Scratch { public const string ACTION_PREVIOUS_TAB = "action_previous_tab"; public const string ACTION_CLEAR_LINES = "action_clear_lines"; public const string ACTION_NEW_BRANCH = "action_new_branch"; + public const string ACTION_HIDE_PROJECT_DOCS = "action_hide_project_docs"; + public const string ACTION_RESTORE_PROJECT_DOCS = "action_restore_project_docs"; public static Gee.MultiMap action_accelerators = new Gee.HashMultiMap (); @@ -129,7 +132,9 @@ namespace Scratch { { ACTION_NEXT_TAB, action_next_tab }, { ACTION_PREVIOUS_TAB, action_previous_tab }, { ACTION_CLEAR_LINES, action_clear_lines }, - { ACTION_NEW_BRANCH, action_new_branch, "s" } + { ACTION_NEW_BRANCH, action_new_branch, "s" }, + { ACTION_HIDE_PROJECT_DOCS, action_hide_project_docs, "s"}, + { ACTION_RESTORE_PROJECT_DOCS, action_restore_project_docs, "s"} }; public MainWindow (Scratch.Application scratch_app) { @@ -176,6 +181,8 @@ namespace Scratch { action_accelerators.set (ACTION_PREVIOUS_TAB, "Tab"); action_accelerators.set (ACTION_CLEAR_LINES, "K"); //Geany action_accelerators.set (ACTION_NEW_BRANCH + "::", "B"); + action_accelerators.set (ACTION_HIDE_PROJECT_DOCS + "::", "h"); + action_accelerators.set (ACTION_RESTORE_PROJECT_DOCS + "::", "r"); var provider = new Gtk.CssProvider (); provider.load_from_resource ("io/elementary/code/Application.css"); @@ -190,6 +197,8 @@ namespace Scratch { weak Gtk.IconTheme default_theme = Gtk.IconTheme.get_default (); default_theme.add_resource_path ("/io/elementary/code"); + project_doc_map = new Gee.HashMultiMap (); + actions = new SimpleActionGroup (); actions.add_action_entries (ACTION_ENTRIES, this); insert_action_group ("win", actions); @@ -339,21 +348,35 @@ namespace Scratch { } }); - folder_manager_view.close_all_docs_from_folder.connect ((folder_item, callback) => { - var docs = document_view.docs.copy (); - var folder_path = folder_item.file.path; + folder_manager_view.close_project_docs.connect ((project_path) => { + if (project_path == "") { + return; + } + + unowned var docs = document_view.docs; docs.foreach ((doc) => { - if (doc.file.get_path ().has_prefix (folder_path)) { + if (doc.file.get_path ().has_prefix (project_path)) { document_view.close_document (doc); - if (callback != null) { - callback (folder_item, doc); + if (!project_doc_map.contains (project_path) || + !project_doc_map.@get (project_path).contains (doc.file.get_path ())) { + + project_doc_map.@set (project_path, doc.file.get_path ()); } } }); }); - folder_manager_view.restore_document.connect ((doc) => { - document_view.open_document (doc, true, -1); + folder_manager_view.restore_project_docs.connect ((project_path) => { + if (project_path == "") { + return; + } + + project_doc_map.@get (project_path).@foreach ((doc_path) => { + var doc = new Scratch.Services.Document (actions, File.new_for_path (doc_path)); + document_view.open_document (doc); + return true; + }); + }); folder_manager_view.restore_saved_state (); @@ -650,7 +673,6 @@ namespace Scratch { // For exit cleanup private void handle_quit () { - folder_manager_view.restore_all_docs (); document_view.save_opened_files (); update_saved_state (); } @@ -873,6 +895,31 @@ namespace Scratch { } } + private void action_hide_project_docs (SimpleAction action, Variant? param) { + string project_path = ""; + if (param == null || param.get_string () == "") { + var doc = get_current_document (); + if (doc != null) { + project_path = folder_manager_view.get_project_for_file (doc.file).file.path; + } + } else { + project_path = param.get_string (); + } + + folder_manager_view.close_project_docs (project_path); + } + + private void action_restore_project_docs (SimpleAction action, Variant? param) { + string project_path = ""; + if (param == null || param.get_string () == "") { + project_path = folder_manager_view.active_project_path; + } else { + project_path = param.get_string (); + } + + folder_manager_view.restore_project_docs (project_path); + } + /** Not a toggle action - linked to keyboard short cut (Ctrl-f). **/ private string current_search_term = ""; private void action_fetch (SimpleAction action, Variant? param) { From 3df2c5793005f4e0a4da638a368ebf7f6d966b25 Mon Sep 17 00:00:00 2001 From: Jeremy Paul Wootten Date: Mon, 11 Oct 2021 15:55:36 +0100 Subject: [PATCH 3/9] Add DocumentManager service; add close project docs action --- src/FolderManager/FileView.vala | 3 +- src/FolderManager/ProjectFolderItem.vala | 18 ++++- src/MainWindow.vala | 83 +++++++++++------------- src/Services/DocumentManager.vala | 45 +++++++++++++ src/meson.build | 1 + 5 files changed, 100 insertions(+), 50 deletions(-) create mode 100644 src/Services/DocumentManager.vala diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index 29eee4ceb6..07e745aa49 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -28,6 +28,7 @@ namespace Scratch.FolderManager { private Scratch.Services.GitManager git_manager; public signal void select (string file); + public signal void hide_project_docs (string project_path); public signal void close_project_docs (string project_path); public signal void restore_project_docs (string project_path); @@ -107,7 +108,7 @@ namespace Scratch.FolderManager { project_folder.file.path != path) { project_folder.expanded = false; - close_project_docs (project_folder.file.path); + hide_project_docs (project_folder.file.path); } else if (project_folder.file.path == path) { project_folder.expanded = true; restore_project_docs (project_folder.file.path); diff --git a/src/FolderManager/ProjectFolderItem.vala b/src/FolderManager/ProjectFolderItem.vala index 3e76ff14e0..bb49e58304 100644 --- a/src/FolderManager/ProjectFolderItem.vala +++ b/src/FolderManager/ProjectFolderItem.vala @@ -103,8 +103,8 @@ namespace Scratch.FolderManager { } public override Gtk.Menu? get_context_menu () { - var close_item = new Gtk.MenuItem.with_label (_("Close Folder")); - close_item.activate.connect (() => { + var close_folder_item = new Gtk.MenuItem.with_label (_("Close Folder")); + close_folder_item.activate.connect (() => { closed (); }); @@ -112,6 +112,16 @@ namespace Scratch.FolderManager { close_all_except_item.activate.connect (() => { close_all_except (); }); close_all_except_item.sensitive = view.root.children.size > 1; + var close_accellabel = new Granite.AccelLabel.from_action_name ( + _("Close Open Documents"), + MainWindow.ACTION_PREFIX + MainWindow.ACTION_CLOSE_PROJECT_DOCS + "::" + ); + var close_item = new Gtk.MenuItem () { + action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_CLOSE_PROJECT_DOCS, + action_target = new Variant.string (file.file.get_path ()) + }; + close_item.add (close_accellabel); + var hide_accellabel = new Granite.AccelLabel.from_action_name ( _("Hide Open Documents"), MainWindow.ACTION_PREFIX + MainWindow.ACTION_HIDE_PROJECT_DOCS + "::" @@ -172,10 +182,12 @@ namespace Scratch.FolderManager { } menu.append (new Gtk.SeparatorMenuItem ()); - menu.append (close_item); + menu.append (close_folder_item); menu.append (close_all_except_item); + menu.append (new Gtk.SeparatorMenuItem ()); menu.append (hide_item); menu.append (restore_item); + menu.append (close_item); menu.append (new Gtk.SeparatorMenuItem ()); menu.append (delete_item); menu.append (new Gtk.SeparatorMenuItem ()); diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 75ad65f0b2..8c494d15df 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -34,7 +34,7 @@ namespace Scratch { public Scratch.Widgets.SearchBar search_bar; private Code.WelcomeView welcome_view; private FolderManager.FileView folder_manager_view; - private Gee.HashMultiMap project_doc_map; + private Scratch.Services.DocumentManager document_manager; // Plugins private Scratch.Services.PluginsManager plugins; @@ -91,6 +91,7 @@ namespace Scratch { public const string ACTION_PREVIOUS_TAB = "action_previous_tab"; public const string ACTION_CLEAR_LINES = "action_clear_lines"; public const string ACTION_NEW_BRANCH = "action_new_branch"; + public const string ACTION_CLOSE_PROJECT_DOCS = "action_close_project_docs"; public const string ACTION_HIDE_PROJECT_DOCS = "action_hide_project_docs"; public const string ACTION_RESTORE_PROJECT_DOCS = "action_restore_project_docs"; @@ -134,6 +135,7 @@ namespace Scratch { { ACTION_CLEAR_LINES, action_clear_lines }, { ACTION_NEW_BRANCH, action_new_branch, "s" }, { ACTION_HIDE_PROJECT_DOCS, action_hide_project_docs, "s"}, + { ACTION_CLOSE_PROJECT_DOCS, action_close_project_docs, "s"}, { ACTION_RESTORE_PROJECT_DOCS, action_restore_project_docs, "s"} }; @@ -197,7 +199,7 @@ namespace Scratch { weak Gtk.IconTheme default_theme = Gtk.IconTheme.get_default (); default_theme.add_resource_path ("/io/elementary/code"); - project_doc_map = new Gee.HashMultiMap (); + document_manager = Scratch.Services.DocumentManager.get_instance (); actions = new SimpleActionGroup (); actions.add_action_entries (ACTION_ENTRIES, this); @@ -349,34 +351,15 @@ namespace Scratch { }); folder_manager_view.close_project_docs.connect ((project_path) => { - if (project_path == "") { - return; - } - - unowned var docs = document_view.docs; - docs.foreach ((doc) => { - if (doc.file.get_path ().has_prefix (project_path)) { - document_view.close_document (doc); - if (!project_doc_map.contains (project_path) || - !project_doc_map.@get (project_path).contains (doc.file.get_path ())) { + close_project_docs (project_path, false); + }); - project_doc_map.@set (project_path, doc.file.get_path ()); - } - } - }); + folder_manager_view.hide_project_docs.connect ((project_path) => { + close_project_docs (project_path, true); }); folder_manager_view.restore_project_docs.connect ((project_path) => { - if (project_path == "") { - return; - } - - project_doc_map.@get (project_path).@foreach ((doc_path) => { - var doc = new Scratch.Services.Document (actions, File.new_for_path (doc_path)); - document_view.open_document (doc); - return true; - }); - + restore_project_docs (project_path); }); folder_manager_view.restore_saved_state (); @@ -896,28 +879,36 @@ namespace Scratch { } private void action_hide_project_docs (SimpleAction action, Variant? param) { - string project_path = ""; - if (param == null || param.get_string () == "") { - var doc = get_current_document (); - if (doc != null) { - project_path = folder_manager_view.get_project_for_file (doc.file).file.path; - } - } else { - project_path = param.get_string (); - } + close_project_docs (get_target_path_for_actions (param), true); + } - folder_manager_view.close_project_docs (project_path); + private void action_close_project_docs (SimpleAction action, Variant? param) { + close_project_docs (get_target_path_for_actions (param), false); } private void action_restore_project_docs (SimpleAction action, Variant? param) { - string project_path = ""; - if (param == null || param.get_string () == "") { - project_path = folder_manager_view.active_project_path; - } else { - project_path = param.get_string (); - } + warning ("action restore"); + restore_project_docs (get_target_path_for_actions (param)); + } - folder_manager_view.restore_project_docs (project_path); + private void close_project_docs (string project_path, bool make_restorable) { + unowned var docs = document_view.docs; + docs.foreach ((doc) => { + if (doc.file.get_path ().has_prefix (project_path)) { + document_view.close_document (doc); + if (make_restorable) { + document_manager.make_restorable (doc); + } + } + }); + } + + private void restore_project_docs (string project_path) { + document_manager.take_restorable_paths (project_path).@foreach ((doc_path) => { + var doc = new Scratch.Services.Document (actions, File.new_for_path (doc_path)); + document_view.open_document (doc); + return true; + }); } /** Not a toggle action - linked to keyboard short cut (Ctrl-f). **/ @@ -947,7 +938,7 @@ namespace Scratch { } private void action_find_global (SimpleAction action, Variant? param) { - folder_manager_view.search_global (get_target_path_for_git_actions (param)); + folder_manager_view.search_global (get_target_path_for_actions (param)); } private void set_search_text () { @@ -1065,10 +1056,10 @@ namespace Scratch { } private void action_new_branch (SimpleAction action, Variant? param) { - folder_manager_view.new_branch (get_target_path_for_git_actions (param)); + folder_manager_view.new_branch (get_target_path_for_actions (param)); } - private string? get_target_path_for_git_actions (Variant? path_variant) { + private string? get_target_path_for_actions (Variant? path_variant) { string? path = ""; if (path_variant != null) { path = path_variant.get_string (); diff --git a/src/Services/DocumentManager.vala b/src/Services/DocumentManager.vala new file mode 100644 index 0000000000..46d2b53e6b --- /dev/null +++ b/src/Services/DocumentManager.vala @@ -0,0 +1,45 @@ +// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*- +/*- + * Copyright (c) 2020 elementary LLC. (https://elementary.io), + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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: Jeremy Wootten + */ + + public class Scratch.Services.DocumentManager : Object { + static Gee.HashMultiMap project_docs_map; + static DocumentManager? instance; + public static DocumentManager get_instance () { + if (instance == null) { + instance = new DocumentManager (); + } + + return instance; + } + + static construct { + project_docs_map = new Gee.HashMultiMap (); + } + + public void make_restorable (Document doc) { + project_docs_map.@set (doc.source_view.project.path, doc.file.get_path ()); + } + + public Gee.Collection take_restorable_paths (string project_path) { + var docs = project_docs_map.@get (project_path); + project_docs_map.remove_all (project_path); + return docs; + } + } diff --git a/src/meson.build b/src/meson.build index 8404a86ebb..a3075d043d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -29,6 +29,7 @@ code_files = files( 'FolderManager/ProjectFolderItem.vala', 'Services/CommentToggler.vala', 'Services/Document.vala', + 'Services/DocumentManager.vala', 'Services/FileHandler.vala', 'Services/GitManager.vala', 'Services/MonitoredRepository.vala', From 6bfdf8ad4fa1e7ad9770d318ad618fb9d36adea8 Mon Sep 17 00:00:00 2001 From: Jeremy Paul Wootten Date: Mon, 11 Oct 2021 16:10:28 +0100 Subject: [PATCH 4/9] Show number of restorable docs in context menu --- src/FolderManager/ProjectFolderItem.vala | 11 +++++++++-- src/Services/DocumentManager.vala | 20 ++++++++++++-------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/FolderManager/ProjectFolderItem.vala b/src/FolderManager/ProjectFolderItem.vala index bb49e58304..44e259dac5 100644 --- a/src/FolderManager/ProjectFolderItem.vala +++ b/src/FolderManager/ProjectFolderItem.vala @@ -132,8 +132,12 @@ namespace Scratch.FolderManager { }; hide_item.add (hide_accellabel); + var n_restorable = Scratch.Services.DocumentManager.get_instance ().restorable_for_project (path); + var restore_text = ngettext (_("Restore %u Hidden Document"), + _("Restore %u Hidden Documents"), + n_restorable).printf (n_restorable); var restore_accellabel = new Granite.AccelLabel.from_action_name ( - _("Restore Hidden Documents"), + restore_text, MainWindow.ACTION_PREFIX + MainWindow.ACTION_RESTORE_PROJECT_DOCS + "::" ); var restore_item = new Gtk.MenuItem () { @@ -186,7 +190,10 @@ namespace Scratch.FolderManager { menu.append (close_all_except_item); menu.append (new Gtk.SeparatorMenuItem ()); menu.append (hide_item); - menu.append (restore_item); + if (n_restorable > 0) { + menu.append (restore_item); + } + menu.append (close_item); menu.append (new Gtk.SeparatorMenuItem ()); menu.append (delete_item); diff --git a/src/Services/DocumentManager.vala b/src/Services/DocumentManager.vala index 46d2b53e6b..3077723224 100644 --- a/src/Services/DocumentManager.vala +++ b/src/Services/DocumentManager.vala @@ -17,9 +17,9 @@ * * Authored by: Jeremy Wootten */ - + public class Scratch.Services.DocumentManager : Object { - static Gee.HashMultiMap project_docs_map; + static Gee.HashMultiMap project_restorable_docs_map; static DocumentManager? instance; public static DocumentManager get_instance () { if (instance == null) { @@ -30,16 +30,20 @@ } static construct { - project_docs_map = new Gee.HashMultiMap (); + project_restorable_docs_map = new Gee.HashMultiMap (); } - + public void make_restorable (Document doc) { - project_docs_map.@set (doc.source_view.project.path, doc.file.get_path ()); + project_restorable_docs_map.@set (doc.source_view.project.path, doc.file.get_path ()); } - + public Gee.Collection take_restorable_paths (string project_path) { - var docs = project_docs_map.@get (project_path); - project_docs_map.remove_all (project_path); + var docs = project_restorable_docs_map.@get (project_path); + project_restorable_docs_map.remove_all (project_path); return docs; } + + public uint restorable_for_project (string project_path) { + return project_restorable_docs_map.@get (project_path).size; + } } From 5b9c7f706e12c1770f0e6523538c1610f13e2aef Mon Sep 17 00:00:00 2001 From: Jeremy Paul Wootten Date: Mon, 11 Oct 2021 17:42:20 +0100 Subject: [PATCH 5/9] Add indication of open docs in project context menu * Reassociate project and document on restore hiddin --- src/FolderManager/FileView.vala | 11 ++++------- src/FolderManager/ProjectFolderItem.vala | 25 +++++++++++++++++++----- src/MainWindow.vala | 2 +- src/Services/DocumentManager.vala | 23 ++++++++++++++++++++++ src/Widgets/DocumentView.vala | 5 +++++ 5 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index 07e745aa49..875df57a2c 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -19,7 +19,6 @@ */ namespace Scratch.FolderManager { - public delegate void DocumentCallback (ProjectFolderItem folder, Scratch.Services.Document doc); /** * SourceList that displays folders and their contents. */ @@ -104,14 +103,12 @@ namespace Scratch.FolderManager { foreach (var child in root.children) { var project_folder = ((ProjectFolderItem) child); - if (project_folder.expanded && - project_folder.file.path != path) { - + if (project_folder.path != path) { project_folder.expanded = false; - hide_project_docs (project_folder.file.path); - } else if (project_folder.file.path == path) { + hide_project_docs (project_folder.path); + } else if (project_folder.path == path) { project_folder.expanded = true; - restore_project_docs (project_folder.file.path); + restore_project_docs (project_folder.path); } } } diff --git a/src/FolderManager/ProjectFolderItem.vala b/src/FolderManager/ProjectFolderItem.vala index 44e259dac5..0f5344e876 100644 --- a/src/FolderManager/ProjectFolderItem.vala +++ b/src/FolderManager/ProjectFolderItem.vala @@ -112,8 +112,13 @@ namespace Scratch.FolderManager { close_all_except_item.activate.connect (() => { close_all_except (); }); close_all_except_item.sensitive = view.root.children.size > 1; + var n_open = Scratch.Services.DocumentManager.get_instance ().open_for_project (path); + var open_text = ngettext (_("Close %u Open Document"), + _("Close %u Open Documents"), + n_open).printf (n_open); + var close_accellabel = new Granite.AccelLabel.from_action_name ( - _("Close Open Documents"), + open_text, MainWindow.ACTION_PREFIX + MainWindow.ACTION_CLOSE_PROJECT_DOCS + "::" ); var close_item = new Gtk.MenuItem () { @@ -122,8 +127,12 @@ namespace Scratch.FolderManager { }; close_item.add (close_accellabel); + var hide_text = ngettext (_("Hide %u Open Document"), + _("Hide %u Open Documents"), + n_open).printf (n_open); + var hide_accellabel = new Granite.AccelLabel.from_action_name ( - _("Hide Open Documents"), + hide_text, MainWindow.ACTION_PREFIX + MainWindow.ACTION_HIDE_PROJECT_DOCS + "::" ); var hide_item = new Gtk.MenuItem () { @@ -189,13 +198,19 @@ namespace Scratch.FolderManager { menu.append (close_folder_item); menu.append (close_all_except_item); menu.append (new Gtk.SeparatorMenuItem ()); - menu.append (hide_item); if (n_restorable > 0) { menu.append (restore_item); } - menu.append (close_item); - menu.append (new Gtk.SeparatorMenuItem ()); + if (n_open > 0) { + menu.append (hide_item); + menu.append (close_item); + } + + if (n_restorable + n_open > 1) { + menu.append (new Gtk.SeparatorMenuItem ()); + } + menu.append (delete_item); menu.append (new Gtk.SeparatorMenuItem ()); menu.append (search_item); diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 8c494d15df..b27f59ee1c 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -906,7 +906,7 @@ namespace Scratch { private void restore_project_docs (string project_path) { document_manager.take_restorable_paths (project_path).@foreach ((doc_path) => { var doc = new Scratch.Services.Document (actions, File.new_for_path (doc_path)); - document_view.open_document (doc); + open_document (doc); // Use this to reassociate project and document. return true; }); } diff --git a/src/Services/DocumentManager.vala b/src/Services/DocumentManager.vala index 3077723224..5c503f0fe3 100644 --- a/src/Services/DocumentManager.vala +++ b/src/Services/DocumentManager.vala @@ -20,6 +20,8 @@ public class Scratch.Services.DocumentManager : Object { static Gee.HashMultiMap project_restorable_docs_map; + static Gee.HashMultiMap project_open_docs_map; + static DocumentManager? instance; public static DocumentManager get_instance () { if (instance == null) { @@ -31,12 +33,29 @@ static construct { project_restorable_docs_map = new Gee.HashMultiMap (); + project_open_docs_map = new Gee.HashMultiMap (); } public void make_restorable (Document doc) { project_restorable_docs_map.@set (doc.source_view.project.path, doc.file.get_path ()); } + public void add_open_document (Document doc) { + if (doc.source_view.project == null) { + return; + } + + project_open_docs_map.@set (doc.source_view.project.path, doc.file.get_path ()); + } + + public void remove_open_document (Document doc) { + if (doc.source_view.project == null) { + return; + } + + project_open_docs_map.remove (doc.source_view.project.path, doc.file.get_path ()); + } + public Gee.Collection take_restorable_paths (string project_path) { var docs = project_restorable_docs_map.@get (project_path); project_restorable_docs_map.remove_all (project_path); @@ -46,4 +65,8 @@ public uint restorable_for_project (string project_path) { return project_restorable_docs_map.@get (project_path).size; } + + public uint open_for_project (string project_path) { + return project_open_docs_map.@get (project_path).size; + } } diff --git a/src/Widgets/DocumentView.vala b/src/Widgets/DocumentView.vala index 9a0c3465be..703bee6f1f 100644 --- a/src/Widgets/DocumentView.vala +++ b/src/Widgets/DocumentView.vala @@ -195,6 +195,7 @@ public class Scratch.Widgets.DocumentView : Granite.Widgets.DynamicNotebook { } insert_tab (doc, -1); + if (focus) { current_document = doc; } @@ -331,6 +332,8 @@ public class Scratch.Widgets.DocumentView : Granite.Widgets.DynamicNotebook { doc.actions = window.actions; docs.append (doc); + Scratch.Services.DocumentManager.get_instance ().add_open_document (doc); + if (!doc.is_file_temporary) { rename_tabs_with_same_title (doc); } @@ -343,6 +346,8 @@ public class Scratch.Widgets.DocumentView : Granite.Widgets.DynamicNotebook { var doc = tab as Services.Document; docs.remove (doc); + Scratch.Services.DocumentManager.get_instance ().remove_open_document (doc); + doc.source_view.focus_in_event.disconnect (on_focus_in_event); doc.source_view.drag_data_received.disconnect (drag_received); From 9041a321d55862f58e1495a2da9b9188836acde6 Mon Sep 17 00:00:00 2001 From: Jeremy Paul Wootten Date: Mon, 11 Oct 2021 18:02:12 +0100 Subject: [PATCH 6/9] Fix close other projects * Close documents as well * Inform DocumentManager --- src/FolderManager/FileView.vala | 1 + src/MainWindow.vala | 4 ++++ src/Services/DocumentManager.vala | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index 875df57a2c..c76cf89d29 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -251,6 +251,7 @@ namespace Scratch.FolderManager { foreach (var child in root.children) { var project_folder_item = (ProjectFolderItem)child; if (project_folder_item != folder_root) { + close_project_docs (project_folder_item.path); root.remove (project_folder_item); git_manager.remove_project (project_folder_item.file.file); } diff --git a/src/MainWindow.vala b/src/MainWindow.vala index b27f59ee1c..702179ad75 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -901,6 +901,10 @@ namespace Scratch { } } }); + + if (!make_restorable) { + document_manager.remove_project (project_path); + } } private void restore_project_docs (string project_path) { diff --git a/src/Services/DocumentManager.vala b/src/Services/DocumentManager.vala index 5c503f0fe3..7b28448ee5 100644 --- a/src/Services/DocumentManager.vala +++ b/src/Services/DocumentManager.vala @@ -56,6 +56,10 @@ project_open_docs_map.remove (doc.source_view.project.path, doc.file.get_path ()); } + public void remove_project (string project_path) { + project_restorable_docs_map.remove_all (project_path); + } + public Gee.Collection take_restorable_paths (string project_path) { var docs = project_restorable_docs_map.@get (project_path); project_restorable_docs_map.remove_all (project_path); From 919dd61734b3a3b3376ebce16601cc5526c7b88f Mon Sep 17 00:00:00 2001 From: Jeremy Paul Wootten Date: Mon, 11 Oct 2021 19:20:05 +0100 Subject: [PATCH 7/9] FileView: Replace signals with activate_action --- src/FolderManager/FileView.vala | 18 +++++++++++------- src/MainWindow.vala | 17 +++-------------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index c76cf89d29..47005ade4e 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -25,11 +25,9 @@ namespace Scratch.FolderManager { public class FileView : Granite.Widgets.SourceList, Code.PaneSwitcher { private GLib.Settings settings; private Scratch.Services.GitManager git_manager; + private ActionGroup? toplevel_action_group = null; public signal void select (string file); - public signal void hide_project_docs (string project_path); - public signal void close_project_docs (string project_path); - public signal void restore_project_docs (string project_path); // This is a workaround for SourceList silliness: you cannot remove an item // without it automatically selecting another one. @@ -52,6 +50,12 @@ namespace Scratch.FolderManager { settings = new GLib.Settings ("io.elementary.code.folder-manager"); git_manager = Scratch.Services.GitManager.get_instance (); + + realize.connect (() => { + toplevel_action_group = get_action_group (MainWindow.ACTION_GROUP); + assert_nonnull (toplevel_action_group); + }); + } private void on_item_selected (Granite.Widgets.SourceList.Item? item) { @@ -105,10 +109,10 @@ namespace Scratch.FolderManager { var project_folder = ((ProjectFolderItem) child); if (project_folder.path != path) { project_folder.expanded = false; - hide_project_docs (project_folder.path); + toplevel_action_group.activate_action (MainWindow.ACTION_HIDE_PROJECT_DOCS, new Variant.string (project_folder.path)); } else if (project_folder.path == path) { project_folder.expanded = true; - restore_project_docs (project_folder.path); + toplevel_action_group.activate_action (MainWindow.ACTION_RESTORE_PROJECT_DOCS, new Variant.string (project_folder.path)); } } } @@ -241,7 +245,7 @@ namespace Scratch.FolderManager { folder_root.expanded = expand; folder_root.closed.connect (() => { - close_project_docs (folder_root.file.path); + toplevel_action_group.activate_action (MainWindow.ACTION_CLOSE_PROJECT_DOCS, new Variant.string (folder_root.path)); root.remove (folder_root); git_manager.remove_project (folder_root.file.file); write_settings (); @@ -251,7 +255,7 @@ namespace Scratch.FolderManager { foreach (var child in root.children) { var project_folder_item = (ProjectFolderItem)child; if (project_folder_item != folder_root) { - close_project_docs (project_folder_item.path); + toplevel_action_group.activate_action (MainWindow.ACTION_CLOSE_PROJECT_DOCS, new Variant.string (project_folder_item.path)); root.remove (project_folder_item); git_manager.remove_project (project_folder_item.file.file); } diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 702179ad75..0d1871a161 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -55,7 +55,8 @@ namespace Scratch { public SimpleActionGroup actions { get; construct; } - public const string ACTION_PREFIX = "win."; + public const string ACTION_GROUP = "win"; + public const string ACTION_PREFIX = ACTION_GROUP + "."; public const string ACTION_FIND = "action_find"; public const string ACTION_FIND_NEXT = "action_find_next"; public const string ACTION_FIND_PREVIOUS = "action_find_previous"; @@ -203,7 +204,7 @@ namespace Scratch { actions = new SimpleActionGroup (); actions.add_action_entries (ACTION_ENTRIES, this); - insert_action_group ("win", actions); + insert_action_group (ACTION_GROUP, actions); actions.action_state_changed.connect ((name, new_state) => { if (name == ACTION_SHOW_FIND) { @@ -350,17 +351,6 @@ namespace Scratch { } }); - folder_manager_view.close_project_docs.connect ((project_path) => { - close_project_docs (project_path, false); - }); - - folder_manager_view.hide_project_docs.connect ((project_path) => { - close_project_docs (project_path, true); - }); - - folder_manager_view.restore_project_docs.connect ((project_path) => { - restore_project_docs (project_path); - }); folder_manager_view.restore_saved_state (); @@ -887,7 +877,6 @@ namespace Scratch { } private void action_restore_project_docs (SimpleAction action, Variant? param) { - warning ("action restore"); restore_project_docs (get_target_path_for_actions (param)); } From 28184e9a078f22aae6db81c322a6146ef9f51e40 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 31 Aug 2022 12:41:01 +0100 Subject: [PATCH 8/9] Update copyright; cleanup --- src/FolderManager/FileView.vala | 1 - src/Services/DocumentManager.vala | 2 +- src/Widgets/DocumentView.vala | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index 86b68ec380..09fae6cd63 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -263,7 +263,6 @@ public class Scratch.FolderManager.FileView : Granite.Widgets.SourceList, Code.P folder_root.expanded = expand; folder_root.closed.connect (() => { - // close_all_docs_from_path (folder_root.file.path); toplevel_action_group.activate_action (MainWindow.ACTION_CLOSE_PROJECT_DOCS, new Variant.string (folder_root.path)); root.remove (folder_root); foreach (var child in root.children) { diff --git a/src/Services/DocumentManager.vala b/src/Services/DocumentManager.vala index 7b28448ee5..24edde5a4b 100644 --- a/src/Services/DocumentManager.vala +++ b/src/Services/DocumentManager.vala @@ -1,6 +1,6 @@ // -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*- /*- - * Copyright (c) 2020 elementary LLC. (https://elementary.io), + * Copyright (c) 2022 elementary LLC. (https://elementary.io), * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 diff --git a/src/Widgets/DocumentView.vala b/src/Widgets/DocumentView.vala index cd271f4cfa..0b6995ae27 100644 --- a/src/Widgets/DocumentView.vala +++ b/src/Widgets/DocumentView.vala @@ -218,7 +218,6 @@ public class Scratch.Widgets.DocumentView : Granite.Widgets.DynamicNotebook { } insert_tab (doc, -1); - if (focus) { current_document = doc; } From f4d288c085adb95a8a2643110483f6be3ecdce89 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Fri, 21 Oct 2022 09:55:51 +0100 Subject: [PATCH 9/9] Fix merge --- src/MainWindow.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index b65bd1dd73..70268b9c39 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -952,7 +952,7 @@ namespace Scratch { term = search_bar.search_entry.text; } - folder_manager_view.search_global (get_target_path_for_git_actions (param), term); + folder_manager_view.search_global (get_target_path_for_actions (param), term); } private void set_search_text () {