GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
workspace-view.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2013-2018 John W. Eaton
4 Copyright (C) 2011-2018 Jacob Dawid
5 
6 This file is part of Octave.
7 
8 Octave is free software: you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <https://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27 
28 #include <QInputDialog>
29 #include <QApplication>
30 #include <QClipboard>
31 #include <QMessageBox>
32 #include <QLineEdit>
33 #include <QHeaderView>
34 #include <QHBoxLayout>
35 #include <QVBoxLayout>
36 #include <QPushButton>
37 #include <QMenu>
38 #include <QLabel>
39 #include <QCompleter>
40 #include <QSignalMapper>
41 
42 #include "workspace-view.h"
43 #include "resource-manager.h"
44 
45 #include "interpreter-private.h"
46 #include "symscope.h"
47 
48 namespace octave
49 {
51  : octave_dock_widget (p), m_view (new QTableView (this))
52  {
53  setObjectName ("WorkspaceView");
54  setWindowIcon (QIcon (":/actions/icons/logo.png"));
55  set_title (tr ("Workspace"));
56  setStatusTip (tr ("View the variables in the active workspace."));
57 
58  m_filter = new QComboBox (this);
59  m_filter->setToolTip (tr ("Enter text to filter the workspace"));
60  m_filter->setEditable (true);
61  m_filter->setMaxCount (MaxFilterHistory);
62  m_filter->setInsertPolicy (QComboBox::NoInsert);
63  m_filter->setSizeAdjustPolicy (QComboBox::AdjustToMinimumContentsLengthWithIcon);
64  QSizePolicy sizePol (QSizePolicy::Expanding, QSizePolicy::Preferred);
65  m_filter->setSizePolicy (sizePol);
66  m_filter->completer ()->setCaseSensitivity (Qt::CaseSensitive);
67 
68  QLabel *filter_label = new QLabel (tr ("Filter"));
69 
70  m_filter_checkbox = new QCheckBox ();
71 
72  m_view->setWordWrap (false);
73  m_view->setContextMenuPolicy (Qt::CustomContextMenu);
74  m_view->setShowGrid (false);
75  (m_view->verticalHeader) ()->hide ();
76  m_view->setAlternatingRowColors (true);
78 
79  // Set an empty widget, so we can assign a layout to it.
80  setWidget (new QWidget (this));
81 
82  // Create the layouts
83  m_filter_widget = new QWidget (this);
84  QHBoxLayout *filter_layout = new QHBoxLayout ();
85 
86  filter_layout->addWidget (filter_label);
87  filter_layout->addWidget (m_filter_checkbox);
88  filter_layout->addWidget (m_filter);
89  filter_layout->setMargin(0);
90  m_filter_widget->setLayout (filter_layout);
91 
92  QVBoxLayout *ws_layout = new QVBoxLayout ();
93  ws_layout->addWidget (m_filter_widget);
94  ws_layout->addWidget (m_view);
95 
96  QSettings *settings = resource_manager::get_settings ();
97 
98  if (settings)
99  {
100  m_filter_shown = settings->value ("workspaceview/filter_shown",true).toBool ();
101  m_filter_widget->setVisible (m_filter_shown);
102 
103  ws_layout->setMargin (2);
104 
105  // Set the empty widget to have our layout.
106  widget ()->setLayout (ws_layout);
107 
108  // Initialize collapse/expand state of the workspace subcategories.
109 
110  //enable sorting (setting column and order after model was set)
111  m_view->setSortingEnabled (true);
112  // Initialize column order and width of the workspace
113  m_view->horizontalHeader ()->restoreState (
114  settings->value ("workspaceview/column_state").toByteArray ());
115 
116  // Set header properties for sorting
117 #if defined (HAVE_QHEADERVIEW_SETSECTIONSCLICKABLE)
118  m_view->horizontalHeader ()->setSectionsClickable (true);
119 #else
120  m_view->horizontalHeader ()->setClickable (true);
121 #endif
122 #if defined (HAVE_QHEADERVIEW_SETSECTIONSMOVABLE)
123  m_view->horizontalHeader ()->setSectionsMovable (true);
124 #else
125  m_view->horizontalHeader ()->setMovable (true);
126 #endif
127  m_view->horizontalHeader ()->setSortIndicator (settings->value ("workspaceview/sort_by_column",0).toInt (),
128  static_cast<Qt::SortOrder>
129  (settings->value ("workspaceview/sort_order", Qt::AscendingOrder).toUInt ()));
130  m_view->horizontalHeader ()->setSortIndicatorShown (true);
131 
132  m_view->horizontalHeader ()->setContextMenuPolicy (Qt::CustomContextMenu);
133  connect (m_view->horizontalHeader (),
134  SIGNAL (customContextMenuRequested (const QPoint &)),
135  this, SLOT (header_contextmenu_requested (const QPoint &)));
136 
137  // Init state of the filter
138  m_filter->addItems (settings->value ("workspaceview/mru_list").toStringList ());
139 
140  bool filter_state =
141  settings->value ("workspaceview/filter_active", false).toBool ();
142  m_filter_checkbox->setChecked (filter_state);
143  filter_activate (filter_state);
144  }
145 
146  // Connect signals and slots.
147 
148  connect (m_filter, SIGNAL (editTextChanged (const QString&)),
149  this, SLOT (filter_update (const QString&)));
150  connect (m_filter_checkbox, SIGNAL (toggled (bool)),
151  this, SLOT (filter_activate (bool)));
152  connect (m_filter->lineEdit (), SIGNAL (editingFinished ()),
153  this, SLOT (update_filter_history ()));
154 
155  connect (m_view, SIGNAL (customContextMenuRequested (const QPoint&)),
156  this, SLOT (contextmenu_requested (const QPoint&)));
157 
158  connect (m_view, SIGNAL (activated (QModelIndex)),
159  this, SLOT (handle_contextmenu_edit (void)));
160 
161  connect (this, SIGNAL (command_requested (const QString&)),
162  p, SLOT (execute_command_in_terminal (const QString&)));
163 
164  connect (this,
165  SIGNAL (edit_variable_signal (const QString&, const octave_value&)),
166  p, SLOT (edit_variable (const QString&, const octave_value&)));
167  }
168 
170  {
171  m_filter_model.setSourceModel (model);
172  m_filter_model.setFilterKeyColumn(0);
173 
174  m_view->setModel (&m_filter_model);
175 
176  // set the sorting after a model was set, it would be ignored otherwise
177  QSettings *settings = resource_manager::get_settings ();
178  m_view->sortByColumn (settings->value ("workspaceview/sort_by_column",0).toInt (),
179  static_cast<Qt::SortOrder> (settings->value ("workspaceview/sort_order", Qt::AscendingOrder).toUInt ()));
180 
181  m_model = model;
182  }
183 
184  void
185  workspace_view::notice_settings (const QSettings *settings)
186  {
187  int i;
188 
189  m_model->notice_settings (settings); // update colors of model first
190 
191  for (i = 0; i < m_columns_shown_keys.size (); i++)
192  m_view->setColumnHidden (i + 1, ! settings->value (m_columns_shown_keys.at (i),true).toBool ());
193 
194  QString tool_tip;
195 
196  if (! settings->value ("workspaceview/hide_tool_tips",false).toBool ())
197  {
198  tool_tip = QString (tr ("View the variables in the active workspace.<br>"));
199  tool_tip += QString (tr ("Colors for variable attributes:"));
200  for (i = 0; i < resource_manager::storage_class_chars ().length (); i++)
201  {
202  tool_tip +=
203  QString (R"(<div style="background-color:%1;color:#000000">%2</div>)")
204  .arg (m_model->storage_class_color (i).name ())
206  }
207  }
208 
209  setToolTip (tool_tip);
210 
211  m_columns_shown = QStringList ();
212  m_columns_shown.append (tr ("Class"));
213  m_columns_shown.append (tr ("Dimension"));
214  m_columns_shown.append (tr ("Value"));
215  m_columns_shown.append (tr ("Attribute"));
216 
217  m_columns_shown_keys = QStringList ();
218  m_columns_shown_keys.append ("workspaceview/show_class");
219  m_columns_shown_keys.append ("workspaceview/show_dimension");
220  m_columns_shown_keys.append ("workspaceview/show_value");
221  m_columns_shown_keys.append ("workspaceview/show_attribute");
222 
223  m_sig_mapper = nullptr;
224  }
225 
226  void
228  {
229  QSettings *settings = resource_manager::get_settings ();
230 
231  if (! settings)
232  return;
233 
234  settings->setValue ("workspaceview/column_state",
235  m_view->horizontalHeader ()->saveState ());
236 
237  int sort_column = m_view->horizontalHeader ()->sortIndicatorSection ();
238  Qt::SortOrder sort_order = m_view->horizontalHeader ()->sortIndicatorOrder ();
239  settings->setValue ("workspaceview/sort_by_column", sort_column);
240  settings->setValue ("workspaceview/sort_order", sort_order);
241 
242  settings->setValue ("workspaceview/filter_active",
243  m_filter_checkbox->isChecked ());
244  settings->setValue ("workspaceview/filter_shown", m_filter_shown);
245 
246  QStringList mru;
247  for (int i = 0; i < m_filter->count (); i++)
248  mru.append (m_filter->itemText (i));
249  settings->setValue ("workspaceview/mru_list", mru);
250 
251  settings->sync ();
252 
254 
255  if (m_sig_mapper)
256  delete m_sig_mapper;
257  }
258 
259  void
261  {
262  emit active_changed (false);
263  QDockWidget::closeEvent (e);
264  }
265 
266  void
267  workspace_view::filter_update (const QString& expression)
268  {
269  m_filter_model.setFilterWildcard (expression);
271  }
272 
273  void
275  {
276  m_filter->setEnabled (state);
277  m_filter_model.setDynamicSortFilter (state);
278 
279  if (state)
280  filter_update (m_filter->currentText ());
281  else
282  filter_update (QString ());
283  }
284 
285  void
287  {
288  QString text = m_filter->currentText (); // get current text
289  int index = m_filter->findText (text); // and its actual index
290 
291  if (index > -1)
292  m_filter->removeItem (index); // remove if already existing
293 
294  m_filter->insertItem (0, text); // (re)insert at beginning
295  m_filter->setCurrentIndex (0);
296  }
297 
298  void
300  {
301  QMenu menu (this);
302 
303  if (m_sig_mapper)
304  delete m_sig_mapper;
305  m_sig_mapper = new QSignalMapper (this);
306 
307  QSettings *settings = resource_manager::get_settings ();
308 
309  for (int i = 0; i < m_columns_shown.size (); i++)
310  {
311  QAction *action = menu.addAction (m_columns_shown.at (i),
312  m_sig_mapper, SLOT (map ()));
313  m_sig_mapper->setMapping (action, i);
314  action->setCheckable (true);
315  action->setChecked (settings->value (m_columns_shown_keys.at (i),true).toBool ());
316  }
317 
318  connect (m_sig_mapper, SIGNAL (mapped (int)), this, SLOT (toggle_header (int)));
319 
320  menu.exec (m_view->mapToGlobal (mpos));
321  }
322 
323  void
325  {
326  QSettings *settings = resource_manager::get_settings ();
327 
328  QString key = m_columns_shown_keys.at (col);
329  bool shown = settings->value (key,true).toBool ();
330 
331  m_view->setColumnHidden (col + 1, shown);
332 
333  settings->setValue (key, ! shown);
334  settings->sync ();
335 
337  }
338 
339  void
341  {
342  QMenu menu (this);
343 
344  QModelIndex index = m_view->indexAt (qpos);
345 
346  // if it isnt Local, Glocal etc, allow the ctx menu
347  if (index.isValid () && index.column () == 0)
348  {
349  QString var_name = get_var_name (index);
350 
351  menu.addAction (tr ("Open in Variable Editor"), this,
352  SLOT (handle_contextmenu_edit ()));
353 
354  menu.addAction (tr ("Copy name"), this,
355  SLOT (handle_contextmenu_copy ()));
356 
357  menu.addAction (tr ("Copy value"), this,
359 
360  QAction *rename = menu.addAction (tr ("Rename"), this,
361  SLOT (handle_contextmenu_rename ()));
362 
363  QAbstractItemModel *m = m_view->model ();
364  const workspace_model *wm = static_cast<const workspace_model *> (m);
365 
366  if (! wm->is_top_level ())
367  {
368  rename->setDisabled (true);
369  rename->setToolTip (tr ("Only top-level symbols may be renamed"));
370  }
371 
372  menu.addAction ("Clear " + var_name, this,
373  SLOT (handle_contextmenu_clear ()));
374 
375  menu.addSeparator ();
376 
377  menu.addAction ("disp (" + var_name + ')', this,
378  SLOT (handle_contextmenu_disp ()));
379 
380  menu.addAction ("plot (" + var_name + ')', this,
381  SLOT (handle_contextmenu_plot ()));
382 
383  menu.addAction ("stem (" + var_name + ')', this,
384  SLOT (handle_contextmenu_stem ()));
385 
386  menu.addSeparator ();
387 
388  }
389 
390  if (m_filter_shown)
391  menu.addAction (tr ("Hide filter"), this,
392  SLOT (handle_contextmenu_filter ()));
393  else
394  menu.addAction (tr ("Show filter"), this,
395  SLOT (handle_contextmenu_filter ()));
396 
397  menu.exec (m_view->mapToGlobal (qpos));
398  }
399 
400  void
402  {
403  QModelIndex index = m_view->currentIndex ();
404 
405  if (index.isValid ())
406  {
407  QString var_name = get_var_name (index);
408 
409  QClipboard *clipboard = QApplication::clipboard ();
410 
411  clipboard->setText (var_name);
412  }
413  }
414 
415  void
417  {
418  QModelIndex index = m_view->currentIndex ();
419 
420  if (index.isValid ())
421  {
422  QString var_name = get_var_name (index);
423 
424  symbol_scope scope
425  = __get_current_scope__ ("workspace_view::handle_contextmenu_copy_value");
426 
427  octave_value val = scope ? scope.varval (var_name.toStdString ()) : 0;
428  std::ostringstream buf;
429  val.print_raw (buf, true);
430 
431  QClipboard *clipboard = QApplication::clipboard ();
432  clipboard->setText (QString::fromStdString (buf.str ()));
433  }
434  }
435 
436  void
438  {
439  QModelIndex index = m_view->currentIndex ();
440 
441  if (index.isValid ())
442  {
443  QString var_name = get_var_name (index);
444 
445  QInputDialog *inputDialog = new QInputDialog ();
446 
447  inputDialog->setOptions (QInputDialog::NoButtons);
448 
449  bool ok = false;
450 
451  QString new_name
452  = inputDialog->getText (nullptr, "Rename Variable", "New name:",
453  QLineEdit::Normal, var_name, &ok);
454 
455  if (ok && ! new_name.isEmpty ())
456  {
457  QAbstractItemModel *m = m_view->model ();
458  m->setData (index, new_name, Qt::EditRole);
459  }
460  }
461  }
462 
463  void
465  {
466  QModelIndex index = m_view->currentIndex ();
467 
468  if (index.isValid ())
469  {
470  QString var_name = get_var_name (index);
471 
472  symbol_scope scope = m_model->scope ();
473 
475  if (scope)
476  val = scope.varval (var_name.toStdString ());
477 
478  emit edit_variable_signal (var_name, val);
479  }
480  }
481 
482  void
484  {
485  relay_contextmenu_command ("clear", true);
486  }
487 
488  void
490  {
491  relay_contextmenu_command ("disp");
492  }
493 
494  void
496  {
497  relay_contextmenu_command ("figure (); plot");
498  }
499 
500  void
502  {
503  relay_contextmenu_command ("figure (); stem");
504  }
505 
506  void
508  {
510  m_filter_widget->setVisible (m_filter_shown);
511  }
512 
513  void
515  {
516  // m_view->resizeRowsToContents ();
517  // Just modify those rows that have been added rather than go through
518  // the whole list. For-loop test will handle when number of rows reduced.
519  QFontMetrics fm = m_view->fontMetrics ();
520  int row_height = fm.height ();
521  int new_row_count = m_filter_model.rowCount ();
522  for (int i = m_view_previous_row_count; i < new_row_count; i++)
523  m_view->setRowHeight (i, row_height);
524  m_view_previous_row_count = new_row_count;
525  }
526 
527  void
529  {
530  if (m_view->hasFocus ())
532  }
533 
534  void
536  {
537  if (m_view->hasFocus ())
538  m_view->selectAll ();
539  }
540 
541  void
542  workspace_view::relay_contextmenu_command (const QString& cmdname, bool str)
543  {
544  QModelIndex index = m_view->currentIndex ();
545 
546  if (index.isValid ())
547  {
548  QString var_name;
549 
550  if (str)
551  var_name = "\'" + get_var_name (index) + "\'";
552  else
553  var_name = get_var_name (index);
554 
555  emit command_requested (cmdname + " (" + var_name + ");");
556  }
557  }
558 
559  QString
560  workspace_view::get_var_name (const QModelIndex& index)
561  {
562  // We are using a sort model proxy so m_model won't provide the
563  // correct ordering.
564 
565  QAbstractItemModel *m = m_view->model ();
566 
567  QMap<int, QVariant> item_data
568  = m->itemData (index.sibling (index.row (), 0));
569 
570  return item_data[0].toString ();
571  }
572 }
void relay_contextmenu_command(const QString &cmdname, bool str=false)
void toggle_header(int column)
workspace_model * m_model
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:4986
void closeEvent(QCloseEvent *event)
symbol_scope scope(void) const
void active_changed(bool active)
Custom signal that tells whether a user has clicked away that dock widget, i.e the active dock widget...
QString fromStdString(const std::string &s)
void header_contextmenu_requested(const QPoint &mpos)
QSortFilterProxyModel m_filter_model
symbol_scope __get_current_scope__(const std::string &who)
QStringList m_columns_shown_keys
i e
Definition: data.cc:2591
void handle_contextmenu_disp(void)
octave_value arg
Definition: pr-output.cc:3244
void handle_contextmenu_copy_value(void)
int rename(const std::string &from, const std::string &to)
Definition: file-ops.cc:498
workspace_view(QWidget *parent=nullptr)
void command_requested(const QString &cmd)
Signal that user had requested a command on a variable.
QColor storage_class_color(int s_class)
void handle_contextmenu_rename(void)
static QString storage_class_chars(void)
std::string str
Definition: hash.cc:118
QString get_var_name(const QModelIndex &index)
void handle_contextmenu_edit(void)
returns the type of the matrix and caches it for future use Called with more than one the function will not attempt to guess the type if it is still unknown This is useful for debugging purposes The possible matrix types depend on whether the matrix is full or and can be one of the following able sis tem and mark type as unknown tem as the structure of the matrix explicitly gives this(Sparse matrices only) tem code
Definition: matrix_type.cc:120
bool is_top_level(void) const
void update_filter_history(void)
static QStringList storage_class_names(void)
void handle_contextmenu_plot(void)
void filter_update(const QString &expression)
void set_title(const QString &)
octave_value varval(const std::string &name) const
Definition: symscope.h:727
static uint32_t state[624]
Definition: randmtzig.cc:183
void handle_contextmenu_stem(void)
p
Definition: lu.cc:138
octave_map map(dims)
void handle_contextmenu_filter(void)
void handle_contextmenu_copy(void)
static QSettings * get_settings(void)
void filter_activate(bool enable)
QSignalMapper * m_sig_mapper
for i
Definition: data.cc:5264
void setModel(workspace_model *model)
void handle_contextmenu_clear(void)
void contextmenu_requested(const QPoint &pos)
void edit_variable_signal(const QString &, const octave_value &)
Signal that user wants to edit a variable.
void notice_settings(const QSettings *)
QCheckBox * m_filter_checkbox
void notice_settings(const QSettings *)