Mercurial > octave
view libgui/src/variable-editor-model.cc @ 31646:c6d54dd31a7e stable
maint: Use macros to begin/end C++ namespaces.
* BaseControl.cc, BaseControl.h, ButtonControl.cc, ButtonControl.h,
ButtonGroup.cc, ButtonGroup.h, Canvas.cc, Canvas.h,
CheckBoxControl.cc, CheckBoxControl.h, Container.cc, Container.h,
ContextMenu.cc, ContextMenu.h, EditControl.cc, EditControl.h,
Figure.cc, Figure.h, FigureWindow.cc, FigureWindow.h, GLCanvas.cc,
GLCanvas.h, GenericEventNotify.h, KeyMap.cc, KeyMap.h,
ListBoxControl.cc, ListBoxControl.h, Logger.cc, Logger.h, Menu.cc,
Menu.h, MenuContainer.h, Object.cc, Object.h, ObjectProxy.cc,
ObjectProxy.h, Panel.cc, Panel.h, PopupMenuControl.cc,
PopupMenuControl.h, PushButtonControl.cc, PushButtonControl.h,
PushTool.cc, PushTool.h, QtHandlesUtils.cc, QtHandlesUtils.h,
RadioButtonControl.cc, RadioButtonControl.h, SliderControl.cc,
SliderControl.h, Table.cc, Table.h, TextControl.cc, TextControl.h,
TextEdit.cc, TextEdit.h, ToggleButtonControl.cc,
ToggleButtonControl.h, ToggleTool.cc, ToggleTool.h, ToolBar.cc,
ToolBar.h, ToolBarButton.cc, ToolBarButton.h, annotation-dialog.cc,
annotation-dialog.h, gl-select.cc, gl-select.h, qopengl-functions.h,
qt-graphics-toolkit.cc, qt-graphics-toolkit.h, QTerminal.h,
color-picker.cc, color-picker.h, command-widget.cc, command-widget.h,
community-news.cc, community-news.h, dialog.cc, dialog.h,
documentation-bookmarks.cc, documentation-bookmarks.h,
documentation-dock-widget.cc, documentation-dock-widget.h,
documentation.cc, documentation.h, dw-main-window.cc,
dw-main-window.h, external-editor-interface.cc,
external-editor-interface.h, files-dock-widget.cc,
files-dock-widget.h, find-files-dialog.cc, find-files-dialog.h,
find-files-model.cc, find-files-model.h, graphics-init.cc,
graphics-init.h, gui-settings.cc, gui-settings.h, gui-utils.cc,
gui-utils.h, history-dock-widget.cc, history-dock-widget.h,
interpreter-qobject.cc, interpreter-qobject.h, led-indicator.cc,
led-indicator.h, file-editor-interface.h, file-editor-tab.cc,
file-editor-tab.h, file-editor.cc, file-editor.h, find-dialog.cc,
find-dialog.h, marker.cc, marker.h, octave-qscintilla.cc,
octave-qscintilla.h, octave-txt-lexer.cc, octave-txt-lexer.h,
main-window.cc, main-window.h, news-reader.cc, news-reader.h,
octave-dock-widget.cc, octave-dock-widget.h, octave-qobject.cc,
octave-qobject.h, qt-application.cc, qt-application.h,
qt-interpreter-events.cc, qt-interpreter-events.h, qt-utils.h,
release-notes.cc, release-notes.h, resource-manager.cc,
resource-manager.h, set-path-dialog.cc, set-path-dialog.h,
set-path-model.cc, set-path-model.h, settings-dialog.cc,
settings-dialog.h, shortcut-manager.cc, shortcut-manager.h,
tab-bar.cc, tab-bar.h, terminal-dock-widget.cc,
terminal-dock-widget.h, variable-editor-model.cc,
variable-editor-model.h, variable-editor.cc, variable-editor.h,
welcome-wizard.cc, welcome-wizard.h, workspace-model.cc,
workspace-model.h, workspace-view.cc, workspace-view.h:
Use new macros to begin/end C++ namespaces.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 06 Dec 2022 14:37:51 -0500 |
parents | 796f54d4ddbf |
children | 29d734430e5f |
line wrap: on
line source
//////////////////////////////////////////////////////////////////////// // // Copyright (C) 2013-2022 The Octave Project Developers // // See the file COPYRIGHT.md in the top-level directory of this // distribution or <https://octave.org/copyright/>. // // This file is part of Octave. // // Octave is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Octave is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Octave; see the file COPYING. If not, see // <https://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////// #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <sstream> #include <QDebug> #include <QLabel> #include <QMap> #include <QMessageBox> #include <QString> #include <QTableView> #include "qt-interpreter-events.h" #include "variable-editor-model.h" #include "Cell.h" #include "interpreter.h" #include "oct-map.h" #include "ov.h" #include "parse.h" #include "pr-flt-fmt.h" #include "utils.h" #include "variables.h" OCTAVE_BEGIN_NAMESPACE(octave) static bool cell_is_editable (const octave_value& val) { if ((val.isnumeric () || val.islogical ()) && val.numel () == 1) return true; if (val.is_string () && (val.rows () == 1 || val.is_zero_by_zero ())) return true; return false; } static char get_quote_char (const octave_value& val) { if (val.is_sq_string ()) return '\''; if (val.is_dq_string ()) return '"'; return 0; } static float_display_format get_edit_display_format (const octave_value& val) { // FIXME: make this limit configurable. return (val.numel () > 250000 ? float_display_format () : val.get_edit_display_format ()); } static bool do_requires_sub_editor_sub (const octave_value& elt) { return (! ((elt.numel () == 1 && (elt.isnumeric () || elt.islogical ())) || (elt.is_string () && (elt.rows () == 1 || elt.isempty ())))); } base_ve_model::base_ve_model (const QString& expr, const octave_value& val) : m_name (expr.toStdString ()), m_value (val), m_data_rows (m_value.rows ()), m_data_cols (m_value.columns ()), m_display_rows (m_data_rows), m_display_cols (m_data_cols), m_update_pending (), m_valid (m_value.is_defined ()), m_display_fmt (get_edit_display_format (m_value)) { } std::string base_ve_model::name (void) const { return m_name; } bool base_ve_model::index_ok (const QModelIndex& idx, int& row, int& col) const { row = 0; col = 0; if (! idx.isValid ()) return false; row = idx.row (); col = idx.column (); return (row < data_rows () && col < data_columns ()); } int base_ve_model::column_width (void) const { int width = 0; float_format r_fmt = m_display_fmt.real_format (); float_format i_fmt = m_display_fmt.imag_format (); int rw = r_fmt.width (); int iw = i_fmt.width (); if (rw > 0) { if (m_value.iscomplex ()) { if (iw > 0) width = rw + iw + 5; } else width = rw + 2; } return width; } int base_ve_model::rowCount (const QModelIndex&) const { return m_valid ? m_display_rows : 1; } int base_ve_model::columnCount (const QModelIndex&) const { return m_valid ? m_display_cols : 1; } QString base_ve_model::edit_display_sub (const octave_value& elt, int role) const { std::string str; if (cell_is_editable (elt)) { float_display_format fmt; if (role == Qt::DisplayRole) fmt = get_edit_display_format (elt); else fmt.set_precision (elt.is_single_type () ? 8 : 16); str = elt.edit_display (fmt, 0, 0); } else { dim_vector dv = elt.dims (); str = "[" + dv.str () + " " + elt.class_name () + "]"; } return QString::fromStdString (str); } QVariant base_ve_model::edit_display (const QModelIndex& idx, int role) const { int row; int col; if (! index_ok (idx, row, col)) return QVariant (); float_display_format fmt; if (role == Qt::DisplayRole) fmt = m_display_fmt; else fmt.set_precision (m_value.is_single_type () ? 8 : 16); std::string str = m_value.edit_display (fmt, row, col); return QString::fromStdString (str); } QVariant base_ve_model::data (const QModelIndex& idx, int role) const { if (idx.isValid () && role == Qt::DisplayRole && update_pending (idx)) return QVariant (update_pending_data (idx)); if (! m_valid) { if (role == Qt::DisplayRole) return QVariant (QString ("Variable %1 not found or value can't be edited") .arg (QString::fromStdString (m_name))); return QVariant (QString ("x")); } switch (role) { case Qt::DisplayRole: case Qt::EditRole: return edit_display (idx, role); } // Invalid. return QVariant (); } bool base_ve_model::requires_sub_editor (const QModelIndex&) const { return false; } void base_ve_model::set_update_pending (const QModelIndex& idx, const QString& str) { m_update_pending[idx] = str; } bool base_ve_model::update_pending (const QModelIndex& idx) const { return m_update_pending.contains (idx); } QString base_ve_model::update_pending_data (const QModelIndex& idx) const { return m_update_pending[idx]; } void base_ve_model::clear_update_pending (void) { return m_update_pending.clear (); } char base_ve_model::quote_char (const QModelIndex&) const { return 0; } QVariant base_ve_model::header_data (int section, Qt::Orientation, int role) const { if (role != Qt::DisplayRole) return QVariant (); return QString::number (section+1); } QString base_ve_model::subscript_expression (const QModelIndex&) const { return ""; } QString base_ve_model::make_description_text (void) const { QString lbl_txt = QString::fromStdString (m_name); if (m_value.is_defined ()) { if (! lbl_txt.isEmpty ()) lbl_txt += " "; dim_vector dv = m_value.dims (); lbl_txt += ("[" + QString::fromStdString (dv.str ()) + " " + QString::fromStdString (m_value.class_name ()) + "]"); } else lbl_txt += " [undefined]"; return lbl_txt; } // Private slots. octave_value base_ve_model::value_at (const QModelIndex&) const { return octave_value (); } class numeric_model : public base_ve_model { public: numeric_model (const QString& expr, const octave_value& val) : base_ve_model (expr, val) { // FIXME: should fill the window and expand on scrolling or // resizing. maybe_resize_rows (m_data_rows + 16); maybe_resize_columns (m_data_cols + 16); } ~numeric_model (void) = default; // No copying! numeric_model (const numeric_model&) = delete; numeric_model& operator = (const numeric_model&) = delete; void maybe_resize_rows (int rows) { if (rows > m_display_rows) m_display_rows = rows; } void maybe_resize_columns (int cols) { if (cols > m_display_cols) m_display_cols = cols; } QVariant edit_display (const QModelIndex& idx, int role) const { int row; int col; if (! index_ok (idx, row, col)) return QVariant (); float_display_format fmt; if (role == Qt::DisplayRole) fmt = m_display_fmt; else fmt.set_precision (m_value.is_single_type () ? 8 : 16); std::string str = m_value.edit_display (fmt, row, col); return QString::fromStdString (str); } QString subscript_expression (const QModelIndex& idx) const { if (! idx.isValid ()) return ""; return (QString ("(%1,%2)") .arg (idx.row () + 1) .arg (idx.column () + 1)); } }; class string_model : public base_ve_model { public: string_model (const QString& expr, const octave_value& val) : base_ve_model (expr, val) { m_data_rows = 1; m_data_cols = 1; m_display_rows = 1; m_display_cols = 1; } ~string_model (void) = default; // No copying! string_model (const string_model&) = delete; string_model& operator = (const string_model&) = delete; QVariant edit_display (const QModelIndex&, int) const { // There isn't really a format for strings... std::string str = m_value.edit_display (float_display_format (), 0, 0); return QString::fromStdString (str); } char quote_char (const QModelIndex&) const { return get_quote_char (m_value); } }; class cell_model : public base_ve_model { public: cell_model (const QString& expr, const octave_value& val) : base_ve_model (expr, val) { // FIXME: should fill the window and expand on scrolling or // resizing. maybe_resize_rows (m_data_rows + 16); maybe_resize_columns (m_data_cols + 16); } ~cell_model (void) = default; // No copying! cell_model (const cell_model&) = delete; cell_model& operator = (const cell_model&) = delete; void maybe_resize_rows (int rows) { if (rows > m_display_rows) m_display_rows = rows; } void maybe_resize_columns (int cols) { if (cols > m_display_cols) m_display_cols = cols; } QVariant edit_display (const QModelIndex& idx, int role) const { int row; int col; if (! index_ok (idx, row, col)) return QVariant (); Cell cval = m_value.cell_value (); return edit_display_sub (cval(row, col), role); } bool requires_sub_editor (const QModelIndex& idx) const { int row; int col; if (! index_ok (idx, row, col)) return false; Cell cval = m_value.cell_value (); return do_requires_sub_editor_sub (cval(row, col)); } char quote_char (const QModelIndex& idx) const { octave_value ov = value_at (idx); if (ov.is_string ()) return get_quote_char (ov); return 0; } QString subscript_expression (const QModelIndex& idx) const { if (! idx.isValid ()) return ""; return (QString ("{%1,%2}") .arg (idx.row () + 1) .arg (idx.column () + 1)); } octave_value value_at (const QModelIndex& idx) const { int row; int col; if (! index_ok (idx, row, col)) return octave_value (); Cell cval = m_value.cell_value (); return cval(row, col); } }; // Scalar struct. Rows are fields, single column for values. class scalar_struct_model : public base_ve_model { public: scalar_struct_model (const QString& expr, const octave_value& val) : base_ve_model (expr, val) { // No extra cells. We currently don't allow new fields or // additional values to be inserted. If we allow additional values, // then the object becomes a vector structure and the display flips // (see the vector struct model below). Do we want that? m_data_rows = val.nfields (); m_data_cols = 1; m_display_rows = m_data_rows; m_display_cols = 1; } ~scalar_struct_model (void) = default; // No copying! scalar_struct_model (const scalar_struct_model&) = delete; scalar_struct_model& operator = (const scalar_struct_model&) = delete; QVariant edit_display (const QModelIndex& idx, int role) const { int row; int col; if (! index_ok (idx, row, col)) return QVariant (); octave_scalar_map m = m_value.scalar_map_value (); return edit_display_sub (m.contents (row), role); } bool requires_sub_editor (const QModelIndex& idx) const { int row; int col; if (! index_ok (idx, row, col)) return false; octave_scalar_map m = m_value.scalar_map_value (); return do_requires_sub_editor_sub (m.contents (row)); } char quote_char (const QModelIndex& idx) const { octave_value ov = value_at (idx); if (ov.is_string ()) return get_quote_char (ov); return 0; } QVariant header_data (int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant (); switch (orientation) { case Qt::Horizontal: if (section < data_columns ()) return QString ("Values"); else break; case Qt::Vertical: if (section < data_rows ()) { octave_scalar_map m = m_value.scalar_map_value (); string_vector fields = m.fieldnames (); return QString::fromStdString (fields(section)); } else break; default: break; } return QVariant (); } QString subscript_expression (const QModelIndex& idx) const { // Display size and data size match, so all valid indices should // also be valid indices for the existing struct. int row; int col; if (! index_ok (idx, row, col)) return ""; octave_scalar_map m = m_value.scalar_map_value (); string_vector fields = m.fieldnames (); return QString (".%1").arg (QString::fromStdString (fields(row))); } octave_value value_at (const QModelIndex& idx) const { int row; int col; if (! index_ok (idx, row, col)) return octave_value (); octave_scalar_map m = m_value.scalar_map_value (); return m.contents (row); } }; class display_only_model : public base_ve_model { public: display_only_model (const QString& expr, const octave_value& val) : base_ve_model (expr, val) { m_data_rows = 1; m_data_cols = 1; m_display_rows = m_data_rows; m_display_cols = m_data_cols; } ~display_only_model (void) = default; // No copying! display_only_model (const display_only_model&) = delete; display_only_model& operator = (const display_only_model&) = delete; bool is_editable (void) const { return false; } QVariant edit_display (const QModelIndex&, int) const { if (m_value.is_undefined ()) return QVariant (); std::ostringstream buf; octave_value tval = m_value; tval.print_with_name (buf, m_name); return QString::fromStdString (buf.str ()); } QString make_description_text (void) const { return (QString ("unable to edit %1") .arg (base_ve_model::make_description_text ())); } }; // Vector struct. Columns are fields, rows are values. class vector_struct_model : public base_ve_model { public: vector_struct_model (const QString& expr, const octave_value& val) : base_ve_model (expr, val) { // FIXME: should fill the window vertically and expand on scrolling // or resizing. No extra cells horizontally. New fields must be // added specially. m_data_rows = val.numel (); m_data_cols = val.nfields (); maybe_resize_rows (m_data_rows + 16); m_display_cols = m_data_cols; } ~vector_struct_model (void) = default; // No copying! vector_struct_model (const vector_struct_model&) = delete; vector_struct_model& operator = (const vector_struct_model&) = delete; void maybe_resize_rows (int rows) { if (rows > m_display_rows) m_display_rows = rows; } QVariant edit_display (const QModelIndex& idx, int role) const { int row; int col; if (! index_ok (idx, row, col)) return QVariant (); octave_map m = m_value.map_value (); Cell cval = m.contents (col); return edit_display_sub (cval(row), role); } bool requires_sub_editor (const QModelIndex& idx) const { int row; int col; if (! index_ok (idx, row, col)) return false; octave_map m = m_value.map_value (); Cell cval = m.contents (col); return do_requires_sub_editor_sub (cval(row)); } char quote_char (const QModelIndex& idx) const { octave_value ov = value_at (idx); if (ov.is_string ()) return get_quote_char (ov); return 0; } QVariant header_data (int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant (); switch (orientation) { case Qt::Horizontal: if (section < data_columns ()) { octave_map m = m_value.map_value (); string_vector fields = m.fieldnames (); return QString::fromStdString (fields(section)); } else break; case Qt::Vertical: if (section < data_rows ()) return QString::number (section+1); else break; default: break; } return QVariant (); } QString subscript_expression (const QModelIndex& idx) const { if (! idx.isValid ()) return ""; octave_map m = m_value.map_value (); string_vector fields = m.fieldnames (); return (QString ("(%1).%2") .arg (idx.row () + 1) .arg (QString::fromStdString (fields(idx.column ())))); } octave_value value_at (const QModelIndex& idx) const { int row; int col; if (! index_ok (idx, row, col)) return octave_value (); octave_map m = m_value.map_value (); Cell cval = m.contents (col); return cval(row); } }; // 2-d struct array. Rows and columns index individual scalar structs. class struct_model : public base_ve_model { public: struct_model (const QString& expr, const octave_value& val) : base_ve_model (expr, val) { // FIXME: should fill the window and expand on scrolling or // resizing. maybe_resize_rows (m_data_rows + 16); maybe_resize_columns (m_data_cols + 16); } ~struct_model (void) = default; // No copying! struct_model (const struct_model&) = delete; struct_model& operator = (const struct_model&) = delete; void maybe_resize_rows (int rows) { if (rows > m_display_rows) m_display_rows = rows; } void maybe_resize_columns (int cols) { if (cols > m_display_cols) m_display_cols = cols; } QVariant edit_display (const QModelIndex& idx, int) const { int row; int col; if (! index_ok (idx, row, col)) return QVariant (); std::string str = m_value.edit_display (m_display_fmt, row, col); return QString::fromStdString (str); } bool requires_sub_editor (const QModelIndex& idx) const { int row; int col; if (! index_ok (idx, row, col)) return false; octave_map m = m_value.map_value (); return do_requires_sub_editor_sub (m(row, col)); } char quote_char (const QModelIndex& idx) const { octave_value ov = value_at (idx); if (ov.is_string ()) return get_quote_char (ov); return 0; } QString subscript_expression (const QModelIndex& idx) const { int row; int col; if (! index_ok (idx, row, col)) return ""; return (QString ("(%1,%2)") .arg (row + 1) .arg (col + 1)); } octave_value value_at (const QModelIndex& idx) const { int row; int col; if (! index_ok (idx, row, col)) return octave_value (); octave_map m = m_value.map_value (); return m(row, col); } }; base_ve_model * variable_editor_model::create (const QString& expr, const octave_value& val) { // Choose specific model based on type of val. if ((val.isnumeric () || val.islogical ()) && val.ndims () == 2) return new numeric_model (expr, val); else if (val.is_string () && (val.rows () == 1 || val.is_zero_by_zero ())) return new string_model (expr, val); else if (val.iscell ()) return new cell_model (expr, val); else if (val.isstruct ()) { if (val.numel () == 1) return new scalar_struct_model (expr, val); else if (val.ndims () == 2) { if (val.rows () == 1 || val.columns () == 1) return new vector_struct_model (expr, val); else return new struct_model (expr, val); } } return new display_only_model (expr, val); } variable_editor_model::variable_editor_model (const QString& expr, const octave_value& val, QObject *parent) : QAbstractTableModel (parent), rep (create (expr, val)) { update_description (); connect (this, &variable_editor_model::user_error_signal, this, &variable_editor_model::user_error); connect (this, &variable_editor_model::update_data_signal, this, &variable_editor_model::update_data); connect (this, &variable_editor_model::data_error_signal, this, &variable_editor_model::data_error); if (is_editable ()) { int new_rows = display_rows (); if (new_rows > 0) { beginInsertRows (QModelIndex (), 0, new_rows-1); endInsertRows (); } int new_cols = display_columns (); if (new_cols > 0) { beginInsertColumns (QModelIndex (), 0, new_cols-1); endInsertColumns (); } } } bool variable_editor_model::setData (const QModelIndex& idx, const QVariant& v_user_input, int role) { if (role != Qt::EditRole || ! v_user_input.canConvert (QMetaType::QString) || ! idx.isValid ()) return false; // Initially, set value to whatever the user entered. QString user_input = v_user_input.toString (); char qc = quote_char (idx); // FIXME: maybe we need a better way to ask whether empty input is // valid than to rely on whether there is a quote character (meaning // we are editing a character string)? if (user_input.isEmpty () && ! qc) return false; set_update_pending (idx, user_input); std::ostringstream os; std::string nm = name (); os << nm; QString tmp = subscript_expression (idx); os << tmp.toStdString () << "="; if (qc) os << qc; os << user_input.toStdString (); if (qc) os << qc; std::string expr = os.str (); emit interpreter_event ([=] (interpreter& interp) { // INTERPRETER THREAD try { int parse_status = 0; interp.eval_string (expr, true, parse_status); octave_value val = retrieve_variable (interp, nm); emit update_data_signal (val); } catch (const execution_exception&) { clear_update_pending (); evaluation_error (expr); // This will cause the data in the cell to be reset // from the cached octave_value object. emit dataChanged (idx, idx); } }); return true; } bool variable_editor_model::clear_content (const QModelIndex& idx) { int row = idx.row (); int col = idx.column (); if (row < data_rows () && col < data_columns ()) return setData (idx, QVariant ("0")); return false; } Qt::ItemFlags variable_editor_model::flags (const QModelIndex& idx) const { if (! is_valid ()) return Qt::NoItemFlags; Qt::ItemFlags retval = QAbstractTableModel::flags (idx); if (! requires_sub_editor (idx)) retval |= Qt::ItemIsEditable; return retval; } bool variable_editor_model::insertRows (int row, int count, const QModelIndex&) { // FIXME: cells? eval_expr_event (QString ("%1 = [%1(1:%2,:); zeros(%3,columns(%1)); %1(%2+%3:end,:)]") .arg (QString::fromStdString (name ())) .arg (row) .arg (count)); return true; } bool variable_editor_model::removeRows (int row, int count, const QModelIndex&) { if (row + count > data_rows ()) { qDebug () << "Tried to remove too many rows " << data_rows () << " " << count << " (" << row << ")"; return false; } eval_expr_event (QString ("%1(%2:%3,:) = []") .arg (QString::fromStdString (name ())) .arg (row) .arg (row + count)); return true; } bool variable_editor_model::insertColumns (int col, int count, const QModelIndex&) { eval_expr_event (QString ("%1 = [%1(:,1:%2); zeros(rows(%1),%3) %1(:,%2+%3:end)]") .arg (QString::fromStdString (name ())) .arg (col) .arg (count)); return true; } bool variable_editor_model::removeColumns (int col, int count, const QModelIndex&) { if (col + count > data_columns ()) { qDebug () << "Tried to remove too many cols " << data_columns () << " " << count << " (" << col << ")"; return false; } eval_expr_event (QString ("%1(:,%2:%3) = []") .arg (QString::fromStdString (name ())) .arg (col) .arg (col + count)); return true; } void variable_editor_model::init_from_oct (interpreter& interp) { // INTERPRETER THREAD std::string nm = name (); try { octave_value val = retrieve_variable (interp, nm); emit update_data_signal (val); } catch (const execution_exception&) { QString msg = (QString ("variable '%1' is invalid or undefined") .arg (QString::fromStdString (nm))); emit data_error_signal (msg); } } void variable_editor_model::eval_expr_event (const QString& expr_arg) { std::string expr = expr_arg.toStdString (); emit interpreter_event ([=] (interpreter& interp) { // INTERPRETER THREAD try { int parse_status = 0; interp.eval_string (expr, true, parse_status); init_from_oct (interp); } catch (const execution_exception&) { evaluation_error (expr); } }); } // If the variable exists, load it into the data model. If it doesn't // exist, flag the data model as referring to a nonexistent variable. // This allows the variable to be opened before it is created. // This function should only be called within other functions that // execute in the interpreter thread. It should also be called in a // try-catch block that catches execution exceptions. octave_value variable_editor_model::retrieve_variable (interpreter& interp, const std::string& x) { // INTERPRETER THREAD std::string name = x; name = name.substr (0, name.find (".")); if (name.back () == ')' || name.back () == '}') name = name.substr (0, name.find (name.back () == ')' ? "(" : "{")); if (symbol_exist (name, "var") > 0) { int parse_status = 0; octave_value result = interp.eval_string (x, true, parse_status); if (result.is_cs_list ()) error ("evaluation produced c-s list"); return result; } return octave_value (); } void variable_editor_model::evaluation_error (const std::string& expr) const { emit user_error_signal ("Evaluation failed", QString ("failed to evaluate expression: '%1' or result can't be edited") .arg (QString::fromStdString (expr))); } void variable_editor_model::user_error (const QString& title, const QString& msg) { QMessageBox::critical (nullptr, title, msg); } void variable_editor_model::update_data_cache (void) { emit interpreter_event ([=] (interpreter& interp) { // INTERPRETER_THREAD init_from_oct (interp); }); } void variable_editor_model::update_data (const octave_value& val) { if (val.is_undefined ()) { QString msg = (QString ("variable '%1' is invalid or undefined") .arg (QString::fromStdString (name ()))); emit data_error_signal (msg); return; } // Add or remove rows and columns when the size changes. int old_rows = display_rows (); int old_cols = display_columns (); reset (val); int new_rows = display_rows (); int new_cols = display_columns (); if (new_rows != old_rows || new_cols != old_cols) change_display_size (old_rows, old_cols, new_rows, new_cols); // Even if the size doesn't change, we still need to update here // because the data may have changed. But only if we have some data // to display. if (new_rows > 0 && new_cols > 0) emit dataChanged (QAbstractTableModel::index (0, 0), QAbstractTableModel::index (new_rows-1, new_cols-1)); clear_update_pending (); } void variable_editor_model::change_display_size (int old_rows, int old_cols, int new_rows, int new_cols) { if (new_rows < old_rows) { beginRemoveRows (QModelIndex (), new_rows, old_rows-1); endRemoveRows (); } else if (new_rows > old_rows) { beginInsertRows (QModelIndex (), old_rows, new_rows-1); endInsertRows (); } if (new_cols < old_cols) { beginRemoveColumns (QModelIndex (), new_cols, old_cols-1); endRemoveColumns (); } else if (new_cols > old_cols) { beginInsertColumns (QModelIndex (), old_cols, new_cols-1); endInsertColumns (); } } void variable_editor_model::maybe_resize_rows (int rows) { int old_rows = display_rows (); int old_cols = display_columns (); rep->maybe_resize_rows (rows); int new_rows = display_rows (); int new_cols = display_columns (); if (new_rows != old_rows) change_display_size (old_rows, old_cols, new_rows, new_cols); } void variable_editor_model::maybe_resize_columns (int cols) { int old_rows = display_rows (); int old_cols = display_columns (); rep->maybe_resize_columns (cols); int new_rows = display_rows (); int new_cols = display_columns (); if (new_cols != old_cols) change_display_size (old_rows, old_cols, new_rows, new_cols); } void variable_editor_model::data_error (const QString& msg) { invalidate (); update_description (msg); } void variable_editor_model::reset (const octave_value& val) { base_ve_model *old_rep = rep; rep = create (QString::fromStdString (name ()), val); delete old_rep; update_description (); emit set_editable_signal (is_editable ()); } void variable_editor_model::invalidate (void) { beginResetModel (); reset (octave_value ()); endResetModel (); } void variable_editor_model::update_description (const QString& description) { emit description_changed (description.isEmpty () ? make_description_text () : description); } void variable_editor_model::double_click (const QModelIndex& idx) { if (requires_sub_editor (idx)) { QString name = QString::fromStdString(rep->name ()); emit edit_variable_signal (name + subscript_expression (idx), value_at (idx)); } } OCTAVE_END_NAMESPACE(octave)