GNU Octave 7.1.0
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-2022 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26#ifdef HAVE_CONFIG_H
27# include "config.h"
28#endif
29
30#include <algorithm>
31#include <limits>
32
33#include <QApplication>
34#include <QClipboard>
35#include <QFileDialog>
36#include <QHeaderView>
37#include <QLabel>
38#include <QMdiArea>
39#include <QMenu>
40#include <QPalette>
41#include <QScreen>
42#include <QScrollBar>
43#include <QStackedWidget>
44#include <QTabWidget>
45#include <QTableView>
46#include <QTextEdit>
47#include <QToolBar>
48#include <QToolButton>
49#include <QVBoxLayout>
50
51#include "builtin-defun-decls.h"
52#include "dw-main-window.h"
53#include "gui-preferences-cs.h"
55#include "gui-preferences-sc.h"
56#include "gui-preferences-ve.h"
57#include "octave-qobject.h"
58#include "octave-qtutils.h"
59#include "ovl.h"
60#include "qt-utils.h"
61#include "shortcut-manager.h"
63#include "variable-editor.h"
64
65namespace octave
66{
67 // Code reuse functions
68
69 static QSignalMapper *
71 {
72 QList<QString> list;
73 list << "plot" << "bar" << "stem" << "stairs" << "area" << "pie" << "hist";
74
75 QSignalMapper *plot_mapper = new QSignalMapper (menu);
76
77 for (int i = 0; i < list.size(); ++i)
78 plot_mapper->setMapping
79 (menu->addAction (list.at (i), plot_mapper, SLOT (map ())), list.at (i));
80
81 return plot_mapper;
82 }
83
84 // Variable dock widget
85
87 base_qobject& oct_qobj)
88 : label_dock_widget (p, oct_qobj)
89// See Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
90#if (QT_VERSION >= 0x050302) && (QT_VERSION <= QTBUG_44813_FIX_VERSION)
91 , m_waiting_for_mouse_move (false)
92 , m_waiting_for_mouse_button_release (false)
93#endif
94 {
95 setFocusPolicy (Qt::StrongFocus);
96 setAttribute (Qt::WA_DeleteOnClose);
97
98 connect (m_dock_action, &QAction::triggered,
100 connect (m_close_action, &QAction::triggered,
102 connect (this, &variable_dock_widget::topLevelChanged,
104
105#define DOCKED_FULLSCREEN_BUTTON_TOOLTIP "Fullscreen undock"
106#define UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP "Fullscreen"
107 // Add a fullscreen button
108
109 m_fullscreen_action = nullptr;
110 m_full_screen = false;
111 m_prev_floating = false;
112 m_prev_geom = QRect (0, 0, 0, 0);
113
114 QHBoxLayout *h_layout = m_title_widget->findChild<QHBoxLayout *> ();
117 = new QAction (rmgr.icon ("view-fullscreen", false), "", this);
119 QToolButton *fullscreen_button = new QToolButton (m_title_widget);
120 fullscreen_button->setDefaultAction (m_fullscreen_action);
121 fullscreen_button->setFocusPolicy (Qt::NoFocus);
122 fullscreen_button->setIconSize (QSize (m_icon_size, m_icon_size));
123 QString css_button = QString ("QToolButton {background: transparent; border: 0px;}");
124 fullscreen_button->setStyleSheet (css_button);
125
126 connect (m_fullscreen_action, &QAction::triggered,
128
129 int index = -1;
130 QToolButton *first = m_title_widget->findChild<QToolButton *> ();
131 if (first != nullptr)
132 index = h_layout->indexOf (first);
133 h_layout->insertWidget (index, fullscreen_button);
134
135 // Custom title bars cause loss of decorations, add a frame
136 m_frame = new QFrame (this);
137 m_frame->setFrameStyle (QFrame::Box | QFrame::Sunken);
138 m_frame->setAttribute (Qt::WA_TransparentForMouseEvents);
139 }
140
141 // slot for (un)dock action
142 void
144 {
145 if (isFloating ())
146 {
147 if (m_full_screen)
148 {
149 setGeometry (m_prev_geom);
151 m_fullscreen_action->setIcon (rmgr.icon ("view-fullscreen", false));
152 m_full_screen = false;
153 }
155 }
156 else
158
159 setFloating (! isFloating ());
160 }
161
162 // slot for hiding the widget
163 void
165 {
166 close ();
167 }
168
169 void
171 {
172 if (toplevel)
173 {
174 m_dock_action->setIcon (QIcon (":/actions/icons/widget-dock.png"));
175 m_dock_action->setToolTip (tr ("Dock widget"));
176
177 setWindowFlags (Qt::Window);
178 setWindowTitle (tr ("Variable Editor: ") + objectName ());
179
180 show ();
181 activateWindow ();
182 setFocus ();
183
184// See Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
185#if (QT_VERSION >= 0x050302) && (QT_VERSION <= QTBUG_44813_FIX_VERSION)
186 m_waiting_for_mouse_move = true;
187#endif
188 }
189 else
190 {
191 m_dock_action->setIcon (QIcon (":/actions/icons/widget-undock.png"));
192 m_dock_action->setToolTip (tr ("Undock widget"));
193
194 setFocus ();
195
196// See Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
197#if (QT_VERSION >= 0x050302) && (QT_VERSION <= QTBUG_44813_FIX_VERSION)
198 m_waiting_for_mouse_move = false;
199 m_waiting_for_mouse_button_release = false;
200#endif
201 }
202 }
203
204 void
206 {
208
209 if (! m_full_screen)
210 {
211 m_prev_floating = isFloating ();
212 m_fullscreen_action->setIcon (rmgr.icon ("view-restore", false));
213 if (m_prev_floating)
214 m_fullscreen_action->setToolTip (tr ("Restore geometry"));
215 else
216 {
217 m_fullscreen_action->setToolTip (tr ("Redock"));
218 setFloating (true);
219 }
220 m_prev_geom = geometry ();
221
222 // showFullscreen() and setWindowState() only work for QWindow objects.
223 QScreen *pscreen = QGuiApplication::primaryScreen ();
224 QRect rect (0, 0, 0, 0);
225 rect = pscreen->availableGeometry ();
226 setGeometry (rect);
227
228 m_full_screen = true;
229 }
230 else
231 {
232 m_fullscreen_action->setIcon (rmgr.icon ("view-fullscreen", false));
233 setGeometry (m_prev_geom);
234 if (m_prev_floating)
236 else
237 {
238 setFloating (false);
240 }
241
242 m_full_screen = false;
243 }
244#undef DOCKED_FULLSCREEN_BUTTON_TOOLTIP
245#undef UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP
246 }
247
248 void
250 {
251 QDockWidget::closeEvent (e);
252 }
253
254 void
256 {
257 octave_unused_parameter (now);
258
259 // This is a proxied test
260 if (hasFocus ())
261 {
262 if (old == this)
263 return;
264
265 if (titleBarWidget () != nullptr)
266 {
267 QLabel *label = titleBarWidget ()->findChild<QLabel *> ();
268 if (label != nullptr)
269 {
270 label->setBackgroundRole (QPalette::Highlight);
271 label->setStyleSheet ("background-color: palette(highlight); color: palette(highlightedText);");
272 }
273 }
274
275 emit variable_focused_signal (objectName ());
276 }
277 else if (old == focusWidget())
278 {
279 if (titleBarWidget () != nullptr)
280 {
281 QLabel *label = titleBarWidget ()->findChild<QLabel *> ();
282 if (label != nullptr)
283 {
284 label->setBackgroundRole (QPalette::NoRole);
285 label->setStyleSheet (";");
286 }
287 }
288 }
289 }
290
292 {
293 if (m_frame)
294 m_frame->resize (size ());
295 }
296
297// See Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
298#if (QT_VERSION >= 0x050302) && (QT_VERSION <= QTBUG_44813_FIX_VERSION)
299
300 bool
301 variable_dock_widget::event (QEvent *event)
302 {
303 // low-level check of whether docked-widget became a window via
304 // via drag-and-drop
305 if (event->type () == QEvent::MouseButtonPress)
306 {
307 m_waiting_for_mouse_move = false;
308 m_waiting_for_mouse_button_release = false;
309 }
310 if (event->type () == QEvent::MouseMove && m_waiting_for_mouse_move)
311 {
312 m_waiting_for_mouse_move = false;
313 m_waiting_for_mouse_button_release = true;
314 }
315 if (event->type () == QEvent::MouseButtonRelease
316 && m_waiting_for_mouse_button_release)
317 {
318 m_waiting_for_mouse_button_release = false;
319 bool retval = QDockWidget::event (event);
320 if (isFloating ())
321 emit queue_unfloat_float ();
322 return retval;
323 }
324
325 return QDockWidget::event (event);
326 }
327
328 void
330 {
331 hide ();
332 setFloating (false);
333 // Avoid a Ubunty Unity issue by queuing this rather than direct.
334 emit queue_float ();
335 m_waiting_for_mouse_move = false;
336 m_waiting_for_mouse_button_release = false;
337 }
338
339 void
341 {
342 setFloating (true);
343 m_waiting_for_mouse_move = false;
344 m_waiting_for_mouse_button_release = false;
345 show ();
346 activateWindow ();
347 setFocus ();
348 }
349
350#else
351
352 void
354 { }
355
356 void
358 { }
359
360#endif
361
362 // Variable editor stack
363
365 base_qobject& oct_qobj)
366 : QStackedWidget (p), m_octave_qobj (oct_qobj),
367 m_edit_view (new variable_editor_view (this, m_octave_qobj))
368 {
369 setFocusPolicy (Qt::StrongFocus);
370
372
373 addWidget (m_edit_view);
374 addWidget (m_disp_view);
375 }
376
377 QTextEdit *
379 {
380 QTextEdit *viewer = new QTextEdit (parent);
381
382 viewer->setLineWrapMode (QTextEdit::NoWrap);
383 viewer->setReadOnly (true);
384
385 return viewer;
386 }
387
388 void
390 {
391 // The QTableView is for editable data models
392 // and the QTextEdit is for non-editable models.
393
394 if (editable)
395 {
396 if (m_edit_view != nullptr)
397 {
398 setCurrentWidget (m_edit_view);
399 setFocusProxy (m_edit_view);
400 m_edit_view->setFocusPolicy (Qt::StrongFocus);
401 }
402
403 if (m_disp_view != nullptr)
404 m_disp_view->setFocusPolicy (Qt::NoFocus);
405 }
406 else
407 {
408 if (m_disp_view != nullptr)
409 {
410 setCurrentWidget (m_disp_view);
411 setFocusProxy (m_disp_view);
412
413 QAbstractTableModel *model = findChild<QAbstractTableModel *> ();
414 if (model != nullptr)
415 m_disp_view->setPlainText (model->data (QModelIndex ()).toString ());
416 else
417 m_disp_view->setPlainText ("");
418 }
419
420 if (m_edit_view != nullptr)
421 m_edit_view->setFocusPolicy (Qt::NoFocus);
422 }
423 }
424
425 void
427 {
428 if (! hasFocus ())
429 return;
430
431 QString name = objectName ();
432
433 // FIXME: Is there a better way?
434
435 if (name.endsWith (')') || name.endsWith ('}'))
436 {
437 name.remove ( QRegExp ("[({][^({]*[)}]$)") );
439 }
440 }
441
442 // Slot for saving a variable into a file
443 void
445 {
446 if (! hasFocus ())
447 return;
448
449 // Check whether a format for saving the variable is given
450 QString format_string;
451 if (! format.isEmpty ())
452 {
453 format_string = "-" + format;
455 return;
456 }
457
458 // No format given, test save default options
460 ([=] (interpreter& interp)
461 {
462 // INTERPRETER THREAD
463
464 octave_value_list argout
466 QString save_opts = QString::fromStdString (argout(0).string_value ());
467
470
471 emit (do_save_signal (format_string, save_opts));
472
473 });
474 }
475
476
477 // Perform saving the variable after desired format is determined
478 void
479 variable_editor_stack::do_save (const QString& format, const QString& save_opts)
480 {
481 QString file_ext = "txt";
482 for (int i = 0; i < ve_save_formats_ext.length ()/2; i++)
483 {
484 if (save_opts.contains (ve_save_formats_ext.at (2*i), Qt::CaseInsensitive))
485 {
486 file_ext = ve_save_formats_ext.at (2*i + 1);
487 break;
488 }
489 }
490
491 // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
492 int opts = 0; // No options by default.
495 if (! settings->value (global_use_native_dialogs).toBool ())
496 opts = QFileDialog::DontUseNativeDialog;
497
498 QString name = objectName ();
499 QString file
500 = QFileDialog::getSaveFileName (this,
501 tr ("Save Variable %1 As").arg (name),
502 QString ("./%1.%2").arg (name).arg (file_ext),
503 0, 0, QFileDialog::Option (opts));
504
505 if (file.isEmpty ())
506 return; // No file selected: Just return
507
508 // Let the interpreter thread do the saving
510 ([=] (interpreter& interp)
511 {
512 // INTERPRETER THREAD
513
515 std::list<octave_value> str_list
516 = {octave_value (file.toStdString ()),
517 octave_value (name.toStdString ())};
518 if (! format.isEmpty ())
519 str_list.push_front (octave_value (format.toStdString ()));
520
521 Fsave (interp, octave_value_list (str_list));
522 });
523 }
524
525
526 // Custom editable variable table view
527
529 base_qobject& oct_qobj)
530 : QTableView (p), m_octave_qobj (oct_qobj), m_var_model (nullptr)
531 {
532 setWordWrap (false);
533 setContextMenuPolicy (Qt::CustomContextMenu);
534 setSelectionMode (QAbstractItemView::ContiguousSelection);
535
536 horizontalHeader ()->setContextMenuPolicy (Qt::CustomContextMenu);
537 verticalHeader ()->setContextMenuPolicy (Qt::CustomContextMenu);
538
539 setHorizontalScrollMode (QAbstractItemView::ScrollPerPixel);
540 setVerticalScrollMode (QAbstractItemView::ScrollPerPixel);
541
542 verticalHeader ()->setSectionResizeMode (QHeaderView::Interactive);
543 }
544
545 void
546 variable_editor_view::setModel (QAbstractItemModel *model)
547 {
548 QTableView::setModel (model);
549
550 horizontalHeader ()->setSectionResizeMode (QHeaderView::Interactive);
551
552 m_var_model = parent ()->findChild<variable_editor_model *> ();
553
554 if (m_var_model != nullptr && m_var_model->column_width () > 0)
555 {
556 // col_width is in characters. The font should be a fixed-width
557 // font, so any character will do. If not, you lose!
558
559 QFontMetrics fm (font ());
560 int w = (m_var_model->column_width ()
562 horizontalHeader ()->setDefaultSectionSize (w);
563 }
564 }
565
568 {
569 QItemSelectionModel *sel = selectionModel ();
570
571 // Return early if nothing selected.
572 if (! sel->hasSelection ())
573 return QList<int> ();
574
575 QList<QModelIndex> indices = sel->selectedIndexes ();
576
577 // FIXME: Shouldn't this be keyed to octave_idx_type?
578
579 int32_t from_row = std::numeric_limits<int32_t>::max ();
580 int32_t to_row = 0;
581 int32_t from_col = std::numeric_limits<int32_t>::max ();
582 int32_t to_col = 0;
583
584 for (const auto& idx : indices)
585 {
586 from_row = std::min (from_row, idx.row ());
587 to_row = std::max (to_row, idx.row ());
588 from_col = std::min (from_col, idx.column ());
589 to_col = std::max (to_col, idx.column ());
590 }
591
592 QVector<int> vect;
593 vect << from_row + 1 << to_row + 1 << from_col + 1 << to_col + 1;
595
596 return range;
597 }
598
599 void
601 {
602 if (! hasFocus ())
603 return;
604
606 if (range.isEmpty ())
607 {
608 // Nothing selected, apply print command to all data
609 range << 1 << m_var_model->data_rows ()
610 << 1 << m_var_model->data_columns ();
611 }
612
613 int s1 = m_var_model->data_rows ();
614 int s2 = m_var_model->data_columns ();
615 if (s1 < range.at (0) || s2 < range.at (2))
616 return; // Selected range does not contain data
617
618 s1 = std::min (s1, range.at (1));
619 s2 = std::min (s2, range.at (3));
620
621 // Variable with desired range as string
622 QString variable = QString ("%1(%2:%3,%4:%5)")
623 .arg (objectName ())
624 .arg (range.at (0)).arg (s1)
625 .arg (range.at (2)).arg (s2);
626
627 // Desired command as string
628 QString command;
629 if (cmd == "create")
630 command = QString ("unnamed = %1;").arg (variable);
631 else
632 command = QString ("figure (); %1 (%2); title ('%2');")
633 .arg (cmd).arg (variable);
634
635 emit command_signal (command);
636 }
637
638 void
640 const QString& qualifier_string)
641 {
643
644 menu->addAction (rmgr.icon ("edit-cut"),
645 tr ("Cut") + qualifier_string,
647
648 menu->addAction (rmgr.icon ("edit-copy"),
649 tr ("Copy") + qualifier_string,
651
652 menu->addAction (rmgr.icon ("edit-paste"),
653 tr ("Paste"),
655
656 menu->addSeparator ();
657
658 menu->addAction (rmgr.icon ("edit-delete"),
659 tr ("Clear") + qualifier_string,
661
662 menu->addAction (rmgr.icon ("edit-delete"),
663 tr ("Delete") + qualifier_string,
665
666 menu->addAction (rmgr.icon ("document-new"),
667 tr ("Variable from Selection"),
669 }
670
671 void
673 {
674 QModelIndex index = indexAt (qpos);
675
676 if (index.isValid ())
677 {
678 QMenu *menu = new QMenu (this);
679
680 add_edit_actions (menu, tr (""));
681
682 // FIXME: addAction for sort?
683 // FIXME: Add icon for transpose.
684
685 menu->addAction (tr ("Transpose"),
687
688 QItemSelectionModel *sel = selectionModel ();
689
690 QList<QModelIndex> indices = sel->selectedIndexes ();
691
692 if (! indices.isEmpty ())
693 {
694 menu->addSeparator ();
695
696 QSignalMapper *plot_mapper = make_plot_mapper (menu);
697
698 connect (plot_mapper, SIGNAL (mapped (const QString&)),
699 this, SLOT (selected_command_requested (const QString&)));
700 }
701
702 menu->exec (mapToGlobal (qpos));
703 }
704 }
705
706 void
708 {
709 int index = horizontalHeader ()->logicalIndexAt (pt);
710
711 if (index < 0 || index > model ()->columnCount ())
712 return;
713
714 QList<int> coords = range_selected ();
715
716 bool nothingSelected = coords.isEmpty ();
717
718 bool whole_columns_selected
719 = (nothingSelected
720 ? false
721 : (coords[0] == 1 && coords[1] == model ()->rowCount ()));
722
723 bool current_column_selected
724 = nothingSelected ? false : (coords[2] <= index+1 && coords[3] > index);
725
726 int column_selection_count
727 = nothingSelected ? 0 : (coords[3] - coords[2] + 1);
728
729 if (! whole_columns_selected || ! current_column_selected)
730 {
731 selectColumn (index);
732 column_selection_count = 1;
733 }
734
735 QString column_string
736 = column_selection_count > 1 ? tr (" columns") : tr (" column");
737
738 QMenu *menu = new QMenu (this);
739
740 add_edit_actions (menu, column_string);
741
742 menu->addSeparator ();
743
744 QSignalMapper *plot_mapper = make_plot_mapper (menu);
745
746 connect (plot_mapper, SIGNAL (mapped (const QString&)),
747 this, SLOT (selected_command_requested (const QString&)));
748
749 QPoint menupos = pt;
750 menupos.setY (horizontalHeader ()->height ());
751
752 menu->exec (mapToGlobal (menupos));
753 }
754
755 void
757 {
758 int index = verticalHeader ()->logicalIndexAt (pt);
759
760 if (index < 0 || index > model ()->columnCount ())
761 return;
762
763 QList<int> coords = range_selected ();
764
765 bool nothingSelected = coords.isEmpty ();
766
767 bool whole_rows_selected
768 = (nothingSelected
769 ? false
770 : (coords[2] == 1 && coords[3] == model ()->columnCount ()));
771
772 bool current_row_selected
773 = (nothingSelected ? false : (coords[0] <= index+1 && coords[1] > index));
774
775 int rowselection_count = nothingSelected ? 0 : (coords[3] - coords[2] + 1);
776
777 if (! whole_rows_selected || ! current_row_selected)
778 {
779 selectRow (index);
780 rowselection_count = 1;
781 }
782
783 QString row_string = rowselection_count > 1 ? tr (" rows") : tr (" row");
784
785 QMenu *menu = new QMenu (this);
786
787 add_edit_actions (menu, row_string);
788
789 menu->addSeparator ();
790
791 QSignalMapper *plot_mapper = make_plot_mapper (menu);
792
793 connect (plot_mapper, SIGNAL (mapped (const QString&)),
794 this, SLOT (selected_command_requested (const QString&)));
795
796 QPoint menupos = pt;
797 menupos.setX (verticalHeader ()->width ());
798
799 // FIXME: What was the intent here?
800 // setY (verticalHeader ()->sectionPosition (index+1) +
801 // verticalHeader ()->sectionSize (index));
802
803 menu->exec (mapToGlobal (menupos));
804 }
805
806 void
808 {
809 // FIXME: Create unnamed1..n if exist ('unnamed', 'var') is true.
810
812 }
813
814 void
816 {
817 if (! hasFocus ())
818 return;
819
820 emit command_signal (QString ("%1 = %1';").arg (objectName ()));
821 }
822
823 void
825 {
826 if (! hasFocus ())
827 return;
828
829 QAbstractItemModel *mod = model ();
830 QList<int> coords = range_selected ();
831
832 if (coords.isEmpty ())
833 return;
834
835 bool whole_columns_selected
836 = coords[0] == 1 && coords[1] == mod->rowCount ();
837
838 bool whole_rows_selected
839 = coords[2] == 1 && coords[3] == mod->columnCount ();
840
841 // Must be deleting whole columns or whole rows, and not the whole thing.
842
843 if (whole_columns_selected == whole_rows_selected)
844 return;
845
846 if (whole_rows_selected)
847 mod->removeRows (coords[0], coords[1] - coords[0]);
848
849 if (whole_columns_selected)
850 mod->removeColumns (coords[2], coords[3] - coords[2]);
851 }
852
853 void
855 {
856 if (! hasFocus ())
857 return;
858
859 if (m_var_model == nullptr)
860 return;
861
862 QItemSelectionModel *sel = selectionModel ();
863 QList<QModelIndex> indices = sel->selectedIndexes ();
864
865 // FIXME: Use [] for empty cells?
866
867 for (const auto& idx : indices)
869 }
870
871 void
873 {
874 copyClipboard ();
875
876 clearContent ();
877 }
878
879 void
881 {
882 if (! hasFocus ())
883 return;
884
885 QItemSelectionModel *sel = selectionModel ();
886 QList<QModelIndex> indices = sel->selectedIndexes ();
887 std::sort (indices.begin (), indices.end ());
888
889 if (indices.isEmpty ())
890 return;
891
892 // Convert selected items into TSV format and copy that.
893 // Spreadsheet tools should understand that.
894
895 QAbstractItemModel *mod = model ();
896 QModelIndex previous = indices.first ();
897 QString copy = mod->data (previous).toString ();
898 indices.removeFirst ();
899 for (auto idx : indices)
900 {
901 copy.push_back (previous.row () != idx.row () ? '\n' : '\t');
902 copy.append (mod->data (idx).toString ());
903 previous = idx;
904 }
905
906 QClipboard *clipboard = QApplication::clipboard ();
907 clipboard->setText (copy);
908 }
909
910 void
912 {
913 if (! hasFocus ())
914 return;
915
916 QAbstractItemModel *mod = model ();
917 QItemSelectionModel *sel = selectionModel ();
918 QList<QModelIndex> indices = sel->selectedIndexes ();
919
920 QClipboard *clipboard = QApplication::clipboard ();
921 QString text = clipboard->text ();
922
923 QPoint start, end;
924
925 QPoint tabsize = QPoint (mod->rowCount (), mod->columnCount ());
926
927 if (indices.isEmpty ())
928 {
929 start = QPoint (0, 0);
930 end = tabsize;
931 }
932 else if (indices.size () == 1)
933 {
934 start = QPoint (indices[0].row (), indices[0].column ());
935 end = tabsize;
936 }
937 else
938 {
939 end = QPoint (0, 0);
940 start = tabsize;
941
942 for (int i = 0; i < indices.size (); i++)
943 {
944 if (indices[i].column () < start.y ())
945 start.setY (indices[i].column ());
946
947 if (indices[i].column () > end.y ())
948 end.setY (indices[i].column ());
949
950 if (indices[i].row () < start.x ())
951 start.setX (indices[i].column ());
952
953 if (indices[i].row () > end.x ())
954 end.setX (indices[i].column ());
955 }
956 }
957
958 int rownum = 0;
959 int colnum = 0;
960
961 QStringList rows = text.split ('\n');
962 for (const auto& row : rows)
963 {
964 if (rownum > end.x () - start.x ())
965 continue;
966
967 QStringList cols = row.split ('\t');
968 if (cols.isEmpty ())
969 continue;
970
971 for (const auto& col : cols)
972 {
973 if (col.isEmpty ())
974 continue;
975 if (colnum > end.y () - start.y () )
976 continue;
977
978 mod->setData (mod->index (rownum + start.x (),
979 colnum + start.y ()),
980 QVariant (col));
981
982 colnum++;
983 }
984
985 colnum = 0;
986 rownum++;
987 }
988 }
989
990 void
992 {
993 if (action == QAbstractSlider::SliderSingleStepAdd
994 || action == QAbstractSlider::SliderPageStepAdd
995 || action == QAbstractSlider::SliderToMaximum
996 || action == QAbstractSlider::SliderMove)
997 {
998 if (m_var_model != nullptr)
999 {
1000 QScrollBar *sb = horizontalScrollBar ();
1001
1002 if (sb && sb->value () == sb->maximum ())
1003 {
1004 int new_cols = m_var_model->display_columns () + 16;
1005
1007 }
1008 }
1009 }
1010 }
1011
1012 void
1014 {
1015 if (action == QAbstractSlider::SliderSingleStepAdd
1016 || action == QAbstractSlider::SliderPageStepAdd
1017 || action == QAbstractSlider::SliderToMaximum
1018 || action == QAbstractSlider::SliderMove)
1019 {
1020 if (m_var_model != nullptr)
1021 {
1022 QScrollBar *sb = verticalScrollBar ();
1023
1024 if (sb && sb->value () == sb->maximum ())
1025 {
1026 int new_rows = m_var_model->display_rows () + 16;
1027
1028 m_var_model->maybe_resize_rows (new_rows);
1029 }
1030 }
1031 }
1032 }
1033
1034
1035 // Gadgets for focus restoration
1036
1038 : QToolButton (parent)
1039 {
1040 installEventFilter (this);
1041 }
1042
1044 {
1045 if (ev->type () == QEvent::HoverEnter)
1046 emit hovered_signal ();
1047 else if (ev->type () == QEvent::MouseButtonPress)
1048 emit popup_shown_signal ();
1049
1050 return QToolButton::eventFilter (obj, ev);
1051 }
1052
1054 : HoverToolButton (parent)
1055 {
1056 installEventFilter (this);
1057 }
1058
1060 {
1061
1062 if (ev->type () == QEvent::MouseButtonRelease && isDown ())
1063 {
1064 emit about_to_activate ();
1065
1066 setDown (false);
1067 QAction *action = defaultAction ();
1068 if (action != nullptr)
1069 action->activate (QAction::Trigger);
1070
1071 return true;
1072 }
1073
1074 return HoverToolButton::eventFilter (obj, ev);
1075 }
1076
1078 : QMenu (parent)
1079 {
1080 installEventFilter (this);
1081 }
1082
1084 {
1085 if (ev->type () == QEvent::MouseButtonRelease && underMouse ())
1086 {
1087 emit about_to_activate ();
1088 }
1089
1090 return QMenu::eventFilter (obj, ev);
1091 }
1092
1093 // Variable editor.
1094
1096 : octave_dock_widget ("VariableEditor", p, oct_qobj),
1097 m_main (new dw_main_window (oct_qobj)),
1098 m_tool_bar (new QToolBar (m_main)),
1099 m_default_width (30),
1100 m_default_height (100),
1101 m_add_font_height (0),
1102 m_use_terminal_font (true),
1103 m_alternate_rows (true),
1104 m_stylesheet (""),
1105 m_font (),
1106 m_sel_font (),
1107 m_table_colors (),
1108 m_current_focus_vname (""),
1109 m_hovered_focus_vname (""),
1110 m_plot_mapper (nullptr),
1111 m_focus_widget (nullptr),
1112 m_focus_widget_vdw (nullptr)
1113 {
1114 set_title (tr ("Variable Editor"));
1115 setStatusTip (tr ("Edit variables."));
1116 setWindowIcon (QIcon (":/actions/icons/logo.png"));
1117 setAttribute (Qt::WA_AlwaysShowToolTips);
1118
1119 m_main->setParent (this);
1120// See Octave bug #53409 and https://bugreports.qt.io/browse/QTBUG-55357
1121#if (QT_VERSION < 0x050601) || (QT_VERSION >= 0x050701)
1122 m_main->setDockOptions (QMainWindow::AnimatedDocks |
1123 QMainWindow::AllowNestedDocks |
1124 QMainWindow::VerticalTabs);
1125#else
1126 m_main->setDockNestingEnabled (true);
1127#endif
1128
1129 // Tool Bar.
1130
1132 m_main->addToolBar (m_tool_bar);
1133
1134 // Colors.
1135
1136 for (int i = 0; i < ve_colors_count; i++)
1137 m_table_colors.append (QColor (Qt::white));
1138
1139 // Use an MDI area that is shrunk to nothing as the central widget.
1140 // Future feature might be to switch to MDI mode in which the dock
1141 // area is shrunk to nothing and the widgets live in the MDI window.
1142
1143 QMdiArea *central_mdiarea = new QMdiArea (m_main);
1144 central_mdiarea->setMinimumSize (QSize (0, 0));
1145 central_mdiarea->setMaximumSize (QSize (0, 0));
1146 central_mdiarea->resize (QSize (0, 0));
1147 m_main->setCentralWidget (central_mdiarea);
1148
1149 setWidget (m_main);
1150
1151 if (! p)
1152 make_window ();
1153 }
1154
1155 void variable_editor::focusInEvent (QFocusEvent *ev)
1156 {
1157 octave_dock_widget::focusInEvent (ev);
1158
1159 // set focus to the current variable or most recent if still valid
1160 if (m_focus_widget != nullptr)
1161 {
1162 // Activating a floating window causes problems.
1163 if (! m_focus_widget_vdw->isFloating ())
1164 activateWindow ();
1165 m_focus_widget->setFocus ();
1166 }
1167 else
1168 {
1169 QWidget *fw = m_main->focusWidget ();
1170 if (fw != nullptr)
1171 {
1172 activateWindow ();
1173 fw->setFocus ();
1174 }
1175 else
1176 {
1177 QDockWidget *any_qdw = m_main->findChild<QDockWidget *> ();
1178 if (any_qdw != nullptr)
1179 {
1180 activateWindow ();
1181 any_qdw->setFocus ();
1182 }
1183 else
1184 setFocus();
1185 }
1186 }
1187 }
1188
1190 {
1191 // FIXME: Maybe toolbar actions could be handled with signals and
1192 // slots so that deleting the toolbar here would disconnect all
1193 // toolbar actions and any other slots that might try to access the
1194 // toolbar would work properly (I'm looking at you,
1195 // handle_focus_change).
1196
1197 delete m_tool_bar;
1198 m_tool_bar = nullptr;
1199 }
1200
1201 void
1203 {
1205
1206 if (m_stylesheet.isEmpty ())
1207 {
1210 }
1211
1212 QDockWidget *existing_qdw = m_main->findChild<QDockWidget *> (name);
1213 if (existing_qdw != NULL)
1214 {
1215 // Already open.
1216
1217 // Put current focused variable out of focus
1218 if (m_main->focusWidget () != nullptr)
1219 {
1220 QFocusEvent event (QEvent::FocusOut, Qt::OtherFocusReason);
1221 QApplication::sendEvent (m_main->focusWidget (), &event);
1222 }
1223
1224 // Put existing variable in focus and raise
1225 m_main->parentWidget ()->show ();
1226 existing_qdw->show ();
1227 existing_qdw->raise ();
1228 existing_qdw->activateWindow ();
1229 tab_to_front ();
1230 existing_qdw->setFocus ();
1231
1232 return;
1233 }
1234
1236 = new variable_dock_widget (this, m_octave_qobj);
1237
1238 page->setObjectName (name);
1239 m_main->addDockWidget (Qt::LeftDockWidgetArea, page);
1240
1241 // The old-style signal/slot connection appears to be needed here to
1242 // prevent a crash when closing a variable_dock_widget object.
1243 connect (qApp, SIGNAL (focusChanged (QWidget *, QWidget *)),
1244 page, SLOT (handle_focus_change (QWidget *, QWidget *)));
1245
1246 connect (this, &variable_editor::visibilityChanged,
1247 page, &variable_dock_widget::setVisible);
1248
1249 // Notify the variable editor for page actions.
1250 connect (page, &variable_dock_widget::destroyed,
1254
1255 // See Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
1256#if (QT_VERSION >= 0x050302) && (QT_VERSION <= QTBUG_44813_FIX_VERSION)
1257 connect (page, SIGNAL (queue_unfloat_float ()),
1258 page, SLOT (unfloat_float ()), Qt::QueuedConnection);
1259 connect (page, SIGNAL (queue_float ()),
1260 page, SLOT (refloat ()), Qt::QueuedConnection);
1261#endif
1262
1265
1266 stack->setObjectName (name);
1267 page->setWidget (stack);
1268 page->setFocusProxy (stack);
1269
1270 // Any interpreter_event signal from a variable_editor_stack object is
1271 // handled the same as for the parent variable_editor object.
1274
1277
1280 connect (this, &variable_editor::level_up_signal,
1282 connect (this, &variable_editor::save_signal,
1283 stack, [=] () { stack->save (); });
1284
1285 variable_editor_view *edit_view = stack->edit_view ();
1286
1287 edit_view->setObjectName (name);
1288 edit_view->setFont (m_font);
1289 edit_view->setStyleSheet (m_stylesheet);
1290 edit_view->setAlternatingRowColors (m_alternate_rows);
1291 edit_view->verticalHeader ()->setDefaultSectionSize (m_default_height
1293
1294 connect (m_plot_mapper, SIGNAL (mapped (const QString&)),
1295 edit_view, SLOT (selected_command_requested (const QString&)));
1296 connect (m_save_mapper, SIGNAL (mapped (const QString&)),
1297 stack, SLOT (save (const QString&)));
1298
1299 connect (edit_view, &variable_editor_view::command_signal,
1309 connect (edit_view->horizontalHeader (),
1310 &QHeaderView::customContextMenuRequested,
1312 connect (edit_view->verticalHeader (),
1313 &QHeaderView::customContextMenuRequested,
1315 connect (edit_view, &variable_editor_view::customContextMenuRequested,
1317 connect (edit_view->horizontalScrollBar (), &QScrollBar::actionTriggered,
1319 connect (edit_view->verticalScrollBar (), &QScrollBar::actionTriggered,
1321
1322 variable_editor_model *model =
1323 new variable_editor_model (name, val, stack);
1324
1327 connect (model, &variable_editor_model::dataChanged,
1329 connect (this, &variable_editor::refresh_signal,
1333
1334 edit_view->setModel (model);
1335 connect (edit_view, &variable_editor_view::doubleClicked,
1337
1338 // Any interpreter_event signal from a variable_editor_model object is
1339 // handled the same as for the parent variable_editor object.
1340
1343
1346
1347 // Must supply a title for a QLabel to be created. Calling set_title()
1348 // more than once will add more QLabels. Could change octave_dock_widget
1349 // to always supply a QLabel (initially empty) and then simply update its
1350 // contents.
1351 page->set_title (name);
1352 if (page->titleBarWidget () != nullptr)
1353 {
1354 QLabel *existing_ql = page->titleBarWidget ()->findChild<QLabel *> ();
1355
1356 // FIXME: What was the intent here? update_label_signal does
1357 // not seem to exist now.
1358 connect (model, SIGNAL (description_changed (const QString&)),
1359 existing_ql, SLOT (setText (const QString&)));
1360 existing_ql->setMargin (2);
1361 }
1362
1363 model->update_data (val);
1364
1365 if (m_tool_bar)
1366 {
1367 QList<QTableView *> viewlist = findChildren<QTableView *> ();
1368 if (viewlist.size () == 1 && m_tool_bar)
1369 m_tool_bar->setEnabled (true);
1370 }
1371
1372 show ();
1373 page->show ();
1374 page->raise ();
1375 page->activateWindow ();
1376 tab_to_front ();
1377 page->setFocus ();
1378 }
1379
1380 void
1382 {
1383 QWidget *parent = parentWidget ();
1384
1385 if (parent)
1386 {
1387 QList<QTabBar *> barlist = parent->findChildren<QTabBar *> ();
1388
1389 QVariant this_value (reinterpret_cast<quintptr> (this));
1390
1391 for (auto *tbar : barlist)
1392 {
1393 for (int i = 0; i < tbar->count (); i++)
1394 {
1395 if (tbar->tabData (i) == this_value)
1396 {
1397 tbar->setCurrentIndex (i);
1398 return;
1399 }
1400 }
1401 }
1402 }
1403 }
1404
1405 void
1407 {
1408 emit refresh_signal ();
1409 }
1410
1411 void
1412 variable_editor::callUpdate (const QModelIndex&, const QModelIndex&)
1413 {
1414 emit updated ();
1415 }
1416
1417 void
1419 {
1420 m_main->notice_settings (settings); // update settings in parent main win
1421
1422 m_default_width = settings->value (ve_column_width).toInt ();
1423
1424 m_default_height = settings->value (ve_row_height).toInt ();
1425
1426 m_alternate_rows = settings->value (ve_alternate_rows).toBool ();
1427
1429
1430 QString font_name;
1431 int font_size;
1432 QString default_font = settings->value (global_mono_font).toString ();
1433
1435 {
1436 font_name = settings->value (cs_font.key, default_font).toString ();
1437 font_size = settings->value (cs_font_size).toInt ();
1438 }
1439 else
1440 {
1441 font_name = settings->value (ve_font_name.key, default_font).toString ();
1442 font_size = settings->value (ve_font_size).toInt ();
1443 }
1444
1445 m_font = QFont (font_name, font_size);
1446
1447 QFontMetrics fm (m_font);
1448
1449 m_add_font_height = fm.height ();
1450
1451 int mode = settings->value (ve_color_mode).toInt ();
1452
1453 for (int i = 0; i < ve_colors_count; i++)
1454 {
1455 QColor setting_color = settings->color_value (ve_colors[i], mode);
1456 m_table_colors.replace (i, setting_color);
1457 }
1458
1459 update_colors ();
1460
1461 // Icon size in the toolbar.
1462
1463 if (m_tool_bar)
1464 {
1465 int size_idx = settings->value (global_icon_size).toInt ();
1466 size_idx = (size_idx > 0) - (size_idx < 0) + 1; // Make valid index from 0 to 2
1467
1468 QStyle *st = style ();
1469 int icon_size = st->pixelMetric (global_icon_sizes[size_idx]);
1470 m_tool_bar->setIconSize (QSize (icon_size, icon_size));
1471 }
1472
1473 // Shortcuts (same as file editor)
1476 }
1477
1478 void
1480 {
1481 emit finished ();
1482
1484 }
1485
1486 void
1488 {
1489 // Invalidate the focus-restoring widget pointer if currently active.
1490 if (m_focus_widget_vdw == obj)
1491 {
1492 m_focus_widget = nullptr;
1493 m_focus_widget_vdw = nullptr;
1494 }
1495
1496 if (m_tool_bar)
1497 {
1498 // If no variable pages remain, deactivate the tool bar.
1499 QList<variable_dock_widget *> vdwlist = findChildren<variable_dock_widget *> ();
1500 if (vdwlist.isEmpty ())
1501 m_tool_bar->setEnabled (false);
1502 }
1503
1504 QFocusEvent ev (QEvent::FocusIn);
1505 focusInEvent (&ev);
1506 }
1507
1508 void
1510 {
1512
1513 // focusWidget() appears lost in transition to/from main window
1514 // so keep a record of the widget.
1515
1516 QWidget *current = QApplication::focusWidget ();
1517 m_focus_widget = nullptr;
1518 m_focus_widget_vdw = nullptr;
1519 if (current != nullptr)
1520 {
1521 QList<variable_dock_widget *> vdwlist = findChildren<variable_dock_widget *> ();
1522 for (int i = 0; i < vdwlist.size (); i++)
1523 {
1524 variable_dock_widget *vdw = vdwlist.at (i);
1525 if (vdw->isAncestorOf (current))
1526 {
1527 m_focus_widget = current;
1528 m_focus_widget_vdw = vdw;
1529 break;
1530 }
1531 }
1532 }
1533 }
1534
1535 void
1537 {
1539 }
1540
1541 void
1543 {
1544 variable_dock_widget *tofocus = findChild<variable_dock_widget *> (m_hovered_focus_vname);
1545 if (tofocus != nullptr)
1546 {
1547 // Note that this may be platform and window system dependent.
1548 // On a particular Linux system, activateWindow() alone didn't
1549 // immediately set the active window and there was a race
1550 // between the window focus and action signal. Setting the
1551 // active window via the QApplication route did work.
1552 QApplication::setActiveWindow(tofocus->window());
1553 tofocus->activateWindow ();
1554 tofocus->setFocus (Qt::OtherFocusReason);
1555 }
1556 }
1557
1558 void
1560 {
1561 emit save_signal ();
1562 }
1563
1564 void
1566 {
1567 copyClipboard ();
1568
1569 emit clear_content_signal ();
1570 }
1571
1572 void
1574 {
1575 emit copy_clipboard_signal ();
1576 }
1577
1578 void
1580 {
1581 emit paste_clipboard_signal ();
1582
1583 emit updated ();
1584 }
1585
1586 void
1588 {
1589 emit level_up_signal ();
1590 }
1591
1592 // Also updates the font.
1593
1595 {
1596 m_stylesheet = "";
1597
1598 if (m_table_colors.length () > 0)
1599 m_stylesheet += "QTableView::item{ color: "
1600 + m_table_colors[0].name () +" }";
1601
1602 if (m_table_colors.length () > 1)
1603 m_stylesheet += "QTableView::item{ background-color: "
1604 + m_table_colors[1].name () +" }";
1605
1606 if (m_table_colors.length () > 2)
1607 m_stylesheet += "QTableView::item{ selection-color: "
1608 + m_table_colors[2].name () +" }";
1609
1610 if (m_table_colors.length () > 3)
1611 m_stylesheet += "QTableView::item:selected{ background-color: "
1612 + m_table_colors[3].name () +" }";
1613
1614 if (m_table_colors.length () > 4 && m_alternate_rows)
1615 {
1616 m_stylesheet += "QTableView::item:alternate{ background-color: "
1617 + m_table_colors[4].name () +" }";
1618
1619 m_stylesheet += "QTableView::item:alternate:selected{ background-color: "
1620 + m_table_colors[3].name () +" }";
1621 }
1622
1623 QList<QTableView *> viewlist = findChildren<QTableView *> ();
1624 for (int i = 0; i < viewlist.size (); i++)
1625 {
1626 QTableView *view = viewlist.at (i);
1627
1628 if (! view)
1629 continue;
1630
1631 view->setAlternatingRowColors (m_alternate_rows);
1632 view->setStyleSheet (m_stylesheet);
1633 view->setFont (m_font);
1634 }
1635
1636 }
1637
1638 QAction *
1640 const QString& text,
1641 const QObject *receiver,
1642 const char *member)
1643 {
1644 QAction *action = new QAction (icon, text, this);
1645 connect(action, SIGNAL (triggered ()), receiver, member);
1647 button->setDefaultAction (action);
1648 button->setText (text);
1649 button->setToolTip (text);
1650 button->setIcon (icon);
1651 m_tool_bar->addWidget (button);
1652
1653 return action;
1654 }
1655
1656 void
1658 {
1659 m_tool_bar->setAllowedAreas (Qt::TopToolBarArea);
1660
1661 m_tool_bar->setObjectName ("VariableEditorToolBar");
1662
1663 m_tool_bar->setWindowTitle (tr ("Variable Editor Toolbar"));
1664
1666
1667 m_save_action = add_tool_bar_button (rmgr.icon ("document-save"), tr ("Save"),
1668 this, SLOT (save ()));
1669 addAction (m_save_action);
1670 m_save_action->setShortcutContext (Qt::WidgetWithChildrenShortcut);
1671 m_save_action->setStatusTip(tr("Save variable to a file"));
1672
1673 QAction *action = new QAction (rmgr.icon ("document-save-as"), tr ("Save in format ..."), m_tool_bar);
1674
1675 QToolButton *save_tool_button = new HoverToolButton (m_tool_bar);
1676 save_tool_button->setDefaultAction (action);
1677
1678 save_tool_button->setText (tr ("Save in format ..."));
1679 save_tool_button->setToolTip (tr("Save variable to a file in different format"));
1680 save_tool_button->setIcon (rmgr.icon ("document-save-as"));
1681 save_tool_button->setPopupMode (QToolButton::InstantPopup);
1682
1683 QMenu *save_menu = new ReturnFocusMenu (save_tool_button);
1684 save_menu->setTitle (tr ("Save in format ..."));
1685 save_menu->setSeparatorsCollapsible (false);
1686
1687 m_save_mapper = new QSignalMapper (save_menu);
1688 for (int i = 0; i < ve_save_formats.length (); i++)
1689 m_save_mapper->setMapping
1690 (save_menu->addAction (ve_save_formats.at (i),
1691 m_save_mapper, SLOT (map ())),
1692 ve_save_formats.at (i));
1693
1694 save_tool_button->setMenu (save_menu);
1695 m_tool_bar->addWidget (save_tool_button);
1696
1697 m_tool_bar->addSeparator ();
1698
1699 action = add_tool_bar_button (rmgr.icon ("edit-cut"), tr ("Cut"),
1700 this, SLOT (cutClipboard ()));
1701 action->setStatusTip(tr("Cut data to clipboard"));
1702
1703 action = add_tool_bar_button (rmgr.icon ("edit-copy"), tr ("Copy"),
1704 this, SLOT (copyClipboard ()));
1705 action->setStatusTip(tr("Copy data to clipboard"));
1706
1707 action = add_tool_bar_button (rmgr.icon ("edit-paste"), tr ("Paste"),
1708 this, SLOT (pasteClipboard ()));
1709 action->setStatusTip(tr("Paste clipboard into variable data"));
1710
1711 m_tool_bar->addSeparator ();
1712
1713 // FIXME: Add a print item?
1714 // QAction *print_action; /icons/fileprint.png
1715 // m_tool_bar->addSeparator ();
1716
1717 action = new QAction (rmgr.icon ("plot-xy-curve"), tr ("Plot"), m_tool_bar);
1718 action->setToolTip (tr ("Plot Selected Data"));
1719 QToolButton *plot_tool_button = new HoverToolButton (m_tool_bar);
1720 plot_tool_button->setDefaultAction (action);
1721
1722 plot_tool_button->setText (tr ("Plot"));
1723 plot_tool_button->setToolTip (tr ("Plot selected data"));
1724 plot_tool_button->setIcon (rmgr.icon ("plot-xy-curve"));
1725
1726 plot_tool_button->setPopupMode (QToolButton::InstantPopup);
1727
1728 QMenu *plot_menu = new ReturnFocusMenu (plot_tool_button);
1729 plot_menu->setTitle (tr ("Plot"));
1730 plot_menu->setSeparatorsCollapsible (false);
1731
1732 m_plot_mapper = make_plot_mapper (plot_menu);
1733
1734 plot_tool_button->setMenu (plot_menu);
1735
1736 m_tool_bar->addWidget (plot_tool_button);
1737
1738 m_tool_bar->addSeparator ();
1739
1740 action = add_tool_bar_button (rmgr.icon ("go-up"), tr ("Up"), this,
1741 SLOT (levelUp ()));
1742 action->setStatusTip(tr("Go one level up in variable hierarchy"));
1743
1744 // The QToolButton mouse-clicks change active window, so connect all
1745 // HoverToolButton and ReturnFocusToolButton objects to the mechanism
1746 // that restores active window and focus before acting.
1747 QList<HoverToolButton *> hbuttonlist
1748 = m_tool_bar->findChildren<HoverToolButton *> (""
1749 , Qt::FindDirectChildrenOnly
1750 );
1751 for (int i = 0; i < hbuttonlist.size (); i++)
1752 {
1753 connect (hbuttonlist.at (i), &HoverToolButton::hovered_signal,
1755 connect (hbuttonlist.at (i), &HoverToolButton::popup_shown_signal,
1757 }
1758
1760 = m_tool_bar->findChildren<ReturnFocusToolButton *> (""
1761 , Qt::FindDirectChildrenOnly
1762 );
1763 for (int i = 0; i < rfbuttonlist.size (); i++)
1764 {
1765 connect (rfbuttonlist.at (i), &ReturnFocusToolButton::about_to_activate,
1767 }
1768
1769 // Same for QMenu
1771 = m_tool_bar->findChildren<ReturnFocusMenu *> ();
1772 for (int i = 0; i < menulist.size (); i++)
1773 {
1774 connect (menulist.at (i), &ReturnFocusMenu::about_to_activate,
1776 }
1777
1778 m_tool_bar->setAttribute(Qt::WA_ShowWithoutActivating);
1779 m_tool_bar->setFocusPolicy (Qt::NoFocus);
1780
1781 // Disabled when no tab is present.
1782
1783 m_tool_bar->setEnabled (false);
1784 }
1785
1786}
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
HoverToolButton(QWidget *parent=nullptr)
bool eventFilter(QObject *obj, QEvent *ev)
void popup_shown_signal(void)
bool eventFilter(QObject *obj, QEvent *ev)
void about_to_activate(void)
ReturnFocusMenu(QWidget *parent=nullptr)
ReturnFocusToolButton(QWidget *parent=nullptr)
bool eventFilter(QObject *obj, QEvent *ev)
Base class for Octave interfaces that use Qt.
shortcut_manager & get_shortcut_manager(void)
resource_manager & get_resource_manager(void)
void notice_settings(const gui_settings *)
void set_title(const QString &)
void make_window(bool widget_was_dragged=false)
virtual void closeEvent(QCloseEvent *e)
gui_settings * get_settings(void) const
QIcon icon(const QString &icon_name, bool fallback=true)
void set_shortcut(QAction *action, const sc_pref &scpref, bool enable=true)
void resizeEvent(QResizeEvent *event)
variable_dock_widget(QWidget *p, base_qobject &oct_qobj)
void handle_focus_change(QWidget *old, QWidget *now)
virtual void closeEvent(QCloseEvent *e)
void variable_focused_signal(const QString &name)
void interpreter_event(const fcn_callback &fcn)
void double_click(const QModelIndex &idx)
void edit_variable_signal(const QString &name, const octave_value &val)
bool clear_content(const QModelIndex &idx)
void update_data(const octave_value &val)
octave_idx_type data_rows(void) const
octave_idx_type data_columns(void) const
void do_save(const QString &format, const QString &save_opts)
void edit_variable_signal(const QString &name, const octave_value &val)
variable_editor_view * m_edit_view
void do_save_signal(const QString &format, const QString &save_opts)
variable_editor_stack(QWidget *p, base_qobject &oct_qobj)
void save(const QString &format=QString())
void interpreter_event(const fcn_callback &fcn)
variable_editor_view * edit_view(void)
void set_editable(bool editable)
QTextEdit * make_disp_view(QWidget *parent)
void add_edit_actions(QMenu *menu, const QString &qualifier_string)
QList< int > range_selected(void)
void createColumnMenu(const QPoint &pt)
void selected_command_requested(const QString &cmd)
void command_signal(const QString &cmd)
variable_editor_model * m_var_model
void createContextMenu(const QPoint &pt)
variable_editor_view(QWidget *p, base_qobject &oct_qobj)
void handle_vertical_scroll_action(int action)
void createRowMenu(const QPoint &pt)
void setModel(QAbstractItemModel *model)
void handle_horizontal_scroll_action(int action)
void variable_destroyed(QObject *obj)
void clear_content_signal(void)
void closeEvent(QCloseEvent *)
void copy_clipboard_signal(void)
void record_hovered_focus_variable(void)
void interpreter_event(const fcn_callback &fcn)
QList< QColor > m_table_colors
QAction * add_tool_bar_button(const QIcon &icon, const QString &text, const QObject *receiver, const char *member)
variable_editor(QWidget *parent, base_qobject &oct_qobj)
void notice_settings(const gui_settings *)
variable_dock_widget * m_focus_widget_vdw
dw_main_window * m_main
void paste_clipboard_signal(void)
QSignalMapper * m_save_mapper
void edit_variable(const QString &name, const octave_value &val)
void focusInEvent(QFocusEvent *ev)
void delete_selected_signal(void)
void command_signal(const QString &cmd)
void restore_hovered_focus_variable(void)
void callUpdate(const QModelIndex &, const QModelIndex &)
void variable_focused(const QString &name)
QSignalMapper * m_plot_mapper
const gui_pref cs_font_size("terminal/fontSize", QVariant(10))
const gui_pref cs_font("terminal/fontName", QVariant())
QString name
const gui_pref global_mono_font("monospace_font", global_font_family)
const QStyle::PixelMetric global_icon_sizes[3]
const gui_pref global_use_native_dialogs("use_native_file_dialogs", QVariant(true))
const gui_pref global_icon_size("toolbar_icon_size", QVariant(0))
const sc_pref sc_edit_file_save(sc_edit_file+":save", QKeySequence::Save)
const gui_pref ve_color_mode("variable_editor/color_mode", QVariant(0))
const int ve_colors_count
const QStringList ve_save_formats(QStringList()<< "ascii"<< "binary"<< "float-binary"<< "hdf5"<< "float-hdf5"<< "text"<< "mat7-binary"<< "mat-binary"<< "mat4-binary"<< "zip")
const gui_pref ve_column_width("variable_editor/column_width", QVariant(100))
const QStringList ve_save_formats_ext(QStringList()<< "-ascii"<< "dat"<< "-hdf5"<< "h5"<< "-text"<< "txt"<< "-v7.3"<< "mat"<< "-7.3"<< "mat"<< "-v7"<< "mat"<< "-7"<< "mat"<< "-mat7-binary"<< "mat"<< "-v6"<< "mat"<< "-6"<< "mat"<< "-mat-binary"<< "mat"<< "-v4"<< "mat"<< "-4"<< "mat"<< "-mat4-binary"<< "mat"<< "-binary"<< "bin"<< "-z"<< "txt.gz")
const gui_pref ve_use_terminal_font("variable_editor/use_terminal_font", QVariant(true))
const gui_pref ve_font_size("variable_editor/font_size", QVariant(10))
const gui_pref ve_alternate_rows("variable_editor/alternate_rows", QVariant(false))
const gui_pref ve_font_name("variable_editor/font_name", QVariant())
const gui_pref ve_colors[2 *ve_colors_count]
const gui_pref ve_row_height("variable_editor/row_height", QVariant(10))
OCTAVE_EXPORT octave_value_list Fsave(octave::interpreter &interp, const octave_value_list &args, int nargout)
Definition: load-save.cc:1810
OCTAVE_EXPORT octave_value_list Fsave_default_options(octave::interpreter &interp, const octave_value_list &args, int nargout)
Definition: load-save.cc:1950
std::complex< double > w(std::complex< double > z, double relerr=0)
QString fromStdString(const std::string &s)
static QSignalMapper * make_plot_mapper(QMenu *menu)
class OCTAVE_API range
Definition: range-fwd.h:33
int qt_fontmetrics_horizontal_advance(const QFontMetrics &fm, QChar ch)
Definition: qt-utils.h:48
octave_int< T > mod(const octave_int< T > &x, const octave_int< T > &y)
Definition: oct-inttypes.h:916
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
static std::string format_string("short")
const QString key
std::size_t format(std::ostream &os, const char *fmt,...)
Definition: utils.cc:1471
#define DOCKED_FULLSCREEN_BUTTON_TOOLTIP
#define UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP
#define QTBUG_44813_FIX_VERSION