changeset 16502:45ae1038ee89

allow renaming of variables in workspace viewer * main-window.h, main-window.cc (main_window::handle_rename_variable_request): New function. (main_window::construct_octave_qt_link): Connect _workspace_model::rename_variable to main_window::handle_rename_variable_request. (main_window::rename_variable_callback): New function. * octave-qt-link.h, octave-qt-link.cc (octave_qt_link::do_set_workspace, octave_qt_link::set_workspace_signal): New argument, top_level. Change all uses. * octave-link.h, octave-link.cc (octave_link::post_event): Provide two-argument version. (octave_link::set_workspace, octave_link::do_set_workspace): New argument, top_level. Change all uses. * workspace-model.h, workspace-model.cc (workspace_model::flags): Conditionally add Qt::ItemIsEditable to flags. (workspace_model::data): Also return value for column 0 if it is editable. (workspace_model::setData): Handle setting new values. (workspace_model::_top_level): New data member. (workspace_model::set_workspace): New argument, top_level. (workspace_model::rename_variable): New signal. * workspace-view.h, workspace-view.cc (variable_name_editor): New class. (workspace_view::var_name_editor): New data member. (workspace_view::workspace_view): Initialize it. Set var_name_editor as delegate for column 0. (workspace_view::~workspace_view): Delete var_name_editor. (workspace_view::item_double_clicked): Delete. * symtab.h (symbol_table::rename, symbol_table::do_rename, symbol_table::symbol_record::rename): New functions.
author John W. Eaton <jwe@octave.org>
date Fri, 12 Apr 2013 14:50:56 -0400
parents 3781abc74540
children c1ff738d606d
files libgui/src/main-window.cc libgui/src/main-window.h libgui/src/octave-qt-link.cc libgui/src/octave-qt-link.h libgui/src/workspace-model.cc libgui/src/workspace-model.h libgui/src/workspace-view.cc libgui/src/workspace-view.h libinterp/interpfcn/input.cc libinterp/interpfcn/octave-link.h libinterp/interpfcn/symtab.h
diffstat 11 files changed, 266 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/main-window.cc	Fri Apr 12 19:10:32 2013 +0200
+++ b/libgui/src/main-window.cc	Fri Apr 12 14:50:56 2013 -0400
@@ -39,6 +39,8 @@
 #include <QMessageBox>
 #include <QIcon>
 
+#include <utility>
+
 #ifdef HAVE_QSCINTILLA
 #include "file-editor.h"
 #endif
@@ -49,6 +51,7 @@
 
 #include "builtin-defun-decls.h"
 #include "defaults.h"
+#include "symtab.h"
 #include "version.h"
 
 static file_editor_interface *
@@ -148,6 +151,17 @@
 }
 
 void
+main_window::handle_rename_variable_request (const QString& old_name,
+                                             const QString& new_name)
+
+{
+  name_pair names (old_name.toStdString (), new_name.toStdString ());
+
+  octave_link::post_event (this, &main_window::rename_variable_callback,
+                           names);
+}
+
+void
 main_window::handle_clear_history_request (void)
 {
   octave_link::post_event (this, &main_window::clear_history_callback);
@@ -598,12 +612,14 @@
 
   connect (_octave_qt_link,
            SIGNAL (set_workspace_signal
-                   (const QString&, const QStringList&, const QStringList&,
-                    const QStringList&, const QStringList&)),
+                   (bool, const QString&, const QStringList&,
+                    const QStringList&, const QStringList&,
+                    const QStringList&)),
            _workspace_model,
            SLOT (set_workspace
-                 (const QString&, const QStringList&,const QStringList&,
-                  const QStringList&, const QStringList&)));
+                 (bool, const QString&, const QStringList&,
+                  const QStringList&, const QStringList&,
+                  const QStringList&)));
 
   connect (_octave_qt_link, SIGNAL (clear_workspace_signal ()),
            _workspace_model, SLOT (clear_workspace ()));
@@ -649,6 +665,12 @@
            editor_window,
            SLOT (handle_delete_debugger_pointer_request (const QString&, int)));
 
+  connect (_workspace_model,
+           SIGNAL (rename_variable (const QString&, const QString&)),
+           this,
+           SLOT (handle_rename_variable_request (const QString&,
+                                                 const QString&)));
+
   _octave_qt_link->execute_interpreter ();
 
   octave_link::connect_link (_octave_qt_link);
@@ -1184,6 +1206,18 @@
 }
 
 void
+main_window::rename_variable_callback (const main_window::name_pair& names)
+{
+  /* bool status = */ symbol_table::rename (names.first, names.second);
+
+  // if (status)
+    octave_link::set_workspace (true, symbol_table::workspace_info ());
+
+  //  else
+  //    ; // we need an octave_link action that runs a GUI error option.
+}
+
+void
 main_window::clear_history_callback (void)
 {
   Fhistory (ovl ("-c"));
--- a/libgui/src/main-window.h	Fri Apr 12 19:10:32 2013 +0200
+++ b/libgui/src/main-window.h	Fri Apr 12 14:50:56 2013 -0400
@@ -64,6 +64,8 @@
 
 public:
 
+  typedef std::pair <std::string, std::string> name_pair;
+
   main_window (QWidget *parent = 0);
 
   ~main_window (void);
@@ -82,6 +84,8 @@
   void handle_load_workspace_request (void);
   void handle_clear_workspace_request (void);
   void handle_clear_history_request (void);
+  void handle_rename_variable_request (const QString& old_name,
+                                       const QString& new_name);
   void new_file (const QString& commands = QString ());
   void open_file (const QString& file_name = QString ());
   void open_online_documentation_page (void);
@@ -150,6 +154,8 @@
 
   void load_workspace_callback (const std::string& file);
 
+  void rename_variable_callback (const name_pair& names);
+
   void clear_workspace_callback (void);
 
   void clear_history_callback (void);
--- a/libgui/src/octave-qt-link.cc	Fri Apr 12 19:10:32 2013 +0200
+++ b/libgui/src/octave-qt-link.cc	Fri Apr 12 14:50:56 2013 -0400
@@ -69,7 +69,8 @@
 }
 
 void
-octave_qt_link::do_set_workspace (const std::list<workspace_element>& ws)
+octave_qt_link::do_set_workspace (bool top_level,
+                                  const std::list<workspace_element>& ws)
 {
   QString scopes;
   QStringList symbols;
@@ -87,7 +88,8 @@
       values.append (QString::fromStdString (it->value ()));
     }
 
-  emit set_workspace_signal (scopes, symbols, class_names, dimensions, values);
+  emit set_workspace_signal (top_level, scopes, symbols, class_names,
+                             dimensions, values);
 }
 
 void
--- a/libgui/src/octave-qt-link.h	Fri Apr 12 19:10:32 2013 +0200
+++ b/libgui/src/octave-qt-link.h	Fri Apr 12 14:50:56 2013 -0400
@@ -61,7 +61,9 @@
 
   void do_change_directory (const std::string& dir);
 
-  void do_set_workspace (const std::list<workspace_element>& ws);
+  void do_set_workspace (bool top_level,
+                         const std::list<workspace_element>& ws);
+
   void do_clear_workspace (void);
 
   void do_set_history (const string_vector& hist);
@@ -99,7 +101,8 @@
 
   void change_directory_signal (const QString& dir);
 
-  void set_workspace_signal (const QString& scopes,
+  void set_workspace_signal (bool top_level,
+                             const QString& scopes,
                              const QStringList& symbols,
                              const QStringList& class_names,
                              const QStringList& dimensions,
--- a/libgui/src/workspace-model.cc	Fri Apr 12 19:10:32 2013 +0200
+++ b/libgui/src/workspace-model.cc	Fri Apr 12 14:50:56 2013 -0400
@@ -27,8 +27,7 @@
 
 #include <QTreeWidget>
 
-#include "symtab.h"
-#include "variables.h"
+#include "utils.h"
 
 #include "workspace-model.h"
 
@@ -56,10 +55,15 @@
 Qt::ItemFlags
 workspace_model::flags (const QModelIndex& idx) const
 {
-  if (! idx.isValid ())
-    return 0;
+  Qt::ItemFlags retval = 0;
+
+  if (idx.isValid ())
+    retval |= Qt::ItemIsEnabled | Qt::ItemIsSelectable;
 
-  return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+  if (idx.column () == 0)
+    retval |= Qt::ItemIsEditable;
+
+  return retval;
 }
 
 QVariant
@@ -75,37 +79,73 @@
 QVariant
 workspace_model::data (const QModelIndex& idx, int role) const
 {
-  if (!idx.isValid())
-    return QVariant();
+  QVariant retval;
 
-  if (role != Qt::DisplayRole)
-    return QVariant ();
-
-  switch (idx.column ())
+  if (idx.isValid ()
+      && (role == Qt::DisplayRole
+          || (idx.column () == 0 && role == Qt::EditRole)))
     {
-    case 0:
-      return QVariant(_symbols[idx.row()]);
+      switch (idx.column ())
+        {
+        case 0:
+          retval = QVariant (_symbols[idx.row()]);
+          break;
 
-    case 1:
-      return QVariant(_class_names[idx.row()]);
+        case 1:
+          retval = QVariant (_class_names[idx.row()]);
+          break;
 
-    case 2:
-      return QVariant(_dimensions[idx.row()]);
+        case 2:
+          retval = QVariant (_dimensions[idx.row()]);
+          break;
 
-    case 3:
-      return QVariant(_values[idx.row()]);
+        case 3:
+          retval = QVariant (_values[idx.row()]);
+          break;
+
+        default:
+          break;
+        }
     }
 
-  return QVariant ();
+  return retval;
 }
 
+bool
+workspace_model::setData (const QModelIndex& idx, const QVariant& value,
+                          int role)
+{
+  bool retval = false;
+
+  if (idx.column () == 0 && role == Qt::EditRole)
+    {
+      QString qold_name = _symbols[idx.row()];
+
+      QString qnew_name = value.toString ();
+
+      std::string new_name = qnew_name.toStdString ();
+
+      if (valid_identifier (new_name))
+        {
+          emit rename_variable (qold_name, qnew_name);
+
+          retval = true;
+        }
+    }
+
+  return retval;
+}
+
+
 void
-workspace_model::set_workspace (const QString& scopes,
+workspace_model::set_workspace (bool top_level,
+                                const QString& scopes,
                                 const QStringList& symbols,
                                 const QStringList& class_names,
                                 const QStringList& dimensions,
                                 const QStringList& values)
 {
+  _top_level = top_level;
   _scopes = scopes;
   _symbols = symbols;
   _class_names = class_names;
@@ -129,6 +169,7 @@
 void
 workspace_model::clear_data (void)
 {
+  _top_level = false;
   _scopes = QString ();
   _symbols = QStringList ();
   _class_names = QStringList ();
--- a/libgui/src/workspace-model.h	Fri Apr 12 19:10:32 2013 +0200
+++ b/libgui/src/workspace-model.h	Fri Apr 12 14:50:56 2013 -0400
@@ -42,6 +42,9 @@
 
   QVariant data (const QModelIndex& index, int role) const;
 
+  bool setData (const QModelIndex& index, const QVariant& value,
+                int role = Qt::EditRole);
+
   Qt::ItemFlags flags (const QModelIndex& index) const;
 
   QVariant headerData (int section, Qt::Orientation orientation,
@@ -51,9 +54,12 @@
 
   int columnCount (const QModelIndex& parent = QModelIndex ()) const;
 
+  bool is_top_level (void) const { return _top_level; }
+
 public slots:
 
-  void set_workspace (const QString& scopes,
+  void set_workspace (bool top_level,
+                      const QString& scopes,
                       const QStringList& symbols,
                       const QStringList& class_names,
                       const QStringList& dimensions,
@@ -65,11 +71,14 @@
 
   void model_changed (void);
 
+  void rename_variable (const QString& old_name, const QString& new_name);
+
 private:
 
   void clear_data (void);
   void update_table (void);
 
+  bool _top_level;
   QString _scopes;
   QStringList _symbols;
   QStringList _class_names;
--- a/libgui/src/workspace-view.cc	Fri Apr 12 19:10:32 2013 +0200
+++ b/libgui/src/workspace-view.cc	Fri Apr 12 14:50:56 2013 -0400
@@ -25,24 +25,85 @@
 #include <config.h>
 #endif
 
-#include "workspace-view.h"
-#include "resource-manager.h"
+#include <QMessageBox>
+#include <QLineEdit>
 #include <QHeaderView>
 #include <QHBoxLayout>
 #include <QVBoxLayout>
 #include <QPushButton>
 #include <QMenu>
 
+#include "workspace-view.h"
+#include "resource-manager.h"
+
+QWidget *
+variable_name_editor::createEditor (QWidget *p, const QStyleOptionViewItem&,
+                                    const QModelIndex& index) const
+{
+  QWidget *retval = 0;
+
+  const QAbstractItemModel *m = index.model ();
+
+  const workspace_model *wm = static_cast<const workspace_model *> (m);
+
+  if (wm->is_top_level ())
+    retval = new QLineEdit (p);
+  else
+    {
+      QMessageBox *msg_box
+        = new QMessageBox (QMessageBox::Critical,
+                           tr ("Workspace Viewer"),
+                           tr ("Only top-level symbols may be renamed.\n"),
+                           QMessageBox::Ok);
+
+      msg_box->setWindowModality (Qt::NonModal);
+      msg_box->setAttribute (Qt::WA_DeleteOnClose);
+      msg_box->show ();
+    }
+
+  return retval;
+}
+
+void
+variable_name_editor::setEditorData (QWidget *editor,
+                                     const QModelIndex& index) const
+{
+  QLineEdit *line_editor = static_cast<QLineEdit *> (editor);
+
+  const QAbstractItemModel *m = index.model ();
+
+  QVariant d =  m->data (index, Qt::EditRole);
+
+  line_editor->insert (d.toString ());
+}
+
+void
+variable_name_editor::setModelData (QWidget *editor,
+                                    QAbstractItemModel *model,
+                                    const QModelIndex& index) const
+{
+  QLineEdit *line_editor = static_cast<QLineEdit*> (editor);
+
+  model->setData (index, line_editor->text (), Qt::EditRole);
+}
+
+void
+variable_name_editor::updateEditorGeometry (QWidget *editor,
+                                            const QStyleOptionViewItem& option,
+                                            const QModelIndex&) const
+{
+  editor->setGeometry (option.rect);
+}
+
 workspace_view::workspace_view (QWidget *p)
-  : octave_dock_widget (p)
+  : octave_dock_widget (p), view (new QTableView (this)),
+    var_name_editor (new variable_name_editor (this))
 {
   setObjectName ("WorkspaceView");
   setWindowIcon (QIcon (":/actions/icons/logo.png"));
   setWindowTitle (tr ("Workspace"));
   setStatusTip (tr ("View the variables in the active workspace."));
 
-  view = new QTableView (this);
-
   view->setWordWrap (false);
   view->setContextMenuPolicy (Qt::CustomContextMenu);
 
@@ -61,16 +122,13 @@
 
   QSettings *settings = resource_manager::get_settings ();
 
-  // FIXME -- what should happen if settings is 0?
-
   // Initialize column order and width of the workspace
   
   view->horizontalHeader ()->restoreState (settings->value ("workspaceview/column_state").toByteArray ());
 
-  // Connect signals and slots.
+  view->setItemDelegateForColumn (0, var_name_editor);
 
-  connect (view, SIGNAL (doubleClicked (QModelIndex)),
-           this, SLOT (item_double_clicked (QModelIndex)));
+  // Connect signals and slots.
 
   connect (view, SIGNAL (customContextMenuRequested (const QPoint&)),
            this, SLOT(contextmenu_requested (const QPoint&)));
@@ -87,13 +145,8 @@
                      view->horizontalHeader ()->saveState ());
 
   settings->sync ();
-}
 
-void
-workspace_view::item_double_clicked (QModelIndex)
-{
-  // TODO: Implement opening a dialog that allows the user to change a
-  // variable in the workspace.
+  delete var_name_editor;
 }
 
 void
--- a/libgui/src/workspace-view.h	Fri Apr 12 19:10:32 2013 +0200
+++ b/libgui/src/workspace-view.h	Fri Apr 12 14:50:56 2013 -0400
@@ -24,12 +24,34 @@
 #if !defined (workspace_view_h)
 #define workspace_view_h 1
 
+#include <QItemDelegate>
 #include <QTableView>
 #include <QSemaphore>
 
 #include "octave-dock-widget.h"
 #include "workspace-model.h"
 
+class variable_name_editor : public QItemDelegate
+{
+  Q_OBJECT
+
+public:
+
+  variable_name_editor (QObject *p = 0) : QItemDelegate (p) { }
+
+  QWidget *createEditor (QWidget *p, const QStyleOptionViewItem& option,
+                         const QModelIndex& index) const;
+
+  void setEditorData (QWidget *editor, const QModelIndex& index) const;
+
+  void setModelData (QWidget *editor, QAbstractItemModel *model,
+                     const QModelIndex& index) const;
+
+  void updateEditorGeometry (QWidget *editor,
+                             const QStyleOptionViewItem& option,
+                             const QModelIndex&) const;
+};
+
 class workspace_view : public octave_dock_widget
 {
   Q_OBJECT
@@ -44,7 +66,6 @@
 
   void setModel (workspace_model *model) { view->setModel (model); }
 
-
 signals:
 
   /** signal that user had requested a command on a variable */
@@ -56,7 +77,6 @@
 
 protected slots:
 
-  void item_double_clicked (QModelIndex index);
   void contextmenu_requested (const QPoint& pos);
 
   // context menu slots
@@ -68,7 +88,9 @@
 
   void relay_contextmenu_command (const QString& cmdname);
 
-  QTableView * view;
+  QTableView *view;
+
+  variable_name_editor *var_name_editor;
 };
 
 #endif
--- a/libinterp/interpfcn/input.cc	Fri Apr 12 19:10:32 2013 +0200
+++ b/libinterp/interpfcn/input.cc	Fri Apr 12 14:50:56 2013 -0400
@@ -219,7 +219,9 @@
 
       octave_link::pre_input_event ();
 
-      octave_link::set_workspace (symbol_table::workspace_info ());
+      octave_link::set_workspace ((symbol_table::current_scope ()
+                                   == symbol_table::top_scope ()),
+                                  symbol_table::workspace_info ());
 
       // FIXME -- this call should happen any time the terminal window
       // size changes, not just prior to prompting for input.
@@ -526,7 +528,9 @@
             {
               octave_link::enter_debugger_event (nm, curr_debug_line);
 
-              octave_link::set_workspace (symbol_table::workspace_info ());
+              octave_link::set_workspace ((symbol_table::current_scope ()
+                                           == symbol_table::top_scope ()),
+                                          symbol_table::workspace_info ());
 
               frame.add_fcn (execute_in_debugger_handler,
                              std::pair<std::string, int> (nm, curr_debug_line));
--- a/libinterp/interpfcn/octave-link.h	Fri Apr 12 19:10:32 2013 +0200
+++ b/libinterp/interpfcn/octave-link.h	Fri Apr 12 14:50:56 2013 -0400
@@ -108,6 +108,14 @@
       instance->do_post_event (obj, method, arg);
   }
 
+  template <class T, class A, class B>
+  static void post_event (T *obj, void (T::*method) (const A&, const B&),
+                          const A& arg_a, const B& arg_b)
+  {
+    if (enabled ())
+      instance->do_post_event (obj, method, arg_a, arg_b);
+  }
+
   static void entered_readline_hook (void)
   {
     if (enabled ())
@@ -132,10 +140,11 @@
       instance->do_change_directory (dir);
   }
 
-  static void set_workspace (const std::list<workspace_element>& ws)
+  static void set_workspace (bool top_level,
+                             const std::list<workspace_element>& ws)
   {
     if (enabled ())
-      instance->do_set_workspace (ws);
+      instance->do_set_workspace (top_level, ws);
   }
 
   static void clear_workspace (void)
@@ -269,7 +278,8 @@
   virtual void do_change_directory (const std::string& dir) = 0;
 
   virtual void
-  do_set_workspace (const std::list<workspace_element>& ws) = 0;
+  do_set_workspace (bool top_level,
+                    const std::list<workspace_element>& ws) = 0;
 
   virtual void do_clear_workspace (void) = 0;
 
--- a/libinterp/interpfcn/symtab.h	Fri Apr 12 19:10:32 2013 +0200
+++ b/libinterp/interpfcn/symtab.h	Fri Apr 12 14:50:56 2013 -0400
@@ -527,6 +527,8 @@
 
     const std::string& name (void) const { return rep->name; }
 
+    void rename (const std::string& new_name) { rep->name = new_name; }
+
     octave_value
     find (const octave_value_list& args = octave_value_list ()) const;
 
@@ -1283,6 +1285,16 @@
     return inst ? inst->do_insert (name) : foobar;
   }
 
+  static void rename (const std::string& old_name,
+                      const std::string& new_name,
+                      scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_rename (old_name, new_name);
+  }
+
   static void assign (const std::string& name,
                       const octave_value& value = octave_value (),
                       scope_id scope = xcurrent_scope,
@@ -2462,6 +2474,22 @@
       return p->second;
   }
 
+  void do_rename (const std::string& old_name, const std::string& new_name)
+  {
+    table_iterator p = table.find (old_name);
+
+    if (p != table.end ())
+      {
+        symbol_record sr = p->second;
+
+        sr.rename (new_name);
+
+        table.erase (p);
+
+        table[new_name] = sr;
+      }
+  }
+
   void do_assign (const std::string& name, const octave_value& value,
                   context_id context, bool force_add)
   {