# HG changeset patch
# User Remi Thebault <remi.thebault@gmail.com>
# Date 1643669218 -3600
#      Mon Jan 31 23:46:58 2022 +0100
# Node ID db32d39e42588403d8119f22d82fea1ebf83bea1
# Parent  b15e026c5a3136d02e20c6c9b64f9a9c66d1f88d
Perform file rename directly in the file tree view

diff -r b15e026c5a31 -r db32d39e4258 libgui/src/files-dock-widget.cc
--- a/libgui/src/files-dock-widget.cc	Tue Jan 18 13:28:01 2022 -0500
+++ b/libgui/src/files-dock-widget.cc	Mon Jan 31 23:46:58 2022 +0100
@@ -41,6 +41,8 @@
 #include <QMessageBox>
 #include <QProcess>
 #include <QSizePolicy>
+#include <QStyledItemDelegate>
+#include <QTimer>
 #include <QToolButton>
 #include <QUrl>
 
@@ -70,6 +72,45 @@ namespace octave
     }
   };
 
+  // Delegate to improve ergonomy of file renaming by pre-selecting the text
+  // before the extension.
+  class RenameItemDelegate : public QStyledItemDelegate
+  {
+  public:
+    RenameItemDelegate (QObject *parent = nullptr)
+        : QStyledItemDelegate{ parent }
+    {
+    }
+
+    void setEditorData (QWidget *editor,
+                        const QModelIndex &index) const override
+    {
+      QLineEdit *line_edit = qobject_cast<QLineEdit *> (editor);
+
+      if (!line_edit)
+        {
+          QStyledItemDelegate::setEditorData (editor, index);
+          return;
+        }
+
+      QString filename = index.data (Qt::EditRole).toString ();
+
+      int select_len = filename.indexOf (QChar ('.'));
+      if (select_len == -1)
+        select_len = filename.size ();
+
+      line_edit->setText (filename);
+
+      // Qt calls QLineEdit::selectAll after this function is called, so to
+      // actually restrict the selection, we have to post the modification at
+      // the end of the event loop.
+      // QTimer allows this easily with 0 as timeout.
+      QTimer::singleShot (0, [=] () {
+        line_edit->setSelection (0, select_len);
+      });
+    }
+  };
+
   files_dock_widget::files_dock_widget (QWidget *p, base_qobject& oct_qobj)
     : octave_dock_widget ("FilesDockWidget", p, oct_qobj)
   {
@@ -219,6 +260,24 @@ namespace octave
     m_file_tree_view->setAnimated (true);
     m_file_tree_view->setToolTip (tr ("Double-click to open file/folder, right click for alternatives"));
 
+    // allow renaming directly in the tree view with
+    // m_file_tree_view->edit(index)
+    m_file_system_model->setReadOnly (false);
+    // delegate to improve rename ergonomy by pre-selecting text up to the
+    // extension
+    auto *rename_delegate = new RenameItemDelegate (this);
+    m_file_tree_view->setItemDelegateForColumn (0, rename_delegate);
+    // prevent the tree view to override Octave's double-click behavior
+    m_file_tree_view->setEditTriggers (QAbstractItemView::NoEditTriggers);
+    // create the rename action (that will be added to context menu)
+    // and associate to F2 key shortcut
+    m_rename_action = new QAction (tr ("Rename..."), this);
+    m_rename_action->setShortcut (Qt::Key_F2);
+    m_rename_action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
+    connect (m_rename_action, &QAction::triggered, this,
+             &files_dock_widget::contextmenu_rename);
+    addAction(m_rename_action);
+
     // get sort column and order as well as column state (order and width)
 
     m_file_tree_view->sortByColumn
@@ -582,8 +641,7 @@ namespace octave
           }
 
         menu.addSeparator ();
-        menu.addAction (tr ("Rename..."),
-                        this, &files_dock_widget::contextmenu_rename);
+        menu.addAction (m_rename_action);
         menu.addAction (rmgr.icon ("edit-delete"), tr ("Delete..."),
                         this, &files_dock_widget::contextmenu_delete);
 
@@ -694,35 +752,7 @@ namespace octave
     if (rows.size () > 0)
       {
         QModelIndex index = rows[0];
-
-        QFileInfo info = m_file_system_model->fileInfo (index);
-        QDir path = info.absoluteDir ();
-        QString old_name = info.fileName ();
-        bool ok;
-
-        QString new_name
-          = QInputDialog::getText (this, tr ("Rename file/directory"),
-                                   tr ("Rename file/directory:\n")
-                                   + old_name + tr ("\n to: "),
-                                   QLineEdit::Normal, old_name, &ok);
-        if (ok && new_name.length () > 0)
-          {
-            new_name = path.absolutePath () + '/' + new_name;
-            old_name = path.absolutePath () + '/' + old_name;
-            // editor: close old
-            emit file_remove_signal (old_name, new_name);
-            // Do the renaming
-            QFile f (old_name);  // Must use QFile, not QDir (bug #56298)
-            bool st = f.rename (new_name);
-            if (! st)
-              QMessageBox::warning (this, tr ("Rename error"),
-                                    tr ("Could not rename file \"%1\" to \"%2\".").
-                                    arg (old_name).arg (new_name));
-            // editor: load new/old file depending on success
-            emit file_renamed_signal (st);
-            // Clear cache of file browser
-            m_file_system_model->revert ();
-          }
+        m_file_tree_view->edit(index);
       }
 
   }
diff -r b15e026c5a31 -r db32d39e4258 libgui/src/files-dock-widget.h
--- a/libgui/src/files-dock-widget.h	Tue Jan 18 13:28:01 2022 -0500
+++ b/libgui/src/files-dock-widget.h	Mon Jan 31 23:46:58 2022 +0100
@@ -207,6 +207,7 @@ namespace octave
     QToolBar *m_navigation_tool_bar;
     QAction *m_sync_octave_directory_action;
     QAction *m_sync_browser_directory_action;
+    QAction *m_rename_action;
 
     //! The file system model.
 
