From 1cc6b21dd5bcf62e510ad6a422e7027e2b0e9d5c Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 24 Jan 2024 20:26:59 +0000 Subject: [PATCH] Fix select after rename; fix rename folder; disallow rename if unsaved edits (#1386) * Select and open fileitem after renaming * Allow editing folderitem * Only create new file/folder if editing name succeeded * Only allow sidebar to rename files that are not locked and are saved * Check all open windows before renaing * Revert select prev after new folder * Deselect after rename * Change debug message * Unselect all on folder rename * Account for SourceList weirdness --- src/FolderManager/FileItem.vala | 25 +++++++++++++-- src/FolderManager/FileView.vala | 8 ++++- src/FolderManager/FolderItem.vala | 51 +++++++++++++++++++++++-------- src/MainWindow.vala | 16 ++++++++++ 4 files changed, 84 insertions(+), 16 deletions(-) diff --git a/src/FolderManager/FileItem.vala b/src/FolderManager/FileItem.vala index 289ec8111..766089388 100644 --- a/src/FolderManager/FileItem.vala +++ b/src/FolderManager/FileItem.vala @@ -122,10 +122,31 @@ namespace Scratch.FolderManager { var rename_item = new Gtk.MenuItem.with_label (_("Rename")); rename_item.activate.connect (() => { - view.ignore_next_select = true; - view.start_editing_item (this); + // Ensure item selected else rename does not work + view.select_path (file.path); + if (view.start_editing_item (this)) { + ulong once = 0; + once = this.edited.connect ((new_name) => { + this.disconnect (once); + var new_path = Path.get_dirname (file.path) + Path.DIR_SEPARATOR_S + new_name; + view.toplevel_action_group.activate_action (MainWindow.ACTION_CLOSE_TAB, new Variant.string (this.path)); + view.select (new_path); // Select and open newly named file + }); + + // Handle cancelled rename (which does not produce signal) + Timeout.add (200, () => { + if (view.editing) { + return Source.CONTINUE; + } else { + // Avoid selected but unopened item if rename cancelled (they would not open if clicked on) + view.unselect_all (); + return Source.REMOVE; + } + }); + } }); + rename_item.sensitive = view.rename_request (file); var delete_item = new Gtk.MenuItem.with_label (_("Move to Trash")); delete_item.activate.connect (trash); diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index 6de7f1ec6..fb809245e 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -24,10 +24,12 @@ public class Scratch.FolderManager.FileView : Granite.Widgets.SourceList, Code.PaneSwitcher { private GLib.Settings settings; private Scratch.Services.GitManager git_manager; - private ActionGroup? toplevel_action_group = null; + + public ActionGroup toplevel_action_group { get; private set; } private Scratch.Services.PluginsManager plugins; public signal void select (string file); + public signal bool rename_request (File file); public bool ignore_next_select { get; set; default = false; } public string icon_name { get; set; } @@ -119,6 +121,10 @@ public class Scratch.FolderManager.FileView : Granite.Widgets.SourceList, Code.P item_selected.connect (on_item_selected); } + public void unselect_all () { + selected = null; + } + public void collapse_other_projects (string? keep_open_path = null) { unowned string path; if (keep_open_path == null) { diff --git a/src/FolderManager/FolderItem.vala b/src/FolderManager/FolderItem.vala index d3ce1e4cd..2c82c4d73 100644 --- a/src/FolderManager/FolderItem.vala +++ b/src/FolderManager/FolderItem.vala @@ -123,8 +123,25 @@ namespace Scratch.FolderManager { var rename_menu_item = new Gtk.MenuItem.with_label (_("Rename")); rename_menu_item.activate.connect (() => { - view.ignore_next_select = true; - view.start_editing_item (this); + selectable = true; + if (view.start_editing_item (this)) { + // Need to poll view as no signal emited when editing cancelled and need to set + // selectable to false anyway. + Timeout.add (200, () => { + if (view.editing) { + return Source.CONTINUE; + } else { + view.unselect_all (); + // Must do this *after* unselecting all else sourcelist breaks + selectable = false; + } + + return Source.REMOVE; + }); + } else { + debug ("Could not rename %s", file.path); + selectable = false; + } }); var delete_item = new Gtk.MenuItem.with_label (_("Move to Trash")); @@ -380,14 +397,12 @@ namespace Scratch.FolderManager { add (rename_item); /* Start editing after finishing signal handler */ GLib.Idle.add (() => { - view.start_editing_item (rename_item); - /* Need to poll view editing as no signal is generated when canceled (Granite bug) */ - Timeout.add (200, () => { - if (view.editing) { - return Source.CONTINUE; - } else { + if (view.start_editing_item (rename_item)) { + ulong once = 0; + once = rename_item.edited.connect (() => { + rename_item.disconnect (once); + // A name was accepted so create the corresponding file var new_name = rename_item.name; - view.ignore_next_select = true; try { var gfile = file.file.get_child_for_display_name (new_name); if (is_folder) { @@ -398,13 +413,23 @@ namespace Scratch.FolderManager { } } catch (Error e) { warning (e.message); - } finally { + } + }); + + /* Need to remove rename item even when editing cancelled so cannot use "edited" signal */ + Timeout.add (200, () => { + if (view.editing) { + return Source.CONTINUE; + } else { remove (rename_item); } - } - return Source.REMOVE; - }); + return Source.REMOVE; + }); + } else { + remove (rename_item); + } + return Source.REMOVE; }); diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 9aa943ac4..220e3a07e 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -480,6 +480,22 @@ namespace Scratch { folder_manager_view.restore_saved_state (); + folder_manager_view.rename_request.connect ((file) => { + var allow = true; + foreach (var window in app.get_windows ()) { + var win = (MainWindow)window; + foreach (var doc in win.document_view.docs) { + if (doc.file.equal (file.file)) { + // Only allow sidebar to rename docs that are in sync with their file in + // all windows + allow = allow && !doc.locked && doc.saved; + } + } + } + + return allow; + }); + terminal = new Code.Terminal () { no_show_all = true, visible = false