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