GNU Octave  6.2.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-2021 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 
39 #include "qt-interpreter-events.h"
40 #include "variable-editor-model.h"
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 
51 namespace 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
106  base_ve_model::name (void) const
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
164  base_ve_model::edit_display_sub (const octave_value& elt, int role) const
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")
218  .arg (QString::fromStdString (m_name)));
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 += ("["
299  + QString::fromStdString (dv.str ())
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 
419  class cell_model : public base_ve_model
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 
439  cell_model& operator = (const cell_model&) = delete;
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 
957  connect (this, SIGNAL (user_error_signal (const QString&, const QString&)),
958  this, SLOT (user_error (const QString&, const QString&)));
959 
960  connect (this, SIGNAL (update_data_signal (const octave_value&)),
961  this, SLOT (update_data (const octave_value&)));
962 
963  connect (this, SIGNAL (data_error_signal (const QString&)),
964  this, SLOT (data_error (const QString&)));
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 defined (QVARIANT_CANCONVERT_ACCEPTS_QMETATYPE_TYPE)
991  QMetaType::Type string_type = QMetaType::QString;
992 #else
993  QVariant::Type string_type = QVariant::String;
994 #endif
995  if (role != Qt::EditRole || ! v_user_input.canConvert (string_type)
996  || ! idx.isValid ())
997  return false;
998 
999  // Initially, set value to whatever the user entered.
1000 
1001  QString user_input = v_user_input.toString ();
1002 
1003  char qc = quote_char (idx);
1004 
1005  // FIXME: maybe we need a better way to ask whether empty input is
1006  // valid than to rely on whether there is a quote character (meaning
1007  // we are editing a character string)?
1008  if (user_input.isEmpty () && ! qc)
1009  return false;
1010 
1011  set_update_pending (idx, user_input);
1012 
1013  std::ostringstream os;
1014 
1015  std::string nm = name ();
1016  os << nm;
1017 
1018  QString tmp = subscript_expression (idx);
1019  os << tmp.toStdString () << "=";
1020 
1021  if (qc)
1022  os << qc;
1023 
1024  os << user_input.toStdString ();
1025 
1026  if (qc)
1027  os << qc;
1028 
1029  std::string expr = os.str ();
1030 
1031  emit interpreter_event
1032  ([this, nm, expr, idx] (interpreter& interp)
1033  {
1034  // INTERPRETER THREAD
1035 
1036  try
1037  {
1038  int parse_status = 0;
1039  interp.eval_string (expr, true, parse_status);
1040 
1041  octave_value val = retrieve_variable (interp, nm);
1042 
1043  emit update_data_signal (val);
1044  }
1045  catch (const execution_exception&)
1046  {
1048 
1049  evaluation_error (expr);
1050 
1051  // This will cause the data in the cell to be reset
1052  // from the cached octave_value object.
1053 
1054  emit dataChanged (idx, idx);
1055  }
1056  });
1057 
1058  return true;
1059  }
1060 
1061  bool
1062  variable_editor_model::clear_content (const QModelIndex& idx)
1063  {
1064  int row = idx.row ();
1065  int col = idx.column ();
1066 
1067  if (row < data_rows () && col < data_columns ())
1068  return setData (idx, QVariant ("0"));
1069 
1070  return false;
1071  }
1072 
1073  Qt::ItemFlags
1074  variable_editor_model::flags (const QModelIndex& idx) const
1075  {
1076  if (! is_valid ())
1077  return Qt::NoItemFlags;
1078 
1079  Qt::ItemFlags retval = QAbstractTableModel::flags (idx);
1080 
1081  if (! requires_sub_editor (idx))
1082  retval |= Qt::ItemIsEditable;
1083 
1084  return retval;
1085  }
1086 
1087  bool
1088  variable_editor_model::insertRows (int row, int count, const QModelIndex&)
1089  {
1090  // FIXME: cells?
1091 
1093  (QString ("%1 = [%1(1:%2,:); zeros(%3,columns(%1)); %1(%2+%3:end,:)]")
1094  .arg (QString::fromStdString (name ()))
1095  .arg (row)
1096  .arg (count));
1097 
1098  return true;
1099  }
1100 
1101  bool
1102  variable_editor_model::removeRows (int row, int count, const QModelIndex&)
1103  {
1104  if (row + count > data_rows ())
1105  {
1106  qDebug () << "Tried to remove too many rows "
1107  << data_rows () << " "
1108  << count << " (" << row << ")";
1109  return false;
1110  }
1111 
1113  (QString ("%1(%2:%3,:) = []")
1114  .arg (QString::fromStdString (name ()))
1115  .arg (row)
1116  .arg (row + count));
1117 
1118  return true;
1119  }
1120 
1121  bool
1122  variable_editor_model::insertColumns (int col, int count, const QModelIndex&)
1123  {
1125  (QString ("%1 = [%1(:,1:%2); zeros(rows(%1),%3) %1(:,%2+%3:end)]")
1126  .arg (QString::fromStdString (name ()))
1127  .arg (col)
1128  .arg (count));
1129 
1130  return true;
1131  }
1132 
1133  bool
1134  variable_editor_model::removeColumns (int col, int count, const QModelIndex&)
1135  {
1136  if (col + count > data_columns ())
1137  {
1138  qDebug () << "Tried to remove too many cols "
1139  << data_columns () << " "
1140  << count << " (" << col << ")";
1141  return false;
1142  }
1143 
1145  (QString ("%1(:,%2:%3) = []")
1146  .arg (QString::fromStdString (name ()))
1147  .arg (col)
1148  .arg (col + count));
1149 
1150  return true;
1151  }
1152 
1153  void
1155  {
1156  // INTERPRETER THREAD
1157 
1158  std::string nm = name ();
1159 
1160  try
1161  {
1162  octave_value val = retrieve_variable (interp, nm);
1163 
1164  emit update_data_signal (val);
1165  }
1166  catch (const execution_exception&)
1167  {
1168  QString msg = (QString ("variable '%1' is invalid or undefined")
1169  .arg (QString::fromStdString (nm)));
1170 
1171  emit data_error_signal (msg);
1172  }
1173  }
1174 
1175  void
1176  variable_editor_model::eval_expr_event (const QString& expr_arg)
1177  {
1178  std::string expr = expr_arg.toStdString ();
1179 
1180  emit interpreter_event
1181  ([this, expr] (interpreter& interp)
1182  {
1183  // INTERPRETER THREAD
1184 
1185  try
1186  {
1187  int parse_status = 0;
1188  interp.eval_string (expr, true, parse_status);
1189 
1190  init_from_oct (interp);
1191  }
1192  catch (const execution_exception&)
1193  {
1194  evaluation_error (expr);
1195  }
1196  });
1197  }
1198 
1199  // If the variable exists, load it into the data model. If it doesn't
1200  // exist, flag the data model as referring to a nonexistent variable.
1201  // This allows the variable to be opened before it is created.
1202 
1203  // This function should only be called within other functions that
1204  // execute in the interpreter thread. It should also be called in a
1205  // try-catch block that catches execution exceptions.
1206 
1207  octave_value
1209  const std::string& x)
1210  {
1211  // INTERPRETER THREAD
1212 
1213  std::string name = x;
1214 
1215  name = name.substr (0, name.find ("."));
1216 
1217  if (name.back () == ')' || name.back () == '}')
1218  name = name.substr (0, name.find (name.back () == ')' ? "(" : "{"));
1219 
1220  if (symbol_exist (name, "var") > 0)
1221  {
1222  int parse_status = 0;
1223 
1224  octave_value result = interp.eval_string (x, true, parse_status);
1225 
1226  if (result.is_cs_list ())
1227  error ("evaluation produced c-s list");
1228 
1229  return result;
1230  }
1231 
1232  return octave_value ();
1233  }
1234 
1235  void
1236  variable_editor_model::evaluation_error (const std::string& expr) const
1237  {
1238  emit user_error_signal ("Evaluation failed",
1239  QString ("failed to evaluate expression: '%1' or result can't be edited")
1240  .arg (QString::fromStdString (expr)));
1241  }
1242 
1243  void
1244  variable_editor_model::user_error (const QString& title, const QString& msg)
1245  {
1246  QMessageBox::critical (nullptr, title, msg);
1247  }
1248 
1249  void
1251  {
1252  emit interpreter_event
1253  ([this] (interpreter& interp)
1254  {
1255  // INTERPRETER_THREAD
1256 
1257  init_from_oct (interp);
1258  });
1259  }
1260 
1261  void
1263  {
1264  if (val.is_undefined ())
1265  {
1266  QString msg = (QString ("variable '%1' is invalid or undefined")
1267  .arg (QString::fromStdString (name ())));
1268 
1269  emit data_error_signal (msg);
1270 
1271  return;
1272  }
1273 
1274  // Add or remove rows and columns when the size changes.
1275 
1276  int old_rows = display_rows ();
1277  int old_cols = display_columns ();
1278 
1279  reset (val);
1280 
1281  int new_rows = display_rows ();
1282  int new_cols = display_columns ();
1283 
1284  if (new_rows != old_rows || new_cols != old_cols)
1285  change_display_size (old_rows, old_cols, new_rows, new_cols);
1286 
1287  // Even if the size doesn't change, we still need to update here
1288  // because the data may have changed. But only if we have some data
1289  // to display.
1290 
1291  if (new_rows > 0 && new_cols > 0)
1292  emit dataChanged (QAbstractTableModel::index (0, 0),
1293  QAbstractTableModel::index (new_rows-1, new_cols-1));
1294 
1296  }
1297 
1298  void
1299  variable_editor_model::change_display_size (int old_rows, int old_cols,
1300  int new_rows, int new_cols)
1301  {
1302  if (new_rows < old_rows)
1303  {
1304  beginRemoveRows (QModelIndex (), new_rows, old_rows-1);
1305  endRemoveRows ();
1306  }
1307  else if (new_rows > old_rows)
1308  {
1309  beginInsertRows (QModelIndex (), old_rows, new_rows-1);
1310  endInsertRows ();
1311  }
1312 
1313  if (new_cols < old_cols)
1314  {
1315  beginRemoveColumns (QModelIndex (), new_cols, old_cols-1);
1316  endRemoveColumns ();
1317  }
1318  else if (new_cols > old_cols)
1319  {
1320  beginInsertColumns (QModelIndex (), old_cols, new_cols-1);
1321  endInsertColumns ();
1322  }
1323  }
1324 
1325  void
1327  {
1328  int old_rows = display_rows ();
1329  int old_cols = display_columns ();
1330 
1331  rep->maybe_resize_rows (rows);
1332 
1333  int new_rows = display_rows ();
1334  int new_cols = display_columns ();
1335 
1336  if (new_rows != old_rows)
1337  change_display_size (old_rows, old_cols, new_rows, new_cols);
1338  }
1339 
1340  void
1342  {
1343  int old_rows = display_rows ();
1344  int old_cols = display_columns ();
1345 
1346  rep->maybe_resize_columns (cols);
1347 
1348  int new_rows = display_rows ();
1349  int new_cols = display_columns ();
1350 
1351  if (new_cols != old_cols)
1352  change_display_size (old_rows, old_cols, new_rows, new_cols);
1353  }
1354 
1355  void
1357  {
1358  invalidate ();
1359 
1360  update_description (msg);
1361  }
1362 
1363  void
1365  {
1366  base_ve_model *old_rep = rep;
1367 
1368  rep = create (QString::fromStdString (name ()), val);
1369 
1370  delete old_rep;
1371 
1372  update_description ();
1373 
1374  emit set_editable_signal (is_editable ());
1375  }
1376 
1377  void
1379  {
1380  beginResetModel ();
1381 
1382  reset (octave_value ());
1383 
1384  endResetModel ();
1385  }
1386 
1387  void
1388  variable_editor_model::update_description (const QString& description)
1389  {
1390  emit description_changed (description.isEmpty ()
1391  ? make_description_text () : description);
1392  }
1393 
1394  void
1395  variable_editor_model::double_click (const QModelIndex& idx)
1396  {
1397  if (requires_sub_editor (idx))
1398  {
1399  QString name = QString::fromStdString(rep->name ());
1401  value_at (idx));
1402  }
1403  }
1404 }
Definition: Cell.h:43
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
std::string str(char sep='x') const
Definition: dim-vector.cc:85
void set_precision(int prec)
Definition: pr-flt-fmt.h:236
float_format real_format(void) const
Definition: pr-flt-fmt.h:232
float_format imag_format(void) const
Definition: pr-flt-fmt.h:234
float_format & width(int w)
Definition: pr-flt-fmt.h:100
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
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)
cell_model & operator=(const cell_model &)=delete
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
octave_value_list eval_string(const std::string &eval_str, bool silent, int &parse_status, int nargout)
numeric_model & operator=(const numeric_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
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
scalar_struct_model & operator=(const scalar_struct_model &)=delete
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(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 & operator=(const string_model &)=delete
string_model(const QString &expr, const octave_value &val)
QVariant edit_display(const QModelIndex &idx, int) const
struct_model & operator=(const struct_model &)=delete
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)
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
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
vector_struct_model & operator=(const vector_struct_model &)=delete
bool iscell(void) const
Definition: ov.h:560
void print_with_name(std::ostream &os, const std::string &name) const
Definition: ov.h:1239
octave_idx_type rows(void) const
Definition: ov.h:504
bool isnumeric(void) const
Definition: ov.h:703
octave_idx_type numel(void) const
Definition: ov.h:518
bool is_dq_string(void) const
Definition: ov.h:599
bool is_cs_list(void) const
Definition: ov.h:626
bool is_string(void) const
Definition: ov.h:593
std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
Definition: ov.h:1246
bool is_defined(void) const
Definition: ov.h:551
Cell cell_value(void) const
std::string class_name(void) const
Definition: ov.h:1256
octave_idx_type columns(void) const
Definition: ov.h:506
int ndims(void) const
Definition: ov.h:510
bool isstruct(void) const
Definition: ov.h:605
bool is_zero_by_zero(void) const
Definition: ov.h:515
octave_idx_type nfields(void) const
Definition: ov.h:528
octave_scalar_map scalar_map_value(void) const
bool isempty(void) const
Definition: ov.h:557
bool is_single_type(void) const
Definition: ov.h:651
octave_map map_value(void) const
bool is_sq_string(void) const
Definition: ov.h:596
bool is_undefined(void) const
Definition: ov.h:554
float_display_format get_edit_display_format(void) const
bool iscomplex(void) const
Definition: ov.h:694
bool islogical(void) const
Definition: ov.h:688
dim_vector dims(void) const
Definition: ov.h:500
void error(const char *fmt,...)
Definition: error.cc:968
F77_RET_T const F77_DBLE * x
T octave_idx_type m
Definition: mx-inlines.cc:773
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()) ? '\'' :'"'))
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
static int symbol_exist(octave::interpreter &interp, const std::string &name, const std::string &type="any")
Definition: variables.cc:200