GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
variable-editor-model.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 <sstream>
31
32#include <QDebug>
33#include <QLabel>
34#include <QMap>
35#include <QMessageBox>
36#include <QString>
37#include <QTableView>
38
41
42#include "Cell.h"
43#include "interpreter.h"
44#include "oct-map.h"
45#include "ov.h"
46#include "parse.h"
47#include "pr-flt-fmt.h"
48#include "utils.h"
49#include "variables.h"
50
51namespace octave
52{
53 static bool
55 {
56 if ((val.isnumeric () || val.islogical ()) && val.numel () == 1)
57 return true;
58
59 if (val.is_string () && (val.rows () == 1 || val.is_zero_by_zero ()))
60 return true;
61
62 return false;
63 }
64
65 static char
67 {
68 if (val.is_sq_string ())
69 return '\'';
70
71 if (val.is_dq_string ())
72 return '"';
73
74 return 0;
75 }
76
79 {
80 // FIXME: make this limit configurable.
81
82 return (val.numel () > 250000
84 }
85
86 static bool
88 {
89 return (! ((elt.numel () == 1 && (elt.isnumeric () || elt.islogical ()))
90 || (elt.is_string () && (elt.rows () == 1 || elt.isempty ()))));
91 }
92
93 base_ve_model::base_ve_model (const QString& expr, const octave_value& val)
94 : m_name (expr.toStdString ()),
95 m_value (val),
96 m_data_rows (m_value.rows ()),
97 m_data_cols (m_value.columns ()),
98 m_display_rows (m_data_rows),
99 m_display_cols (m_data_cols),
100 m_update_pending (),
101 m_valid (m_value.is_defined ()),
102 m_display_fmt (get_edit_display_format (m_value))
103 { }
104
105 std::string
107 {
108 return m_name;
109 }
110
111 bool
112 base_ve_model::index_ok (const QModelIndex& idx, int& row, int& col) const
113 {
114 row = 0;
115 col = 0;
116
117 if (! idx.isValid ())
118 return false;
119
120 row = idx.row ();
121 col = idx.column ();
122
123 return (row < data_rows () && col < data_columns ());
124 }
125
126 int
128 {
129 int width = 0;
130
133
134 int rw = r_fmt.width ();
135 int iw = i_fmt.width ();
136
137 if (rw > 0)
138 {
139 if (m_value.iscomplex ())
140 {
141 if (iw > 0)
142 width = rw + iw + 5;
143 }
144 else
145 width = rw + 2;
146 }
147
148 return width;
149 }
150
151 int
152 base_ve_model::rowCount (const QModelIndex&) const
153 {
154 return m_valid ? m_display_rows : 1;
155 }
156
157 int
158 base_ve_model::columnCount (const QModelIndex&) const
159 {
160 return m_valid ? m_display_cols : 1;
161 }
162
163 QString
165 {
166 std::string str;
167
168 if (cell_is_editable (elt))
169 {
171
172 if (role == Qt::DisplayRole)
173 fmt = get_edit_display_format (elt);
174 else
175 fmt.set_precision (elt.is_single_type () ? 8 : 16);
176
177 str = elt.edit_display (fmt, 0, 0);
178 }
179 else
180 {
181 dim_vector dv = elt.dims ();
182 str = "[" + dv.str () + " " + elt.class_name () + "]";
183 }
184
185 return QString::fromStdString (str);
186 }
187
188 QVariant
189 base_ve_model::edit_display (const QModelIndex& idx, int role) const
190 {
191 int row;
192 int col;
193
194 if (! index_ok (idx, row, col))
195 return QVariant ();
196
198 if (role == Qt::DisplayRole)
199 fmt = m_display_fmt;
200 else
201 fmt.set_precision (m_value.is_single_type () ? 8 : 16);
202
203 std::string str = m_value.edit_display (fmt, row, col);
204
205 return QString::fromStdString (str);
206 }
207
208 QVariant
209 base_ve_model::data (const QModelIndex& idx, int role) const
210 {
211 if (idx.isValid () && role == Qt::DisplayRole && update_pending (idx))
212 return QVariant (update_pending_data (idx));
213
214 if (! m_valid)
215 {
216 if (role == Qt::DisplayRole)
217 return QVariant (QString ("Variable %1 not found or value can't be edited")
219
220 return QVariant (QString ("x"));
221 }
222
223 switch (role)
224 {
225 case Qt::DisplayRole:
226 case Qt::EditRole:
227 return edit_display (idx, role);
228 }
229
230 // Invalid.
231 return QVariant ();
232 }
233
234 bool
235 base_ve_model::requires_sub_editor (const QModelIndex&) const
236 {
237 return false;
238 }
239
240 void
241 base_ve_model::set_update_pending (const QModelIndex& idx, const QString& str)
242 {
243 m_update_pending[idx] = str;
244 }
245
246 bool
247 base_ve_model::update_pending (const QModelIndex& idx) const
248 {
249 return m_update_pending.contains (idx);
250 }
251
252 QString
253 base_ve_model::update_pending_data (const QModelIndex& idx) const
254 {
255 return m_update_pending[idx];
256 }
257
258 void
260 {
261 return m_update_pending.clear ();
262 }
263
264 char
265 base_ve_model::quote_char (const QModelIndex&) const
266 {
267 return 0;
268 }
269
270 QVariant
271 base_ve_model::header_data (int section, Qt::Orientation, int role) const
272 {
273
274 if (role != Qt::DisplayRole)
275 return QVariant ();
276
277 return QString::number (section+1);
278 }
279
280 QString
281 base_ve_model::subscript_expression (const QModelIndex&) const
282 {
283 return "";
284 }
285
286 QString
288 {
289 QString lbl_txt = QString::fromStdString (m_name);
290
291 if (m_value.is_defined ())
292 {
293 if (! lbl_txt.isEmpty ())
294 lbl_txt += " ";
295
296 dim_vector dv = m_value.dims ();
297
298 lbl_txt += ("["
300 + " "
302 + "]");
303 }
304 else
305 lbl_txt += " [undefined]";
306
307 return lbl_txt;
308 }
309
310 // Private slots.
311
313 base_ve_model::value_at (const QModelIndex&) const
314 {
315 return octave_value ();
316 }
317
319 {
320 public:
321
322 numeric_model (const QString& expr, const octave_value& val)
323 : base_ve_model (expr, val)
324 {
325 // FIXME: should fill the window and expand on scrolling or
326 // resizing.
327
330 }
331
332 ~numeric_model (void) = default;
333
334 // No copying!
335
336 numeric_model (const numeric_model&) = delete;
337
339
340 void maybe_resize_rows (int rows)
341 {
342 if (rows > m_display_rows)
343 m_display_rows = rows;
344 }
345
346 void maybe_resize_columns (int cols)
347 {
348 if (cols > m_display_cols)
349 m_display_cols = cols;
350 }
351
352 QVariant edit_display (const QModelIndex& idx, int role) const
353 {
354 int row;
355 int col;
356
357 if (! index_ok (idx, row, col))
358 return QVariant ();
359
361 if (role == Qt::DisplayRole)
362 fmt = m_display_fmt;
363 else
364 fmt.set_precision (m_value.is_single_type () ? 8 : 16);
365
366 std::string str = m_value.edit_display (fmt, row, col);
367
368 return QString::fromStdString (str);
369 }
370
371 QString subscript_expression (const QModelIndex& idx) const
372 {
373 if (! idx.isValid ())
374 return "";
375
376 return (QString ("(%1,%2)")
377 .arg (idx.row () + 1)
378 .arg (idx.column () + 1));
379 }
380 };
381
383 {
384 public:
385
386 string_model (const QString& expr, const octave_value& val)
387 : base_ve_model (expr, val)
388 {
389 m_data_rows = 1;
390 m_data_cols = 1;
391
392 m_display_rows = 1;
393 m_display_cols = 1;
394 }
395
396 ~string_model (void) = default;
397
398 // No copying!
399
400 string_model (const string_model&) = delete;
401
403
404 QVariant edit_display (const QModelIndex&, int) const
405 {
406 // There isn't really a format for strings...
407
408 std::string str = m_value.edit_display (float_display_format (), 0, 0);
409
410 return QString::fromStdString (str);
411 }
412
413 char quote_char (const QModelIndex&) const
414 {
415 return get_quote_char (m_value);
416 }
417 };
418
420 {
421 public:
422
423 cell_model (const QString& expr, const octave_value& val)
424 : base_ve_model (expr, val)
425 {
426 // FIXME: should fill the window and expand on scrolling or
427 // resizing.
428
431 }
432
433 ~cell_model (void) = default;
434
435 // No copying!
436
437 cell_model (const cell_model&) = delete;
438
440
441 void maybe_resize_rows (int rows)
442 {
443 if (rows > m_display_rows)
444 m_display_rows = rows;
445 }
446
447 void maybe_resize_columns (int cols)
448 {
449 if (cols > m_display_cols)
450 m_display_cols = cols;
451 }
452
453 QVariant edit_display (const QModelIndex& idx, int role) const
454 {
455 int row;
456 int col;
457
458 if (! index_ok (idx, row, col))
459 return QVariant ();
460
461 Cell cval = m_value.cell_value ();
462
463 return edit_display_sub (cval(row, col), role);
464 }
465
466 bool requires_sub_editor (const QModelIndex& idx) const
467 {
468 int row;
469 int col;
470
471 if (! index_ok (idx, row, col))
472 return false;
473
474 Cell cval = m_value.cell_value ();
475
476 return do_requires_sub_editor_sub (cval(row, col));
477 }
478
479 char quote_char (const QModelIndex& idx) const
480 {
481 octave_value ov = value_at (idx);
482
483 if (ov.is_string ())
484 return get_quote_char (ov);
485
486 return 0;
487 }
488
489 QString subscript_expression (const QModelIndex& idx) const
490 {
491 if (! idx.isValid ())
492 return "";
493
494 return (QString ("{%1,%2}")
495 .arg (idx.row () + 1)
496 .arg (idx.column () + 1));
497 }
498
499 octave_value value_at (const QModelIndex& idx) const
500 {
501 int row;
502 int col;
503
504 if (! index_ok (idx, row, col))
505 return octave_value ();
506
507 Cell cval = m_value.cell_value ();
508
509 return cval(row, col);
510 }
511 };
512
513 // Scalar struct. Rows are fields, single column for values.
514
516 {
517 public:
518
519 scalar_struct_model (const QString& expr, const octave_value& val)
520 : base_ve_model (expr, val)
521 {
522 // No extra cells. We currently don't allow new fields or
523 // additional values to be inserted. If we allow additional values,
524 // then the object becomes a vector structure and the display flips
525 // (see the vector struct model below). Do we want that?
526
527 m_data_rows = val.nfields ();
528 m_data_cols = 1;
529
531 m_display_cols = 1;
532 }
533
534 ~scalar_struct_model (void) = default;
535
536 // No copying!
537
539
541
542 QVariant edit_display (const QModelIndex& idx, int role) const
543 {
544 int row;
545 int col;
546
547 if (! index_ok (idx, row, col))
548 return QVariant ();
549
551
552 return edit_display_sub (m.contents (row), role);
553 }
554
555 bool requires_sub_editor (const QModelIndex& idx) const
556 {
557 int row;
558 int col;
559
560 if (! index_ok (idx, row, col))
561 return false;
562
564
565 return do_requires_sub_editor_sub (m.contents (row));
566 }
567
568 char quote_char (const QModelIndex& idx) const
569 {
570 octave_value ov = value_at (idx);
571
572 if (ov.is_string ())
573 return get_quote_char (ov);
574
575 return 0;
576 }
577
578 QVariant header_data (int section, Qt::Orientation orientation,
579 int role) const
580 {
581 if (role != Qt::DisplayRole)
582 return QVariant ();
583
584 switch (orientation)
585 {
586 case Qt::Horizontal:
587 if (section < data_columns ())
588 return QString ("Values");
589 else
590 break;
591
592 case Qt::Vertical:
593 if (section < data_rows ())
594 {
596
597 string_vector fields = m.fieldnames ();
598
599 return QString::fromStdString (fields(section));
600 }
601 else
602 break;
603
604 default:
605 break;
606 }
607
608 return QVariant ();
609 }
610
611 QString subscript_expression (const QModelIndex& idx) const
612 {
613 // Display size and data size match, so all valid indices should
614 // also be valid indices for the existing struct.
615
616 int row;
617 int col;
618
619 if (! index_ok (idx, row, col))
620 return "";
621
623
624 string_vector fields = m.fieldnames ();
625
626 return QString (".%1").arg (QString::fromStdString (fields(row)));
627 }
628
629 octave_value value_at (const QModelIndex& idx) const
630 {
631 int row;
632 int col;
633
634 if (! index_ok (idx, row, col))
635 return octave_value ();
636
638
639 return m.contents (row);
640 }
641 };
642
644 {
645 public:
646
647 display_only_model (const QString& expr, const octave_value& val)
648 : base_ve_model (expr, val)
649 {
650 m_data_rows = 1;
651 m_data_cols = 1;
652
655 }
656
657 ~display_only_model (void) = default;
658
659 // No copying!
660
662
664
665 bool is_editable (void) const { return false; }
666
667 QVariant edit_display (const QModelIndex&, int) const
668 {
669 if (m_value.is_undefined ())
670 return QVariant ();
671
672 std::ostringstream buf;
673
674 octave_value tval = m_value;
675
676 tval.print_with_name (buf, m_name);
677
678 return QString::fromStdString (buf.str ());
679 }
680
681 QString make_description_text (void) const
682 {
683 return (QString ("unable to edit %1")
685 }
686 };
687
688 // Vector struct. Columns are fields, rows are values.
689
691 {
692 public:
693
694 vector_struct_model (const QString& expr, const octave_value& val)
695 : base_ve_model (expr, val)
696 {
697 // FIXME: should fill the window vertically and expand on scrolling
698 // or resizing. No extra cells horizontally. New fields must be
699 // added specially.
700
701 m_data_rows = val.numel ();
702 m_data_cols = val.nfields ();
703
706 }
707
708 ~vector_struct_model (void) = default;
709
710 // No copying!
711
713
715
716 void maybe_resize_rows (int rows)
717 {
718 if (rows > m_display_rows)
719 m_display_rows = rows;
720 }
721
722 QVariant edit_display (const QModelIndex& idx, int role) const
723 {
724 int row;
725 int col;
726
727 if (! index_ok (idx, row, col))
728 return QVariant ();
729
731
732 Cell cval = m.contents (col);
733
734 return edit_display_sub (cval(row), role);
735 }
736
737 bool requires_sub_editor (const QModelIndex& idx) const
738 {
739 int row;
740 int col;
741
742 if (! index_ok (idx, row, col))
743 return false;
744
746
747 Cell cval = m.contents (col);
748
749 return do_requires_sub_editor_sub (cval(row));
750 }
751
752 char quote_char (const QModelIndex& idx) const
753 {
754 octave_value ov = value_at (idx);
755
756 if (ov.is_string ())
757 return get_quote_char (ov);
758
759 return 0;
760 }
761
762 QVariant header_data (int section, Qt::Orientation orientation,
763 int role) const
764 {
765 if (role != Qt::DisplayRole)
766 return QVariant ();
767
768 switch (orientation)
769 {
770 case Qt::Horizontal:
771 if (section < data_columns ())
772 {
774
775 string_vector fields = m.fieldnames ();
776
777 return QString::fromStdString (fields(section));
778 }
779 else
780 break;
781
782 case Qt::Vertical:
783 if (section < data_rows ())
784 return QString::number (section+1);
785 else
786 break;
787
788 default:
789 break;
790 }
791
792 return QVariant ();
793 }
794
795 QString subscript_expression (const QModelIndex& idx) const
796 {
797 if (! idx.isValid ())
798 return "";
799
801
802 string_vector fields = m.fieldnames ();
803
804 return (QString ("(%1).%2")
805 .arg (idx.row () + 1)
806 .arg (QString::fromStdString (fields(idx.column ()))));
807 }
808
809 octave_value value_at (const QModelIndex& idx) const
810 {
811 int row;
812 int col;
813
814 if (! index_ok (idx, row, col))
815 return octave_value ();
816
818
819 Cell cval = m.contents (col);
820
821 return cval(row);
822 }
823 };
824
825 // 2-d struct array. Rows and columns index individual scalar structs.
826
828 {
829 public:
830
831 struct_model (const QString& expr, const octave_value& val)
832 : base_ve_model (expr, val)
833 {
834 // FIXME: should fill the window and expand on scrolling or
835 // resizing.
836
839 }
840
841 ~struct_model (void) = default;
842
843 // No copying!
844
845 struct_model (const struct_model&) = delete;
846
848
849 void maybe_resize_rows (int rows)
850 {
851 if (rows > m_display_rows)
852 m_display_rows = rows;
853 }
854
855 void maybe_resize_columns (int cols)
856 {
857 if (cols > m_display_cols)
858 m_display_cols = cols;
859 }
860
861 QVariant edit_display (const QModelIndex& idx, int) const
862 {
863 int row;
864 int col;
865
866 if (! index_ok (idx, row, col))
867 return QVariant ();
868
869 std::string str = m_value.edit_display (m_display_fmt, row, col);
870 return QString::fromStdString (str);
871 }
872
873 bool requires_sub_editor (const QModelIndex& idx) const
874 {
875 int row;
876 int col;
877
878 if (! index_ok (idx, row, col))
879 return false;
880
882
883 return do_requires_sub_editor_sub (m(row, col));
884 }
885
886 char quote_char (const QModelIndex& idx) const
887 {
888 octave_value ov = value_at (idx);
889
890 if (ov.is_string ())
891 return get_quote_char (ov);
892
893 return 0;
894 }
895
896 QString subscript_expression (const QModelIndex& idx) const
897 {
898 int row;
899 int col;
900
901 if (! index_ok (idx, row, col))
902 return "";
903
904 return (QString ("(%1,%2)")
905 .arg (row + 1)
906 .arg (col + 1));
907 }
908
909 octave_value value_at (const QModelIndex& idx) const
910 {
911 int row;
912 int col;
913
914 if (! index_ok (idx, row, col))
915 return octave_value ();
916
918
919 return m(row, col);
920 }
921 };
922
923 base_ve_model *
924 variable_editor_model::create (const QString& expr, const octave_value& val)
925 {
926 // Choose specific model based on type of val.
927
928 if ((val.isnumeric () || val.islogical ()) && val.ndims () == 2)
929 return new numeric_model (expr, val);
930 else if (val.is_string () && (val.rows () == 1 || val.is_zero_by_zero ()))
931 return new string_model (expr, val);
932 else if (val.iscell ())
933 return new cell_model (expr, val);
934 else if (val.isstruct ())
935 {
936 if (val.numel () == 1)
937 return new scalar_struct_model (expr, val);
938 else if (val.ndims () == 2)
939 {
940 if (val.rows () == 1 || val.columns () == 1)
941 return new vector_struct_model (expr, val);
942 else
943 return new struct_model (expr, val);
944 }
945 }
946
947 return new display_only_model (expr, val);
948 }
949
951 const octave_value& val,
952 QObject *parent)
953 : QAbstractTableModel (parent), rep (create (expr, val))
954 {
956
959
962
965
966 if (is_editable ())
967 {
968 int new_rows = display_rows ();
969
970 if (new_rows > 0)
971 {
972 beginInsertRows (QModelIndex (), 0, new_rows-1);
973 endInsertRows ();
974 }
975
976 int new_cols = display_columns ();
977
978 if (new_cols > 0)
979 {
980 beginInsertColumns (QModelIndex (), 0, new_cols-1);
981 endInsertColumns ();
982 }
983 }
984 }
985
986 bool
987 variable_editor_model::setData (const QModelIndex& idx,
988 const QVariant& v_user_input, int role)
989 {
990 if (role != Qt::EditRole || ! v_user_input.canConvert (QMetaType::QString)
991 || ! idx.isValid ())
992 return false;
993
994 // Initially, set value to whatever the user entered.
995
996 QString user_input = v_user_input.toString ();
997
998 char qc = quote_char (idx);
999
1000 // FIXME: maybe we need a better way to ask whether empty input is
1001 // valid than to rely on whether there is a quote character (meaning
1002 // we are editing a character string)?
1003 if (user_input.isEmpty () && ! qc)
1004 return false;
1005
1006 set_update_pending (idx, user_input);
1007
1008 std::ostringstream os;
1009
1010 std::string nm = name ();
1011 os << nm;
1012
1013 QString tmp = subscript_expression (idx);
1014 os << tmp.toStdString () << "=";
1015
1016 if (qc)
1017 os << qc;
1018
1019 os << user_input.toStdString ();
1020
1021 if (qc)
1022 os << qc;
1023
1024 std::string expr = os.str ();
1025
1027 ([=] (interpreter& interp)
1028 {
1029 // INTERPRETER THREAD
1030
1031 try
1032 {
1033 int parse_status = 0;
1034 interp.eval_string (expr, true, parse_status);
1035
1036 octave_value val = retrieve_variable (interp, nm);
1037
1038 emit update_data_signal (val);
1039 }
1040 catch (const execution_exception&)
1041 {
1043
1044 evaluation_error (expr);
1045
1046 // This will cause the data in the cell to be reset
1047 // from the cached octave_value object.
1048
1049 emit dataChanged (idx, idx);
1050 }
1051 });
1052
1053 return true;
1054 }
1055
1056 bool
1058 {
1059 int row = idx.row ();
1060 int col = idx.column ();
1061
1062 if (row < data_rows () && col < data_columns ())
1063 return setData (idx, QVariant ("0"));
1064
1065 return false;
1066 }
1067
1068 Qt::ItemFlags
1069 variable_editor_model::flags (const QModelIndex& idx) const
1070 {
1071 if (! is_valid ())
1072 return Qt::NoItemFlags;
1073
1074 Qt::ItemFlags retval = QAbstractTableModel::flags (idx);
1075
1076 if (! requires_sub_editor (idx))
1077 retval |= Qt::ItemIsEditable;
1078
1079 return retval;
1080 }
1081
1082 bool
1083 variable_editor_model::insertRows (int row, int count, const QModelIndex&)
1084 {
1085 // FIXME: cells?
1086
1088 (QString ("%1 = [%1(1:%2,:); zeros(%3,columns(%1)); %1(%2+%3:end,:)]")
1089 .arg (QString::fromStdString (name ()))
1090 .arg (row)
1091 .arg (count));
1092
1093 return true;
1094 }
1095
1096 bool
1097 variable_editor_model::removeRows (int row, int count, const QModelIndex&)
1098 {
1099 if (row + count > data_rows ())
1100 {
1101 qDebug () << "Tried to remove too many rows "
1102 << data_rows () << " "
1103 << count << " (" << row << ")";
1104 return false;
1105 }
1106
1108 (QString ("%1(%2:%3,:) = []")
1109 .arg (QString::fromStdString (name ()))
1110 .arg (row)
1111 .arg (row + count));
1112
1113 return true;
1114 }
1115
1116 bool
1117 variable_editor_model::insertColumns (int col, int count, const QModelIndex&)
1118 {
1120 (QString ("%1 = [%1(:,1:%2); zeros(rows(%1),%3) %1(:,%2+%3:end)]")
1121 .arg (QString::fromStdString (name ()))
1122 .arg (col)
1123 .arg (count));
1124
1125 return true;
1126 }
1127
1128 bool
1129 variable_editor_model::removeColumns (int col, int count, const QModelIndex&)
1130 {
1131 if (col + count > data_columns ())
1132 {
1133 qDebug () << "Tried to remove too many cols "
1134 << data_columns () << " "
1135 << count << " (" << col << ")";
1136 return false;
1137 }
1138
1140 (QString ("%1(:,%2:%3) = []")
1141 .arg (QString::fromStdString (name ()))
1142 .arg (col)
1143 .arg (col + count));
1144
1145 return true;
1146 }
1147
1148 void
1150 {
1151 // INTERPRETER THREAD
1152
1153 std::string nm = name ();
1154
1155 try
1156 {
1157 octave_value val = retrieve_variable (interp, nm);
1158
1159 emit update_data_signal (val);
1160 }
1161 catch (const execution_exception&)
1162 {
1163 QString msg = (QString ("variable '%1' is invalid or undefined")
1164 .arg (QString::fromStdString (nm)));
1165
1166 emit data_error_signal (msg);
1167 }
1168 }
1169
1170 void
1172 {
1173 std::string expr = expr_arg.toStdString ();
1174
1176 ([=] (interpreter& interp)
1177 {
1178 // INTERPRETER THREAD
1179
1180 try
1181 {
1182 int parse_status = 0;
1183 interp.eval_string (expr, true, parse_status);
1184
1185 init_from_oct (interp);
1186 }
1187 catch (const execution_exception&)
1188 {
1189 evaluation_error (expr);
1190 }
1191 });
1192 }
1193
1194 // If the variable exists, load it into the data model. If it doesn't
1195 // exist, flag the data model as referring to a nonexistent variable.
1196 // This allows the variable to be opened before it is created.
1197
1198 // This function should only be called within other functions that
1199 // execute in the interpreter thread. It should also be called in a
1200 // try-catch block that catches execution exceptions.
1201
1204 const std::string& x)
1205 {
1206 // INTERPRETER THREAD
1207
1208 std::string name = x;
1209
1210 name = name.substr (0, name.find ("."));
1211
1212 if (name.back () == ')' || name.back () == '}')
1213 name = name.substr (0, name.find (name.back () == ')' ? "(" : "{"));
1214
1215 if (symbol_exist (name, "var") > 0)
1216 {
1217 int parse_status = 0;
1218
1219 octave_value result = interp.eval_string (x, true, parse_status);
1220
1221 if (result.is_cs_list ())
1222 error ("evaluation produced c-s list");
1223
1224 return result;
1225 }
1226
1227 return octave_value ();
1228 }
1229
1230 void
1231 variable_editor_model::evaluation_error (const std::string& expr) const
1232 {
1233 emit user_error_signal ("Evaluation failed",
1234 QString ("failed to evaluate expression: '%1' or result can't be edited")
1235 .arg (QString::fromStdString (expr)));
1236 }
1237
1238 void
1239 variable_editor_model::user_error (const QString& title, const QString& msg)
1240 {
1241 QMessageBox::critical (nullptr, title, msg);
1242 }
1243
1244 void
1246 {
1248 ([=] (interpreter& interp)
1249 {
1250 // INTERPRETER_THREAD
1251
1252 init_from_oct (interp);
1253 });
1254 }
1255
1256 void
1258 {
1259 if (val.is_undefined ())
1260 {
1261 QString msg = (QString ("variable '%1' is invalid or undefined")
1262 .arg (QString::fromStdString (name ())));
1263
1264 emit data_error_signal (msg);
1265
1266 return;
1267 }
1268
1269 // Add or remove rows and columns when the size changes.
1270
1271 int old_rows = display_rows ();
1272 int old_cols = display_columns ();
1273
1274 reset (val);
1275
1276 int new_rows = display_rows ();
1277 int new_cols = display_columns ();
1278
1279 if (new_rows != old_rows || new_cols != old_cols)
1280 change_display_size (old_rows, old_cols, new_rows, new_cols);
1281
1282 // Even if the size doesn't change, we still need to update here
1283 // because the data may have changed. But only if we have some data
1284 // to display.
1285
1286 if (new_rows > 0 && new_cols > 0)
1287 emit dataChanged (QAbstractTableModel::index (0, 0),
1288 QAbstractTableModel::index (new_rows-1, new_cols-1));
1289
1291 }
1292
1293 void
1295 int new_rows, int new_cols)
1296 {
1297 if (new_rows < old_rows)
1298 {
1299 beginRemoveRows (QModelIndex (), new_rows, old_rows-1);
1300 endRemoveRows ();
1301 }
1302 else if (new_rows > old_rows)
1303 {
1304 beginInsertRows (QModelIndex (), old_rows, new_rows-1);
1305 endInsertRows ();
1306 }
1307
1308 if (new_cols < old_cols)
1309 {
1310 beginRemoveColumns (QModelIndex (), new_cols, old_cols-1);
1311 endRemoveColumns ();
1312 }
1313 else if (new_cols > old_cols)
1314 {
1315 beginInsertColumns (QModelIndex (), old_cols, new_cols-1);
1316 endInsertColumns ();
1317 }
1318 }
1319
1320 void
1322 {
1323 int old_rows = display_rows ();
1324 int old_cols = display_columns ();
1325
1326 rep->maybe_resize_rows (rows);
1327
1328 int new_rows = display_rows ();
1329 int new_cols = display_columns ();
1330
1331 if (new_rows != old_rows)
1332 change_display_size (old_rows, old_cols, new_rows, new_cols);
1333 }
1334
1335 void
1337 {
1338 int old_rows = display_rows ();
1339 int old_cols = display_columns ();
1340
1341 rep->maybe_resize_columns (cols);
1342
1343 int new_rows = display_rows ();
1344 int new_cols = display_columns ();
1345
1346 if (new_cols != old_cols)
1347 change_display_size (old_rows, old_cols, new_rows, new_cols);
1348 }
1349
1350 void
1352 {
1353 invalidate ();
1354
1355 update_description (msg);
1356 }
1357
1358 void
1360 {
1361 base_ve_model *old_rep = rep;
1362
1363 rep = create (QString::fromStdString (name ()), val);
1364
1365 delete old_rep;
1366
1368
1370 }
1371
1372 void
1374 {
1375 beginResetModel ();
1376
1377 reset (octave_value ());
1378
1379 endResetModel ();
1380 }
1381
1382 void
1384 {
1385 emit description_changed (description.isEmpty ()
1386 ? make_description_text () : description);
1387 }
1388
1389 void
1391 {
1392 if (requires_sub_editor (idx))
1393 {
1394 QString name = QString::fromStdString(rep->name ());
1396 value_at (idx));
1397 }
1398 }
1399}
Definition: Cell.h:43
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
OCTAVE_API std::string str(char sep='x') const
Definition: dim-vector.cc:68
void set_precision(int prec)
Definition: pr-flt-fmt.h:238
float_format real_format(void) const
Definition: pr-flt-fmt.h:234
float_format imag_format(void) const
Definition: pr-flt-fmt.h:236
float_format & width(int w)
Definition: pr-flt-fmt.h:101
octave_value_list eval_string(const std::string &eval_str, bool silent, int &parse_status, int nargout)
QString update_pending_data(const QModelIndex &idx) const
float_display_format m_display_fmt
virtual bool requires_sub_editor(const QModelIndex &idx) const
octave_idx_type data_columns(void) const
QVariant data(const QModelIndex &idx, int role=Qt::DisplayRole) const
virtual void maybe_resize_rows(int)
virtual QString make_description_text(void) const
int rowCount(const QModelIndex &=QModelIndex()) const
virtual char quote_char(const QModelIndex &idx) const
void set_update_pending(const QModelIndex &idx, const QString &str)
bool index_ok(const QModelIndex &idx, int &row, int &col) const
octave_idx_type data_rows(void) const
virtual QVariant edit_display(const QModelIndex &idx, int role) const
std::string name(void) const
virtual octave_value value_at(const QModelIndex &idx) const
virtual QVariant header_data(int section, Qt::Orientation orientation, int role) const
bool update_pending(const QModelIndex &idx) const
int columnCount(const QModelIndex &=QModelIndex()) const
virtual QString subscript_expression(const QModelIndex &idx) const
QMap< QModelIndex, QString > m_update_pending
virtual void maybe_resize_columns(int)
base_ve_model(const QString &expr, const octave_value &val)
QString edit_display_sub(const octave_value &elt, int role) const
QVariant edit_display(const QModelIndex &idx, int role) const
~cell_model(void)=default
cell_model & operator=(const cell_model &)=delete
void maybe_resize_rows(int rows)
cell_model(const cell_model &)=delete
char quote_char(const QModelIndex &idx) const
cell_model(const QString &expr, const octave_value &val)
octave_value value_at(const QModelIndex &idx) const
void maybe_resize_columns(int cols)
QString subscript_expression(const QModelIndex &idx) const
bool requires_sub_editor(const QModelIndex &idx) const
display_only_model(const QString &expr, const octave_value &val)
display_only_model & operator=(const display_only_model &)=delete
~display_only_model(void)=default
QVariant edit_display(const QModelIndex &, int) const
QString make_description_text(void) const
display_only_model(const display_only_model &)=delete
QVariant edit_display(const QModelIndex &idx, int role) const
numeric_model(const QString &expr, const octave_value &val)
~numeric_model(void)=default
QString subscript_expression(const QModelIndex &idx) const
numeric_model(const numeric_model &)=delete
numeric_model & operator=(const numeric_model &)=delete
char quote_char(const QModelIndex &idx) const
QVariant header_data(int section, Qt::Orientation orientation, int role) const
scalar_struct_model(const scalar_struct_model &)=delete
QVariant edit_display(const QModelIndex &idx, int role) const
~scalar_struct_model(void)=default
QString subscript_expression(const QModelIndex &idx) const
octave_value value_at(const QModelIndex &idx) const
bool requires_sub_editor(const QModelIndex &idx) const
scalar_struct_model & operator=(const scalar_struct_model &)=delete
scalar_struct_model(const QString &expr, const octave_value &val)
string_model(const string_model &)=delete
QVariant edit_display(const QModelIndex &, int) const
~string_model(void)=default
char quote_char(const QModelIndex &) const
string_model(const QString &expr, const octave_value &val)
string_model & operator=(const string_model &)=delete
QVariant edit_display(const QModelIndex &idx, int) const
struct_model(const struct_model &)=delete
bool requires_sub_editor(const QModelIndex &idx) const
~struct_model(void)=default
void maybe_resize_columns(int cols)
char quote_char(const QModelIndex &idx) const
octave_value value_at(const QModelIndex &idx) const
struct_model(const QString &expr, const octave_value &val)
struct_model & operator=(const struct_model &)=delete
QString subscript_expression(const QModelIndex &idx) const
Qt::ItemFlags flags(const QModelIndex &idx) const
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex())
void description_changed(const QString &description)
void data_error(const QString &msg)
void init_from_oct(interpreter &interp)
octave_value value_at(const QModelIndex &idx) const
void update_description(const QString &description=QString())
void data_error_signal(const QString &name) const
octave_value retrieve_variable(interpreter &, const std::string &name)
void set_update_pending(const QModelIndex &idx, const QString &str)
variable_editor_model(const QString &expr, const octave_value &val, QObject *parent=nullptr)
bool requires_sub_editor(const QModelIndex &idx) const
void user_error(const QString &title, const QString &msg)
void interpreter_event(const fcn_callback &fcn)
bool removeColumns(int column, int count, const QModelIndex &parent=QModelIndex())
bool insertColumns(int column, int count, const QModelIndex &parent=QModelIndex())
void update_data_signal(const octave_value &val)
void user_error_signal(const QString &title, const QString &msg) const
static base_ve_model * create(const QString &expr, const octave_value &val)
void reset(const octave_value &val)
void change_display_size(int old_rows, int old_cols, int new_rows, int new_cols)
void double_click(const QModelIndex &idx)
void edit_variable_signal(const QString &name, const octave_value &val)
QString subscript_expression(const QModelIndex &idx) const
void eval_expr_event(const QString &expr)
void evaluation_error(const std::string &expr) const
bool clear_content(const QModelIndex &idx)
QString make_description_text(void) const
void update_data(const octave_value &val)
char quote_char(const QModelIndex &idx) const
octave_idx_type data_rows(void) const
bool setData(const QModelIndex &idx, const QVariant &v, int role=Qt::EditRole)
octave_idx_type data_columns(void) const
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
QVariant header_data(int section, Qt::Orientation orientation, int role) const
vector_struct_model(const QString &expr, const octave_value &val)
octave_value value_at(const QModelIndex &idx) const
vector_struct_model & operator=(const vector_struct_model &)=delete
QString subscript_expression(const QModelIndex &idx) const
bool requires_sub_editor(const QModelIndex &idx) const
char quote_char(const QModelIndex &idx) const
QVariant edit_display(const QModelIndex &idx, int role) const
vector_struct_model(const vector_struct_model &)=delete
~vector_struct_model(void)=default
const Cell & contents(const_iterator p) const
Definition: oct-map.h:331
string_vector fieldnames(void) const
Definition: oct-map.h:353
const octave_value & contents(const_iterator p) const
Definition: oct-map.h:205
string_vector fieldnames(void) const
Definition: oct-map.h:227
bool iscell(void) const
Definition: ov.h:649
void print_with_name(std::ostream &os, const std::string &name) const
Definition: ov.h:1434
OCTINTERP_API octave_scalar_map scalar_map_value(void) const
octave_idx_type rows(void) const
Definition: ov.h:590
bool isnumeric(void) const
Definition: ov.h:795
octave_idx_type numel(void) const
Definition: ov.h:604
bool is_dq_string(void) const
Definition: ov.h:688
bool is_cs_list(void) const
Definition: ov.h:715
bool is_string(void) const
Definition: ov.h:682
std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
Definition: ov.h:1441
bool is_defined(void) const
Definition: ov.h:637
Cell cell_value(void) const
std::string class_name(void) const
Definition: ov.h:1451
octave_idx_type columns(void) const
Definition: ov.h:592
int ndims(void) const
Definition: ov.h:596
bool isstruct(void) const
Definition: ov.h:694
bool is_zero_by_zero(void) const
Definition: ov.h:601
octave_idx_type nfields(void) const
Definition: ov.h:614
bool isempty(void) const
Definition: ov.h:646
bool is_single_type(void) const
Definition: ov.h:743
OCTINTERP_API octave_map map_value(void) const
bool is_sq_string(void) const
Definition: ov.h:685
bool is_undefined(void) const
Definition: ov.h:640
bool iscomplex(void) const
Definition: ov.h:786
OCTINTERP_API float_display_format get_edit_display_format(void) const
bool islogical(void) const
Definition: ov.h:780
dim_vector dims(void) const
Definition: ov.h:586
void error(const char *fmt,...)
Definition: error.cc:980
F77_RET_T const F77_DBLE * x
QString fromStdString(const std::string &s)
std::string toStdString(const QString &s)
static float_display_format get_edit_display_format(const octave_value &val)
static bool cell_is_editable(const octave_value &val)
static char get_quote_char(const octave_value &val)
static bool do_requires_sub_editor_sub(const octave_value &elt)
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
static int symbol_exist(interpreter &interp, const std::string &name, const std::string &type="any")
Definition: variables.cc:162