GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
variable-editor.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2013-2018 John W. Eaton
4 Copyright (C) 2015 Michael Barnes
5 Copyright (C) 2013 RĂ¼diger Sonderfeld
6 
7 This file is part of Octave.
8 
9 Octave is free software: you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation, either version 3 of the License, or (at your
12 option) any later version.
13 
14 Octave is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Octave; see the file COPYING. If not, see
21 <https://www.gnu.org/licenses/>.
22 
23 */
24 
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28 
29 #include <limits>
30 
31 #include <QApplication>
32 #include <QClipboard>
33 #include <QFileDialog>
34 #include <QHeaderView>
35 #include <QLabel>
36 #include <QMdiArea>
37 #include <QMenu>
38 #include <QPalette>
39 #include <QScreen>
40 #include <QScrollBar>
41 #include <QSignalMapper>
42 #include <QStackedWidget>
43 #include <QTableView>
44 #include <QTextEdit>
45 #include <QTabWidget>
46 #include <QToolBar>
47 #include <QToolButton>
48 #include <QVBoxLayout>
49 
50 #include "resource-manager.h"
51 #include "shortcut-manager.h"
52 #include "variable-editor.h"
53 #include "variable-editor-model.h"
54 
55 // Code reuse functions
56 
57 static QString
58 idx_to_expr (int32_t from, int32_t to)
59 {
60  return (from == to
61  ? QString ("%1").arg (from)
62  : QString ("%1:%2").arg (from).arg (to));
63 }
64 
65 static QSignalMapper *
67 {
69  list << "plot" << "bar" << "stem" << "stairs" << "area" << "pie" << "hist";
70 
71  QSignalMapper *plot_mapper = new QSignalMapper (menu);
72 
73  for (int i = 0; i < list.size(); ++i)
74  {
75  plot_mapper->setMapping
76  (menu->addAction (list.at (i), plot_mapper, SLOT (map ())),
77  "figure (); " + list.at (i) + " (%1); title (\"%1\");");
78  }
79 
80  return plot_mapper;
81 }
82 
83 namespace octave
84 {
85  // Variable dock widget
86 
89  {
90  setFocusPolicy (Qt::StrongFocus);
91  setAttribute (Qt::WA_DeleteOnClose);
92 
93  connect (m_dock_action, SIGNAL (triggered (bool)),
94  this, SLOT (change_floating (bool)));
95  connect (m_close_action, SIGNAL (triggered (bool)),
96  this, SLOT (change_existence (bool)));
97  connect (this, SIGNAL (topLevelChanged(bool)),
98  this, SLOT (toplevel_change (bool)));
99  connect (p, SIGNAL (visibilityChanged (bool)),
100  this, SLOT (setVisible (bool)));
101 
102 #if defined (HAVE_QGUIAPPLICATION)
103 #define DOCKED_FULLSCREEN_BUTTON_TOOLTIP "Fullscreen undock"
104 #define UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP "Fullscreen"
105  // Add a fullscreen button
106 
107  m_fullscreen_action = nullptr;
108  m_full_screen = false;
109  m_prev_floating = false;
110  m_prev_geom = QRect (0, 0, 0, 0);
111 
112  QHBoxLayout *h_layout = findChild<QHBoxLayout *> ();
113  if (h_layout != nullptr && titleBarWidget () != nullptr)
114  {
115  m_fullscreen_action = new QAction
116  (resource_manager::icon ("view-fullscreen", false), "", this);
117  m_fullscreen_action->setToolTip (tr (DOCKED_FULLSCREEN_BUTTON_TOOLTIP));
118  QToolButton *fullscreen_button = new QToolButton (titleBarWidget ());
119  fullscreen_button->setDefaultAction (m_fullscreen_action);
120  fullscreen_button->setFocusPolicy (Qt::NoFocus);
121  fullscreen_button->setIconSize (QSize (m_icon_size,m_icon_size));
122  QString css_button = QString ("QToolButton {background: transparent; border: 0px;}");
123  fullscreen_button->setStyleSheet (css_button);
124 
125  connect (m_fullscreen_action, SIGNAL (triggered ()),
126  this, SLOT (change_fullscreen ()));
127 
128  int index = -1;
129  QToolButton *first = titleBarWidget ()->findChild<QToolButton *> ();
130  if (first != nullptr)
131  index = h_layout->indexOf (first);
132  h_layout->insertWidget (index, fullscreen_button);
133  }
134 #endif
135 
136  // Custom title bars cause loss of decorations, add a frame
137  m_frame = new QFrame (this);
138  m_frame->setFrameStyle (QFrame::Box | QFrame::Sunken);
139  m_frame->setAttribute (Qt::WA_TransparentForMouseEvents);
140  }
141 
142  // slot for (un)dock action
143  void
145  {
146 #if defined (HAVE_QGUIAPPLICATION)
147  if (isFloating ())
148  {
149  if (m_full_screen)
150  {
151  setGeometry (m_prev_geom);
152  m_fullscreen_action->setIcon (resource_manager::icon ("view-fullscreen", false));
153  m_full_screen = false;
154  }
155  m_fullscreen_action->setToolTip (tr (DOCKED_FULLSCREEN_BUTTON_TOOLTIP));
156  }
157  else
158  m_fullscreen_action->setToolTip (tr (UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP));
159 #endif
160 
161  setFloating (! isFloating ());
162  }
163 
164  // slot for hiding the widget
165  void
167  {
168  close ();
169  }
170 
171  void
173  {
174  if (toplevel)
175  {
176  m_dock_action->setIcon (QIcon (":/actions/icons/widget-dock.png"));
177  m_dock_action->setToolTip (tr ("Dock widget"));
178 
179  activateWindow();
180  setFocus (Qt::OtherFocusReason);
181  }
182  else
183  {
184  m_dock_action->setIcon (QIcon (":/actions/icons/widget-undock.png"));
185  m_dock_action->setToolTip (tr ("Undock widget"));
186 
187  setFocus (Qt::OtherFocusReason);
188  }
189  }
190 
191  void
193  {
194 #if defined (HAVE_QGUIAPPLICATION)
195  if (! m_full_screen)
196  {
197  m_prev_floating = isFloating ();
198  m_prev_geom = geometry ();
199 
200  m_fullscreen_action->setIcon (resource_manager::icon ("view-restore", false));
201  if (m_prev_floating)
202  m_fullscreen_action->setToolTip (tr ("Restore geometry"));
203  else
204  {
205  m_fullscreen_action->setToolTip (tr ("Redock"));
206  setFloating (true);
207  }
208 
209  // showFullscreen() and setWindowState() only work for QWindow objects.
210  QScreen *pscreen = QGuiApplication::primaryScreen ();
211  QRect rect (0, 0, 0, 0);
212  rect = pscreen->availableGeometry ();
213  setGeometry (rect);
214 
215  m_full_screen = true;
216  }
217  else
218  {
219  m_fullscreen_action->setIcon (resource_manager::icon ("view-fullscreen", false));
220  setGeometry (m_prev_geom);
221  if (m_prev_floating)
222  m_fullscreen_action->setToolTip (tr (UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP));
223  else
224  {
225  setFloating (false);
226  m_fullscreen_action->setToolTip (tr (DOCKED_FULLSCREEN_BUTTON_TOOLTIP));
227  }
228 
229  m_full_screen = false;
230  }
231 #undef DOCKED_FULLSCREEN_BUTTON_TOOLTIP
232 #undef UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP
233 #endif
234  }
235 
236  void
238  {
239  QDockWidget::closeEvent (e);
240  }
241 
242  void
244  {
245  octave_unused_parameter (now);
246 
247  // The is a proxied test
248  if (hasFocus ())
249  {
250  QLabel *label = titleBarWidget ()->findChild<QLabel *> ();
251  if (label != nullptr)
252  {
253  label->setBackgroundRole (QPalette::Highlight);
254  label->setAutoFillBackground (true);
255  }
256 
257  emit variable_focused_signal (objectName ());
258  }
259  else if (old == focusWidget())
260  {
261  QLabel *label = titleBarWidget ()->findChild<QLabel *> ();
262  if (label != NULL)
263  label->setBackgroundRole (QPalette::NoRole);
264  }
265  }
266 
267  void variable_dock_widget::resizeEvent (QResizeEvent *)
268  {
269  if (m_frame)
270  m_frame->resize (size ());
271  }
272 
273 
274  // Variable editor stack
275 
277  : QStackedWidget (p), m_edit_view (new variable_editor_view (this))
278  {
279  setFocusPolicy (Qt::StrongFocus);
280 
281  m_disp_view = make_disp_view (this);
282 
283  addWidget (m_edit_view);
284  addWidget (m_disp_view);
285  }
286 
287  QTextEdit *
289  {
290  QTextEdit *viewer = new QTextEdit (parent);
291 
292  viewer->setLineWrapMode (QTextEdit::NoWrap);
293  viewer->setReadOnly (true);
294 
295  return viewer;
296  }
297 
298  void
300  {
301  // The QTableView is for editable data models
302  // and the QTextEdit is for non-editable models.
303 
304  if (editable)
305  {
306  if (m_edit_view != nullptr)
307  {
308  setCurrentWidget (m_edit_view);
309  setFocusProxy (m_edit_view);
310  m_edit_view->setFocusPolicy (Qt::StrongFocus);
311  }
312 
313  if (m_disp_view != nullptr)
314  m_disp_view->setFocusPolicy (Qt::NoFocus);
315  }
316  else
317  {
318  if (m_disp_view != nullptr)
319  {
320  setCurrentWidget (m_disp_view);
321  setFocusProxy (m_disp_view);
322 
323  QAbstractTableModel *model = findChild<QAbstractTableModel *> ();
324  if (model != nullptr)
325  m_disp_view->setPlainText (model->data (QModelIndex ()).toString ());
326  else
327  m_disp_view->setPlainText ("");
328  }
329 
330  if (m_edit_view != nullptr)
331  m_edit_view->setFocusPolicy (Qt::NoFocus);
332  }
333  }
334 
335  void
337  {
338  if (! hasFocus ())
339  return;
340 
341  QString name = objectName ();
342 
343  // FIXME: Is there a better way?
344 
345  if (name.endsWith (')') || name.endsWith ('}'))
346  {
347  name.remove (QRegExp ("(\\(|\\{)[^({]*(\\)|\\})$"));
349  }
350  }
351 
352  void
354  {
355  if (! hasFocus ())
356  return;
357 
358  QString name = objectName ();
359  QString file
360  = QFileDialog::getSaveFileName (this,
361  tr ("Save Variable %1 As").arg (name),
362  // FIXME: Should determine extension from save_default_options
363  QString ("./%1.txt").arg (name),
364  0, 0,
365  QFileDialog::DontUseNativeDialog);
366 
367  // FIXME: Type? binary, float-binary, ascii, text, hdf5, matlab format?
368  // FIXME: Call octave_value::save_* directly?
369 
370  if (! file.isEmpty ())
371  emit command_signal (QString ("save (\"%1\", \"%2\");")
372  .arg (file)
373  .arg (name));
374  }
375 
376 
377  // Custom editable variable table view
378 
380  : QTableView (p), m_var_model (nullptr)
381  {
382  setWordWrap (false);
383  setContextMenuPolicy (Qt::CustomContextMenu);
384  setSelectionMode (QAbstractItemView::ContiguousSelection);
385 
386  horizontalHeader ()->setContextMenuPolicy (Qt::CustomContextMenu);
387  verticalHeader ()->setContextMenuPolicy (Qt::CustomContextMenu);
388 
389  setHorizontalScrollMode (QAbstractItemView::ScrollPerPixel);
390  setVerticalScrollMode (QAbstractItemView::ScrollPerPixel);
391 
392 #if defined (HAVE_QHEADERVIEW_SETSECTIONRESIZEMODE)
393  verticalHeader ()->setSectionResizeMode (QHeaderView::Interactive);
394 #else
395  verticalHeader ()->setResizeMode (QHeaderView::Interactive);
396 #endif
397  }
398 
399  void
400  variable_editor_view::setModel (QAbstractItemModel *model)
401  {
402  QTableView::setModel (model);
403 
404 #if defined (HAVE_QHEADERVIEW_SETSECTIONRESIZEMODE)
405  horizontalHeader ()->setSectionResizeMode (QHeaderView::Interactive);
406 #else
407  horizontalHeader ()->setResizeMode (QHeaderView::Interactive);
408 #endif
409 
410  m_var_model = parent ()->findChild<variable_editor_model *> ();
411 
412  if (m_var_model != nullptr && m_var_model->column_width () > 0)
413  {
414  // col_width is in characters. The font should be a fixed-width
415  // font, so any character will do. If not, you lose!
416 
417  QFontMetrics fm (font ());
418  int w = m_var_model->column_width () * fm.width ('0');
419  horizontalHeader ()->setDefaultSectionSize (w);
420  }
421  }
422 
423  QList<int>
425  {
426  QItemSelectionModel *sel = selectionModel ();
427 
428  // Return early if nothing selected.
429  if (! sel->hasSelection ())
430  return QList<int> ();
431 
432  QList<QModelIndex> indices = sel->selectedIndexes ();
433 
434  // FIXME: Shouldn't this be keyed to octave_idx_type?
435 
436  int32_t from_row = std::numeric_limits<int32_t>::max ();
437  int32_t to_row = 0;
438  int32_t from_col = std::numeric_limits<int32_t>::max ();
439  int32_t to_col = 0;
440 
441  for (const auto& idx : indices)
442  {
443  from_row = std::min (from_row, idx.row ());
444  to_row = std::max (to_row, idx.row ());
445  from_col = std::min (from_col, idx.column ());
446  to_col = std::max (to_col, idx.column ());
447  }
448 
449  QVector<int> vect;
450  vect << from_row + 1 << to_row + 1 << from_col + 1 << to_col + 1;
452 
453  return range;
454  }
455 
456  QString
458  {
460  if (range.isEmpty ())
461  return objectName ();
462 
463  QString rows = idx_to_expr (range.at (0), range.at (1));
464  QString cols = idx_to_expr (range.at (2), range.at (3));
465 
466  // FIXME: Does cell need separate handling? Maybe use '{.,.}'?
467 
468  return QString ("%1(%2, %3)").arg (objectName ()).arg (rows).arg (cols);
469  }
470 
471  void
473  {
474  if (! hasFocus ())
475  return;
476 
477  QString selarg = selected_to_octave ();
478  if (! selarg.isEmpty ())
479  emit command_signal (cmd.arg (selarg));
480  }
481 
482  void
484  const QString& qualifier_string)
485  {
486  menu->addAction (resource_manager::icon ("edit-cut"),
487  tr ("Cut") + qualifier_string,
488  this, SLOT (cutClipboard ()));
489 
490  menu->addAction (resource_manager::icon ("edit-copy"),
491  tr ("Copy") + qualifier_string,
492  this, SLOT (copyClipboard ()));
493 
494  menu->addAction (resource_manager::icon ("edit-paste"),
495  tr ("Paste"),
496  this, SLOT (pasteClipboard ()));
497 
498  // FIXME: Different icon for Paste Table?
499 
500  menu->addAction (resource_manager::icon ("edit-paste"),
501  tr ("Paste Table"),
502  this, SLOT (pasteTableClipboard ()));
503 
504  menu->addSeparator ();
505 
506  menu->addAction (resource_manager::icon ("edit-delete"),
507  tr ("Clear") + qualifier_string,
508  this, SLOT (clearContent ()));
509 
510  menu->addAction (resource_manager::icon ("edit-delete"),
511  tr ("Delete") + qualifier_string,
512  this, SLOT (delete_selected ()));
513 
514  menu->addAction (resource_manager::icon ("document-new"),
515  tr ("Variable from Selection"),
516  this, SLOT (createVariable ()));
517  }
518 
519  void
521  {
522  QModelIndex index = indexAt (qpos);
523 
524  if (index.isValid ())
525  {
526  QMenu *menu = new QMenu (this);
527 
528  add_edit_actions (menu, tr (""));
529 
530  // FIXME: addAction for sort?
531  // FIXME: Add icon for transpose.
532 
533  menu->addAction (tr ("Transpose"), this, SLOT (transposeContent ()));
534 
535  QItemSelectionModel *sel = selectionModel ();
536 
537  QList<QModelIndex> indices = sel->selectedIndexes ();
538 
539  if (! indices.isEmpty ())
540  {
541  menu->addSeparator ();
542 
543  QSignalMapper *plot_mapper = make_plot_mapper (menu);
544 
545  connect (plot_mapper, SIGNAL (mapped (const QString&)),
546  this, SLOT (selected_command_requested (const QString&)));
547  }
548 
549  menu->exec (mapToGlobal (qpos));
550  }
551  }
552 
553  void
555  {
556  int index = horizontalHeader ()->logicalIndexAt (pt);
557 
558  if (index < 0 || index > model ()->columnCount ())
559  return;
560 
561  QList<int> coords = range_selected ();
562 
563  bool nothingSelected = coords.isEmpty ();
564 
565  bool whole_columns_selected
566  = (nothingSelected
567  ? false
568  : (coords[0] == 1 && coords[1] == model ()->rowCount ()));
569 
570  bool current_column_selected
571  = nothingSelected ? false : (coords[2] <= index+1 && coords[3] > index);
572 
573  int column_selection_count
574  = nothingSelected ? 0 : (coords[3] - coords[2] + 1);
575 
576  if (! whole_columns_selected || ! current_column_selected)
577  {
578  selectColumn (index);
579  column_selection_count = 1;
580  current_column_selected = true;
581  whole_columns_selected = true;
582  }
583 
584  QString column_string
585  = tr (column_selection_count > 1 ? " columns" : " column");
586 
587  QMenu *menu = new QMenu (this);
588 
589  add_edit_actions (menu, column_string);
590 
591  menu->addSeparator ();
592 
593  QSignalMapper *plot_mapper = make_plot_mapper (menu);
594 
595  connect (plot_mapper, SIGNAL (mapped (const QString&)),
596  this, SLOT (selected_command_requested (const QString&)));
597 
598  QPoint menupos = pt;
599  menupos.setY (horizontalHeader ()->height ());
600 
601  menu->exec (mapToGlobal (menupos));
602  }
603 
604  void
606  {
607  int index = verticalHeader ()->logicalIndexAt (pt);
608 
609  if (index < 0 || index > model ()->columnCount ())
610  return;
611 
612  QList<int> coords = range_selected ();
613 
614  bool nothingSelected = coords.isEmpty ();
615 
616  bool whole_rows_selected
617  = (nothingSelected
618  ? false
619  : (coords[2] == 1 && coords[3] == model ()->columnCount ()));
620 
621  bool current_row_selected
622  = (nothingSelected ? false : (coords[0] <= index+1 && coords[1] > index));
623 
624  int rowselection_count = nothingSelected ? 0 : (coords[3] - coords[2] + 1);
625 
626  if (! whole_rows_selected || ! current_row_selected)
627  {
628  selectRow (index);
629  rowselection_count = 1;
630  current_row_selected = true;
631  whole_rows_selected = true;
632  }
633 
634  QString row_string = tr (rowselection_count > 1 ? " rows" : " row");
635 
636  QMenu *menu = new QMenu (this);
637 
638  add_edit_actions (menu, row_string);
639 
640  menu->addSeparator ();
641 
642  QSignalMapper *plot_mapper = make_plot_mapper (menu);
643 
644  connect (plot_mapper, SIGNAL (mapped (const QString&)),
645  this, SLOT (selected_command_requested (const QString&)));
646 
647  QPoint menupos = pt;
648  menupos.setX (verticalHeader ()->width ());
649 
650  // FIXME: What was the intent here?
651  // setY (verticalHeader ()->sectionPosition (index+1) +
652  // verticalHeader ()->sectionSize (index));
653 
654  menu->exec (mapToGlobal (menupos));
655  }
656 
657  void
659  {
660  // FIXME: Create unnamed1..n if exist ('unnamed', 'var') is true.
661 
662  selected_command_requested ("unnamed = %1");
663  }
664 
665  void
667  {
668  if (! hasFocus ())
669  return;
670 
671  emit command_signal (QString ("%1 = %1';").arg (objectName ()));
672  }
673 
674  void
676  {
677  if (! hasFocus ())
678  return;
679 
680  QAbstractItemModel *mod = model ();
681  QList<int> coords = range_selected ();
682 
683  if (coords.isEmpty ())
684  return;
685 
686  bool whole_columns_selected
687  = coords[0] == 1 && coords[1] == mod->rowCount ();
688 
689  bool whole_rows_selected
690  = coords[2] == 1 && coords[3] == mod->columnCount ();
691 
692  // Must be deleting whole columns or whole rows, and not the whole thing.
693 
694  if (whole_columns_selected == whole_rows_selected)
695  return;
696 
697  if (whole_rows_selected)
698  mod->removeRows (coords[0], coords[1] - coords[0]);
699 
700  if (whole_columns_selected)
701  mod->removeColumns (coords[2], coords[3] - coords[2]);
702  }
703 
704  void
706  {
707  if (! hasFocus ())
708  return;
709 
710  if (m_var_model == nullptr)
711  return;
712 
713  QItemSelectionModel *sel = selectionModel ();
714  QList<QModelIndex> indices = sel->selectedIndexes ();
715 
716  // FIXME: Use [] for empty cells?
717 
718  for (const auto& idx : indices)
719  m_var_model->clear_content (idx);
720  }
721 
722  void
724  {
725  copyClipboard ();
726 
727  clearContent ();
728  }
729 
730  void
732  {
733  if (! hasFocus ())
734  return;
735 
736  QItemSelectionModel *sel = selectionModel ();
737  QList<QModelIndex> indices = sel->selectedIndexes ();
738  qSort (indices);
739 
740  if (indices.isEmpty ())
741  return;
742 
743  // Convert selected items into TSV format and copy that.
744  // Spreadsheet tools should understand that.
745 
746  QAbstractItemModel *mod = model ();
747  QModelIndex previous = indices.first ();
748  QString copy = mod->data (previous).toString ();
749  indices.removeFirst ();
750  foreach (QModelIndex idx, indices)
751  {
752  copy.push_back (previous.row () != idx.row () ? '\n' : '\t');
753  copy.append (mod->data (idx).toString ());
754  previous = idx;
755  }
756 
757  QClipboard *clipboard = QApplication::clipboard ();
758  clipboard->setText (copy);
759  }
760 
761  void
763  {
764  if (! hasFocus ())
765  return;
766 
767  QAbstractItemModel *mod = model ();
768  QItemSelectionModel *sel = selectionModel ();
769  QList<QModelIndex> indices = sel->selectedIndexes ();
770 
771  QClipboard *clipboard = QApplication::clipboard ();
772  QString text = clipboard->text ();
773 
774  if (indices.isEmpty ())
775  {
776  if (size () == QSize (1,1))
777  mod->setData (mod->index (0,0), text.toDouble ());
778  else if (size () == QSize (0,0))
779  {
780  mod->insertColumn (0);
781  mod->insertRow (0);
782  mod->setData (mod->index (0,0), text.toDouble ());
783  }
784  }
785  else
786  {
787  QStringList cells = text.split(QRegExp("\n|\r\n|\r"));
788  int clen = cells.size ();
789  for (int i = 0; i < indices.size (); i++)
790  mod->setData (indices[i], cells.at (i % clen).toDouble ());
791  }
792  }
793 
795  {
796  if (! hasFocus ())
797  return;
798 
799  QAbstractItemModel *mod = model ();
800  QItemSelectionModel *sel = selectionModel ();
801  QList<QModelIndex> indices = sel->selectedIndexes ();
802 
803  QClipboard *clipboard = QApplication::clipboard ();
804  QString text = clipboard->text ();
805 
806  QPoint start, end;
807 
808  QPoint tabsize = QPoint (mod->rowCount (), mod->columnCount ());
809 
810  if (indices.isEmpty ())
811  {
812  start = QPoint (0,0);
813  end = tabsize;
814  }
815  else if (indices.size () == 1)
816  {
817  start = QPoint (indices[0].row (), indices[0].column ());
818  end = tabsize;
819  }
820  else
821  {
822  end = QPoint (0,0);
823  start = tabsize;
824 
825  for (int i = 0; i < indices.size (); i++)
826  {
827  if (indices[i].column () < start.y ())
828  start.setY (indices[i].column ());
829 
830  if (indices[i].column () > end.y ())
831  end.setY (indices[i].column ());
832 
833  if (indices[i].row () < start.x ())
834  start.setX (indices[i].column ());
835 
836  if (indices[i].row () > end.x ())
837  end.setX (indices[i].column ());
838  }
839  }
840 
841  int rownum = 0;
842  int colnum = 0;
843 
844  QStringList rows = text.split ('\n');
845  for (const auto& row : rows)
846  {
847  if (rownum > end.x () - start.x ())
848  continue;
849 
850  QStringList cols = row.split ('\t');
851  if (cols.isEmpty ())
852  continue;
853 
854  for (const auto& col : cols)
855  {
856  if (col.isEmpty ())
857  continue;
858  if (colnum > end.y () - start.y () )
859  continue;
860 
861  mod->setData (mod->index (rownum + start.x (),
862  colnum + start.y ()),
863  QVariant (col));
864 
865  colnum++;
866  }
867 
868  colnum = 0;
869  rownum++;
870  }
871  }
872 
873  void
875  {
876  if (action == QAbstractSlider::SliderSingleStepAdd
877  || action == QAbstractSlider::SliderPageStepAdd
878  || action == QAbstractSlider::SliderToMaximum
879  || action == QAbstractSlider::SliderMove)
880  {
881  if (m_var_model != nullptr)
882  {
883  QScrollBar *sb = horizontalScrollBar ();
884 
885  if (sb && sb->value () == sb->maximum ())
886  {
887  int new_cols = m_var_model->display_columns () + 16;
888 
889  m_var_model->maybe_resize_columns (new_cols);
890  }
891  }
892  }
893  }
894 
895  void
897  {
898  if (action == QAbstractSlider::SliderSingleStepAdd
899  || action == QAbstractSlider::SliderPageStepAdd
900  || action == QAbstractSlider::SliderToMaximum
901  || action == QAbstractSlider::SliderMove)
902  {
903  if (m_var_model != nullptr)
904  {
905  QScrollBar *sb = verticalScrollBar ();
906 
907  if (sb && sb->value () == sb->maximum ())
908  {
909  int new_rows = m_var_model->display_rows () + 16;
910 
911  m_var_model->maybe_resize_rows (new_rows);
912  }
913  }
914  }
915  }
916 
917 
918  // Gadgets for focus restoration
919 
921  : QToolButton (parent)
922  {
923  installEventFilter (this);
924  }
925 
926  bool HoverToolButton::eventFilter (QObject *obj, QEvent *ev)
927  {
928  if (ev->type () == QEvent::HoverEnter)
929  emit hovered_signal ();
930  else if (ev->type () == QEvent::MouseButtonPress ||
931  ev->type () == QEvent::MouseButtonPress)
932  emit popup_shown_signal ();
933 
934  return QToolButton::eventFilter (obj, ev);
935  }
936 
938  : HoverToolButton (parent)
939  {
940  installEventFilter (this);
941  }
942 
944  {
945 
946  if (ev->type () == QEvent::MouseButtonRelease && isDown ())
947  {
948  emit about_to_activate ();
949 
950  setDown (false);
951  QAction *action = defaultAction ();
952  if (action != nullptr)
953  action->activate (QAction::Trigger);
954 
955  return true;
956  }
957 
958  return HoverToolButton::eventFilter (obj, ev);
959  }
960 
962  : QMenu (parent)
963  {
964  installEventFilter (this);
965  }
966 
967  bool ReturnFocusMenu::eventFilter (QObject *obj, QEvent *ev)
968  {
969  if (ev->type () == QEvent::MouseButtonRelease && underMouse ())
970  {
971  emit about_to_activate ();
972  }
973 
974  return QMenu::eventFilter (obj, ev);
975  }
976 
977  // Variable editor.
978 
980  : octave_dock_widget (p),
981  m_main (new QMainWindow ()),
982  m_tool_bar (new QToolBar (m_main)),
983  m_default_width (30),
984  m_default_height (100),
985  m_add_font_height (0),
986  m_use_terminal_font (true),
987  m_alternate_rows (true),
988  m_stylesheet (""),
989  m_font (),
990  m_sel_font (),
991  m_table_colors (),
992  m_current_focus_vname (""),
993  m_hovered_focus_vname (""),
994  m_variable_focus_widget (nullptr)
995  {
996  setObjectName ("VariableEditor");
997  set_title (tr ("Variable Editor"));
998  setStatusTip (tr ("Edit variables."));
999  setWindowIcon (QIcon (":/actions/icons/logo.png"));
1000  setAttribute (Qt::WA_AlwaysShowToolTips);
1001 
1002  m_main->setParent (this);
1003 // See Octave bug #53409 and https://bugreports.qt.io/browse/QTBUG-55357
1004 #if (QT_VERSION < 0x050601) || (QT_VERSION >= 0x050701)
1005  m_main->setDockOptions (QMainWindow::AnimatedDocks |
1006  QMainWindow::AllowNestedDocks |
1007  QMainWindow::VerticalTabs);
1008 #else
1009  m_main->setDockNestingEnabled (true);
1010 #endif
1011 
1012  // Tool Bar.
1013 
1014  construct_tool_bar ();
1015  m_main->addToolBar (m_tool_bar);
1016 
1017  // Colors.
1018 
1019  for (int i = 0; i < resource_manager::varedit_color_chars ().length (); i++)
1020  m_table_colors.append (QColor (Qt::white));
1021 
1022  // Use an MDI area that is shrunk to nothing as the central widget.
1023  // Future feature might be to switch to MDI mode in which the dock
1024  // area is shrunk to nothing and the widgets live in the MDI window.
1025 
1026  QMdiArea *central_mdiarea = new QMdiArea (m_main);
1027  central_mdiarea->setMinimumSize (QSize (0, 0));
1028  central_mdiarea->setMaximumSize (QSize (0, 0));
1029  central_mdiarea->resize (QSize (0, 0));
1030  m_main->setCentralWidget (central_mdiarea);
1031 
1032  setWidget (m_main);
1033 
1034  connect (this, SIGNAL (command_signal (const QString&)),
1035  p, SLOT (execute_command_in_terminal (const QString&)));
1036  }
1037 
1038  void variable_editor::focusInEvent (QFocusEvent *ev)
1039  {
1040  octave_dock_widget::focusInEvent (ev);
1041 
1042  // set focus to the current variable or most recent if still valid
1043  QWidget *fw = m_main->focusWidget ();
1044  if (fw != nullptr)
1045  fw->setFocus ();
1046  else if (m_main->isAncestorOf (m_variable_focus_widget))
1047  m_variable_focus_widget->setFocus ();
1048  }
1049 
1050  void variable_editor::focusOutEvent (QFocusEvent *ev)
1051  {
1052  // focusWidget() appears lost in transition to/from main window
1053  m_variable_focus_widget = m_main->focusWidget ();
1054 
1055  octave_dock_widget::focusOutEvent (ev);
1056  }
1057 
1058  // Add an action to a menu or the widget itself.
1059 
1060  QAction*
1061  variable_editor::add_action (QMenu *menu, const QIcon& icon,
1062  const QString& text,
1063  const char *member)
1064  {
1065  QAction *a;
1066 
1067  if (menu)
1068  a = menu->addAction (icon, text, this, member);
1069  else
1070  {
1071  a = new QAction (this);
1072  connect (a, SIGNAL (triggered ()), this, member);
1073  }
1074 
1075  addAction (a); // important for shortcut context
1076  a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
1077 
1078  return a;
1079  }
1080 
1081  void
1083  {
1084  if (m_stylesheet.isEmpty ())
1085  {
1086  QSettings *settings = resource_manager::get_settings ();
1087  notice_settings (settings);
1088  }
1089 
1090  QDockWidget *existing_qdw = m_main->findChild<QDockWidget *> (name);
1091  if (existing_qdw != NULL)
1092  {
1093  // Already open.
1094 
1095  // Put current focused variable out of focus
1096  if (m_main->focusWidget () != nullptr)
1097  {
1098  QFocusEvent event (QEvent::FocusOut, Qt::OtherFocusReason);
1099  QApplication::sendEvent (m_main->focusWidget (), &event);
1100  }
1101 
1102  // Put existing variable in focus and raise
1103  m_main->parentWidget ()->show ();
1104  existing_qdw->show ();
1105  existing_qdw->raise ();
1106  existing_qdw->activateWindow ();
1107  tab_to_front ();
1108  existing_qdw->setFocus ();
1109 
1110  return;
1111  }
1112 
1114  page->setObjectName (name);
1115  m_main->addDockWidget (Qt::LeftDockWidgetArea, page);
1116 
1117  connect (QApplication::instance(), SIGNAL (focusChanged (QWidget *, QWidget *)),
1118  page, SLOT (handle_focus_change (QWidget *, QWidget *)));
1119  connect (page, SIGNAL (destroyed (QObject *)),
1120  this, SLOT (variable_destroyed (QObject *)));
1121  connect (page, SIGNAL (variable_focused_signal (const QString&)),
1122  this, SLOT (variable_focused (const QString&)));
1123 
1125  stack->setObjectName (name);
1126  page->setWidget (stack);
1127  page->setFocusProxy (stack);
1128 
1129  connect (stack, SIGNAL (command_signal (const QString&)),
1130  this, SIGNAL (command_signal (const QString&)));
1131  connect (stack, SIGNAL (edit_variable_signal (const QString&, const octave_value&)),
1132  this, SLOT (edit_variable (const QString&, const octave_value&)));
1133  connect (this, SIGNAL (level_up_signal ()),
1134  stack, SLOT (levelUp ()));
1135  connect (this, SIGNAL (save_signal ()),
1136  stack, SLOT (save ()));
1137 
1138  variable_editor_view *edit_view = stack->edit_view ();
1139 
1140  edit_view->setObjectName (name);
1141  edit_view->setFont (m_font);
1142  edit_view->setStyleSheet (m_stylesheet);
1143  edit_view->setAlternatingRowColors (m_alternate_rows);
1144  edit_view->verticalHeader ()->setDefaultSectionSize (m_default_height
1145  + m_add_font_height);
1146 
1147  connect (edit_view, SIGNAL (command_signal (const QString&)),
1148  this, SIGNAL (command_signal (const QString&)));
1149  connect (this, SIGNAL (delete_selected_signal ()),
1150  edit_view, SLOT (delete_selected ()));
1151  connect (this, SIGNAL (clear_content_signal ()),
1152  edit_view, SLOT (clearContent ()));
1153  connect (this, SIGNAL (copy_clipboard_signal ()),
1154  edit_view, SLOT (copyClipboard ()));
1155  connect (this, SIGNAL (paste_clipboard_signal ()),
1156  edit_view, SLOT (pasteClipboard ()));
1157  connect (this, SIGNAL (paste_table_clipboard_signal ()),
1158  edit_view, SLOT (pasteTableClipboard ()));
1159  connect (this, SIGNAL (selected_command_signal (const QString&)),
1160  edit_view, SLOT (selected_command_requested (const QString&)));
1161  connect (edit_view->horizontalHeader (),
1162  SIGNAL (customContextMenuRequested (const QPoint&)),
1163  edit_view, SLOT (createColumnMenu (const QPoint&)));
1164  connect (edit_view->verticalHeader (),
1165  SIGNAL (customContextMenuRequested (const QPoint&)),
1166  edit_view, SLOT (createRowMenu (const QPoint&)));
1167  connect (edit_view, SIGNAL (customContextMenuRequested (const QPoint&)),
1168  edit_view, SLOT (createContextMenu (const QPoint&)));
1169  connect (edit_view->horizontalScrollBar (), SIGNAL (actionTriggered (int)),
1170  edit_view, SLOT (handle_horizontal_scroll_action (int)));
1171  connect (edit_view->verticalScrollBar (), SIGNAL (actionTriggered (int)),
1172  edit_view, SLOT (handle_vertical_scroll_action (int)));
1173 
1174  variable_editor_model *model =
1175  new variable_editor_model (name, val, stack);
1176 
1177  connect (model, SIGNAL (edit_variable_signal (const QString&, const octave_value&)),
1178  this, SLOT (edit_variable (const QString&, const octave_value&)));
1179  connect (model, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
1180  this, SLOT (callUpdate (const QModelIndex&, const QModelIndex&)));
1181  connect (this, SIGNAL (refresh_signal ()),
1182  model, SLOT (update_data_cache ()));
1183  connect (model, SIGNAL (set_editable_signal (bool)),
1184  stack, SLOT (set_editable (bool)));
1185 
1186  edit_view->setModel (model);
1187  connect (edit_view, SIGNAL (doubleClicked (const QModelIndex&)),
1188  model, SLOT (double_click (const QModelIndex&)));
1189 
1190  // Must supply a title for a QLabel to be created. Calling set_title()
1191  // more than once will add more QLabels. Could change octave_dock_widget
1192  // to always supply a QLabl (initially empty) and then simply update its
1193  // contents.
1194  page->set_title (name);
1195  QLabel *existing_ql = page->titleBarWidget ()->findChild<QLabel *> ();
1196  connect (model, SIGNAL (update_label_signal (const QString&)),
1197  existing_ql, SLOT (setText (const QString&)));
1198  existing_ql->setMargin (2);
1199 
1200  model->update_data (val);
1201 
1202  QList<QTableView *> viewlist = findChildren<QTableView *> ();
1203  if (viewlist.size () == 1)
1204  m_tool_bar->setEnabled (true);
1205 
1206  m_main->parentWidget ()->show ();
1207  page->show ();
1208  page->raise ();
1209  page->activateWindow ();
1210  tab_to_front ();
1211  page->setFocus ();
1212  }
1213 
1214  void
1216  {
1217  if (parent () != nullptr)
1218  {
1219  QList<QTabBar *> barlist = main_win ()->findChildren<QTabBar *> ();
1220  QVariant this_value (reinterpret_cast<quintptr> (this));
1221 
1222  foreach (QTabBar *tbar, barlist)
1223  for (int i = 0; i < tbar->count (); i++)
1224  if (tbar->tabData (i) == this_value)
1225  {
1226  tbar->setCurrentIndex (i);
1227  return;
1228  }
1229  }
1230  }
1231 
1232  void
1234  {
1235  emit refresh_signal ();
1236  }
1237 
1240  {
1241  QList<QColor> colorlist;
1242 
1243  colorlist << qApp->palette ().color (QPalette::WindowText);
1244  colorlist << qApp->palette ().color (QPalette::Base);
1245  colorlist << qApp->palette ().color (QPalette::HighlightedText);
1246  colorlist << qApp->palette ().color (QPalette::Highlight);
1247  colorlist << qApp->palette ().color (QPalette::AlternateBase);
1248 
1249  return colorlist;
1250  }
1251 
1252  QStringList
1254  {
1255  QStringList output;
1256 
1257  output << tr("Foreground");
1258  output << tr("Background");
1259  output << tr("Selected Foreground");
1260  output << tr("Selected Background");
1261  output << tr("Alternate Background");
1262 
1263  return output;
1264  }
1265 
1266  void
1267  variable_editor::callUpdate (const QModelIndex&, const QModelIndex&)
1268  {
1269  emit updated ();
1270  }
1271 
1272  void
1273  variable_editor::notice_settings (const QSettings *settings)
1274  {
1275  // FIXME: Why use object->tostring->toint? Why not just 100?
1276 
1277  m_default_width = settings->value ("variable_editor/column_width",
1278  100).toInt ();
1279 
1280  m_default_height = settings->value ("variable_editor/row_height",
1281  10).toInt ();
1282 
1283  m_alternate_rows = settings->value ("variable_editor/alternate_rows",
1284  false).toBool ();
1285 
1287 
1288  QString class_chars = resource_manager::varedit_color_chars ();
1289 
1290  m_use_terminal_font = settings->value ("variable_editor/use_terminal_font",
1291  true).toBool ();
1292 
1293  QString font_name;
1294  int font_size;
1295 
1296  if (m_use_terminal_font)
1297  {
1298  font_name = settings->value ("terminal/fontName", "Courier New").toString ();
1299  font_size = settings->value ("terminal/fontSize", 10).toInt ();
1300  }
1301  else
1302  {
1303  font_name = settings->value ("variable_editor/font_name",
1304  settings->value ("terminal/fontName",
1305  "Courier New")).toString ();
1306 
1307  font_size = settings->value ("variable_editor/font_size", 10).toInt ();
1308  }
1309 
1310  m_font = QFont (font_name, font_size);
1311 
1312  QFontMetrics fm (m_font);
1313 
1314  m_add_font_height = fm.height ();
1315 
1316  for (int i = 0; i < class_chars.length (); i++)
1317  {
1318  QVariant default_var;
1319  if (i < default_colors.length ())
1320  default_var = default_colors.at (i);
1321  else
1322  default_var = QColor ();
1323 
1324  QColor setting_color = settings->value ("variable_editor/color_"
1325  + class_chars.mid (i, 1),
1326  default_var).value<QColor> ();
1327 
1328  if (i < m_table_colors.length ())
1329  m_table_colors.replace (i, setting_color);
1330  }
1331 
1332  update_colors ();
1333 
1334  // Icon size in the toolbar.
1335 
1336  int icon_size_settings = settings->value ("toolbar_icon_size", 0).toInt ();
1337  QStyle *st = style ();
1338  int icon_size = st->pixelMetric (QStyle::PM_ToolBarIconSize);
1339 
1340  // FIXME: Magic numbers. Use enum?
1341 
1342  if (icon_size_settings == 1)
1343  icon_size = st->pixelMetric (QStyle::PM_LargeIconSize);
1344  else if (icon_size_settings == -1)
1345  icon_size = st->pixelMetric (QStyle::PM_SmallIconSize);
1346 
1347  m_tool_bar->setIconSize (QSize (icon_size, icon_size));
1348  }
1349 
1350  void
1352  {
1353  emit finished ();
1354 
1356  }
1357 
1358  void
1360  {
1361  QList<variable_dock_widget *> vdwlist = findChildren<variable_dock_widget *> ();
1362  if (vdwlist.isEmpty ())
1363  m_tool_bar->setEnabled (false);
1364  }
1365 
1366  void
1368  {
1370  }
1371 
1372  void
1374  {
1376  }
1377 
1378  void
1380  {
1381  variable_dock_widget *tofocus = findChild<variable_dock_widget *> (m_hovered_focus_vname);
1382  if (tofocus != nullptr)
1383  {
1384  // Note that this may be platform and window system dependent.
1385  // On a particular Linux system, activateWindow() alone didn't
1386  // immediately set the active window and there was a race
1387  // between the window focus and action signal. Setting the
1388  // active window via the QApplication route did work.
1389  QApplication::setActiveWindow(tofocus->window());
1390  tofocus->activateWindow ();
1391  tofocus->setFocus (Qt::OtherFocusReason);
1392  }
1393  }
1394 
1395  void
1397  {
1398  emit save_signal ();
1399  }
1400 
1401  void
1403  {
1404  copyClipboard ();
1405 
1406  emit clear_content_signal ();
1407  }
1408 
1409  void
1411  {
1412  emit copy_clipboard_signal ();
1413  }
1414 
1415  void
1417  {
1418  emit paste_clipboard_signal ();
1419 
1420  emit updated ();
1421  }
1422 
1423  void
1425  {
1427 
1428  emit updated ();
1429  }
1430 
1431  void
1433  {
1434  emit level_up_signal ();
1435  }
1436 
1437  void
1439  {
1440  emit selected_command_signal (cmd);
1441  }
1442 
1443  // Also updates the font.
1444 
1446  {
1447  m_stylesheet = "";
1448 
1449  if (m_table_colors.length () > 0)
1450  m_stylesheet += "QTableView::item{ foreground-color: "
1451  + m_table_colors[0].name () +" }";
1452 
1453  if (m_table_colors.length () > 1)
1454  m_stylesheet += "QTableView::item{ background-color: "
1455  + m_table_colors[1].name () +" }";
1456 
1457  if (m_table_colors.length () > 2)
1458  m_stylesheet += "QTableView::item{ selection-color: "
1459  + m_table_colors[2].name () +" }";
1460 
1461  if (m_table_colors.length () > 3)
1462  m_stylesheet += "QTableView::item:selected{ background-color: "
1463  + m_table_colors[3].name () +" }";
1464 
1465  if (m_table_colors.length () > 4 && m_alternate_rows)
1466  {
1467  m_stylesheet
1468  += "QTableView::item:alternate{ background-color: "
1469  + m_table_colors[4].name () +" }";
1470 
1471  m_stylesheet
1472  += "QTableView::item:alternate:selected{ background-color: "
1473  + m_table_colors[3].name () +" }";
1474  }
1475 
1476  QList<QTableView *> viewlist = findChildren<QTableView *> ();
1477  for (int i = 0; i < viewlist.size (); i++)
1478  {
1479  QTableView *view = viewlist.at (i);
1480 
1481  if (! view)
1482  continue;
1483 
1484  view->setAlternatingRowColors (m_alternate_rows);
1485  view->setStyleSheet (m_stylesheet);
1486  view->setFont (m_font);
1487  }
1488 
1489  }
1490 
1491  QAction *
1493  const QString &text,
1494  const QObject *receiver,
1495  const char *member)
1496  {
1497  QAction *action = new QAction (icon, text, this);
1498  connect(action, SIGNAL (triggered ()), receiver, member);
1500  button->setDefaultAction (action);
1501  button->setText (text);
1502  button->setToolTip (text);
1503  button->setIcon (icon);
1504  m_tool_bar->addWidget (button);
1505 
1506  return action;
1507  }
1508 
1509  void
1511  {
1512  m_tool_bar->setAllowedAreas (Qt::TopToolBarArea);
1513 
1514  m_tool_bar->setObjectName ("VariableEditorToolBar");
1515 
1516  m_tool_bar->setWindowTitle (tr ("Variable Editor Toolbar"));
1517 
1518  QAction *action;
1519  action = add_tool_bar_button (resource_manager::icon ("document-save"),
1520  tr ("Save"), this, SLOT (save ()));
1521  action->setShortcuts (QKeySequence::Save);
1522  action->setStatusTip(tr("Save variable to a file"));
1523 
1524  m_tool_bar->addSeparator ();
1525 
1526  action = add_tool_bar_button (resource_manager::icon ("edit-cut"),
1527  tr ("Cut"), this, SLOT (cutClipboard ()));
1528  action->setStatusTip(tr("Cut data to clipboard"));
1529 
1530  action = add_tool_bar_button (resource_manager::icon ("edit-copy"),
1531  tr ("Copy"), this, SLOT (copyClipboard ()));
1532  action->setStatusTip(tr("Copy data to clipboard"));
1533 
1534  action = add_tool_bar_button (resource_manager::icon ("edit-paste"),
1535  tr ("Paste"), this, SLOT (pasteClipboard ()));
1536  action->setStatusTip(tr("Paste clipboard into variable data"));
1537 
1538  // FIXME: Different icon for Paste Table?
1539 
1540  action = add_tool_bar_button (resource_manager::icon ("edit-paste"),
1541  tr ("Paste Table"),
1542  this, SLOT (pasteTableClipboard ()));
1543  action->setStatusTip(tr("Another paste clipboard into variable data"));
1544 
1545  m_tool_bar->addSeparator ();
1546 
1547  // FIXME: Add a print item?
1548  // QAction *print_action; /icons/fileprint.png
1549  // m_tool_bar->addSeparator ();
1550 
1551  action = new QAction (resource_manager::icon ("plot-xy-curve"),
1552  tr ("Plot"), m_tool_bar);
1553  action->setToolTip (tr ("Plot Selected Data"));
1554  QToolButton *plot_tool_button = new HoverToolButton (m_tool_bar);
1555  plot_tool_button->setDefaultAction (action);
1556 
1557  plot_tool_button->setText (tr ("Plot"));
1558  plot_tool_button->setToolTip (tr ("Plot selected data"));
1559  plot_tool_button->setIcon (resource_manager::icon ("plot-xy-curve"));
1560 
1561  plot_tool_button->setPopupMode (QToolButton::InstantPopup);
1562 
1563  QMenu *plot_menu = new ReturnFocusMenu (plot_tool_button);
1564  plot_menu->setTitle (tr ("Plot"));
1565  plot_menu->setSeparatorsCollapsible (false);
1566 
1567  QSignalMapper *plot_mapper = make_plot_mapper (plot_menu);
1568 
1569  connect (plot_mapper, SIGNAL (mapped (const QString&)),
1570  this, SLOT (relay_selected_command (const QString&)));
1571 
1572  plot_tool_button->setMenu (plot_menu);
1573 
1574  m_tool_bar->addWidget (plot_tool_button);
1575 
1576  m_tool_bar->addSeparator ();
1577 
1578  action = add_tool_bar_button (resource_manager::icon ("go-up"),
1579  tr ("Up"), this, SLOT (levelUp ()));
1580  action->setStatusTip(tr("Go one level up in variable hierarchy"));
1581 
1582  // The QToolButton mouse-clicks change active window, so connect all
1583  // HoverToolButton and RuternFocusToolButton objects to the mechanism
1584  // that restores active window and focus before acting.
1585  QList<HoverToolButton *> hbuttonlist
1586  = m_tool_bar->findChildren<HoverToolButton *> (""
1587 #if defined (QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS)
1588  , Qt::FindDirectChildrenOnly
1589 #endif
1590  );
1591  for (int i = 0; i < hbuttonlist.size (); i++)
1592  {
1593  connect (hbuttonlist.at (i), SIGNAL (hovered_signal ()),
1594  this, SLOT (record_hovered_focus_variable ()));
1595  connect (hbuttonlist.at (i), SIGNAL (popup_shown_signal ()),
1596  this, SLOT (restore_hovered_focus_variable ()));
1597  }
1598 
1599  QList<ReturnFocusToolButton *> rfbuttonlist
1600  = m_tool_bar->findChildren<ReturnFocusToolButton *> (""
1601 #if defined (QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS)
1602  , Qt::FindDirectChildrenOnly
1603 #endif
1604  );
1605  for (int i = 0; i < rfbuttonlist.size (); i++)
1606  {
1607  connect (rfbuttonlist.at (i), SIGNAL (about_to_activate ()),
1608  this, SLOT (restore_hovered_focus_variable ()));
1609  }
1610 
1611  // Same for QMenu
1612  QList<ReturnFocusMenu *> menulist
1613  = m_tool_bar->findChildren<ReturnFocusMenu *> ();
1614  for (int i = 0; i < menulist.size (); i++)
1615  {
1616  connect (menulist.at (i), SIGNAL (about_to_activate ()),
1617  this, SLOT (restore_hovered_focus_variable ()));
1618  }
1619 
1620  m_tool_bar->setAttribute(Qt::WA_ShowWithoutActivating);
1621  m_tool_bar->setFocusPolicy (Qt::NoFocus);
1622 
1623  // Disabled when no tab is present.
1624 
1625  m_tool_bar->setEnabled (false);
1626  }
1627 }
void command_signal(const QString &cmd)
void focusOutEvent(QFocusEvent *ev)
static QStringList color_names(void)
void add_edit_actions(QMenu *menu, const QString &qualifier_string)
ReturnFocusMenu(QWidget *parent=nullptr)
OCTAVE_EXPORT octave_value_list column
Definition: sparse.cc:123
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:124
void closeEvent(QCloseEvent *)
The value of lines which begin with a space character are not saved in the history list A value of all commands are saved on the history list
Definition: oct-hist.cc:734
void resizeEvent(QResizeEvent *event)
void selected_command_requested(const QString &cmd)
void focusInEvent(QFocusEvent *ev)
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:4986
bool clear_content(const QModelIndex &idx)
variable_dock_widget(QWidget *p=nullptr)
octave::sys::time now
Definition: data.cc:6251
void callUpdate(const QModelIndex &, const QModelIndex &)
void set_editable(bool editable)
octave_int< T > mod(const octave_int< T > &x, const octave_int< T > &y)
Definition: oct-inttypes.h:860
OCTAVE_EXPORT octave_value_list page
Definition: sub2ind.cc:107
bool eventFilter(QObject *obj, QEvent *ev)
variable_editor_model * m_var_model
void record_hovered_focus_variable(void)
void createContextMenu(const QPoint &pt)
virtual void closeEvent(QCloseEvent *e)
void edit_variable_signal(const QString &name, const octave_value &val)
i e
Definition: data.cc:2591
void paste_clipboard_signal(void)
octave_value arg
Definition: pr-output.cc:3244
QTextEdit * make_disp_view(QWidget *parent)
void createRowMenu(const QPoint &pt)
variable_editor(QWidget *parent=nullptr)
static QList< QColor > varedit_default_colors(void)
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:400
void restore_hovered_focus_variable(void)
void about_to_activate(void)
ReturnFocusToolButton(QWidget *parent=nullptr)
void variable_destroyed(QObject *obj)
QAction * add_tool_bar_button(const QIcon &icon, const QString &text, const QObject *receiver, const char *member)
nd deftypefn *std::string name
Definition: sysdep.cc:647
static QSignalMapper * make_plot_mapper(QMenu *menu)
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit first
Definition: file-io.cc:587
void variable_focused(const QString &name)
text(const graphics_handle &mh, const graphics_handle &p)
Definition: graphics.in.h:4541
std::complex< double > w(std::complex< double > z, double relerr=0)
void popup_shown_signal(void)
static QList< QColor > default_colors(void)
is false
Definition: cellfun.cc:400
QMainWindow * main_win(void)
void variable_focused_signal(const QString &name)
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
variable_editor_view * edit_view(void)
bool eventFilter(QObject *obj, QEvent *ev)
HoverToolButton(QWidget *parent=nullptr)
void set_title(const QString &)
void edit_variable(const QString &name, const octave_value &val)
QList< QColor > m_table_colors
void delete_selected_signal(void)
virtual void closeEvent(QCloseEvent *e)
static QString idx_to_expr(int32_t from, int32_t to)
static QIcon icon(const QString &icon_name, bool fallback=true)
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:227
void handle_horizontal_scroll_action(int action)
static QString varedit_color_chars(void)
octave::sys::time start
Definition: graphics.cc:12337
void notice_settings(const QSettings *)
void setModel(QAbstractItemModel *model)
p
Definition: lu.cc:138
octave_map map(dims)
QList< int > range_selected(void)
void handle_focus_change(QWidget *old, QWidget *now)
static QSettings * get_settings(void)
void createColumnMenu(const QPoint &pt)
bool eventFilter(QObject *obj, QEvent *ev)
variable_editor_view(QWidget *p=nullptr)
for i
Definition: data.cc:5264
void copy_clipboard_signal(void)
void relay_selected_command(const QString &cmd)
variable_editor_view * m_edit_view
OCTAVE_EXPORT octave_value_list or cell arrays Arguments are concatenated vertically The returned values are padded with blanks as needed to make each row of the string array have the same length Empty input strings are significant and will concatenated in the output For numerical each element is converted to the corresponding ASCII character A range error results if an input is outside the ASCII range(0-255). For cell arrays
void paste_table_clipboard_signal(void)
variable_editor_stack(QWidget *p=nullptr)
void handle_vertical_scroll_action(int action)
void command_signal(const QString &cmd)
void command_signal(const QString &cmd)
where the brackets indicate optional arguments and and character or cell array For character arrays the conversion is repeated for every row
Definition: str2double.cc:342
QAction * add_action(QMenu *menu, const QIcon &icon, const QString &text, const char *member)
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:204
void clear_content_signal(void)
void selected_command_signal(const QString &cmd)