Warning, file /education/kmplot/kmplot/initialconditionseditor.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 KmPlot - a math. function plotter for the KDE-Desktop 0003 0004 SPDX-FileCopyrightText: 2006 David Saxton <david@bluehaze.org> 0005 0006 This file is part of the KDE Project. 0007 KmPlot is part of the KDE-EDU Project. 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 0011 */ 0012 0013 #include "initialconditionseditor.h" 0014 #include "equationedit.h" 0015 #include "parser.h" 0016 0017 #include <QHeaderView> 0018 #include <assert.h> 0019 0020 // BEGIN helper functions 0021 /** 0022 * \return a pointer to the differential state for the given function and row. 0023 */ 0024 DifferentialState *differentialState(DifferentialStates *states, int row) 0025 { 0026 if (!states) 0027 return 0; 0028 0029 if (row < 0 || row >= states->size()) 0030 return 0; 0031 0032 return &(*states)[row]; 0033 } 0034 0035 /** 0036 * \return a pointer to the Value for the given function, row and column 0037 */ 0038 Value *value(DifferentialStates *states, int row, int column) 0039 { 0040 DifferentialState *state = differentialState(states, row); 0041 if (!state) 0042 return 0; 0043 0044 if (column == 0) 0045 return &state->x0; 0046 else 0047 return &state->y0[column - 1]; 0048 } 0049 // END helper functions 0050 0051 // BEGIN class InitialConditionsModel 0052 InitialConditionsModel::InitialConditionsModel(InitialConditionsEditor *parent) 0053 : QAbstractTableModel(parent) 0054 { 0055 m_parent = parent; 0056 } 0057 0058 int InitialConditionsModel::rowCount(const QModelIndex & /*parent*/) const 0059 { 0060 return m_parent->differentialStates()->size(); 0061 } 0062 0063 int InitialConditionsModel::columnCount(const QModelIndex & /*parent*/) const 0064 { 0065 return m_parent->differentialStates()->order() + 1; 0066 } 0067 0068 QVariant InitialConditionsModel::data(const QModelIndex &index, int role) const 0069 { 0070 Value *v = value(m_parent->differentialStates(), index.row(), index.column()); 0071 if (!v) 0072 return QVariant(); 0073 0074 switch ((Qt::ItemDataRole)role) { 0075 case Qt::DisplayRole: 0076 case Qt::EditRole: 0077 case Qt::AccessibleTextRole: 0078 return v->expression(); 0079 0080 case Qt::ToolTipRole: 0081 /// \todo return a description of the initial condition 0082 return QVariant(); 0083 0084 case Qt::DecorationRole: 0085 case Qt::StatusTipRole: 0086 return QVariant(); 0087 0088 case Qt::TextAlignmentRole: 0089 return Qt::AlignLeft; 0090 0091 case Qt::ForegroundRole: 0092 return QColor(Qt::black); 0093 0094 case Qt::WhatsThisRole: 0095 case Qt::AccessibleDescriptionRole: 0096 case Qt::CheckStateRole: 0097 case Qt::BackgroundRole: 0098 case Qt::SizeHintRole: 0099 case Qt::FontRole: 0100 case Qt::UserRole: 0101 return QVariant(); 0102 0103 default: 0104 return QVariant(); 0105 } 0106 } 0107 0108 bool InitialConditionsModel::setData(const QModelIndex &index, const QVariant &variant, int role) 0109 { 0110 if (role != Qt::EditRole) 0111 return false; 0112 0113 Value *v = value(m_parent->differentialStates(), index.row(), index.column()); 0114 if (!v) 0115 return false; 0116 0117 v->updateExpression(variant.toString()); 0118 emit dataChanged(index, index); 0119 return true; 0120 } 0121 0122 QVariant InitialConditionsModel::headerData(int section, Qt::Orientation orientation, int role) const 0123 { 0124 Equation *eq = m_parent->equation(); 0125 0126 if (role != Qt::DisplayRole || !eq) 0127 return QAbstractTableModel::headerData(section, orientation, role); 0128 0129 // Don't display row headers 0130 if (orientation == Qt::Vertical) 0131 return QVariant(); 0132 0133 QString param; 0134 QStringList variables = eq->variables(); 0135 if (variables.isEmpty()) 0136 param = 'x'; 0137 else 0138 param = variables.first(); 0139 0140 param += SubscriptZeroSymbol; 0141 0142 if (section == 0) 0143 return param; 0144 else 0145 return QStringLiteral("%1%2(%3)").arg(eq->name(true)).arg(QString(), section - 1, '\'').arg(param); 0146 } 0147 0148 Qt::ItemFlags InitialConditionsModel::flags(const QModelIndex & /*index*/) const 0149 { 0150 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; 0151 } 0152 0153 bool InitialConditionsModel::insertRows(int position, int rows, const QModelIndex & /*parent*/) 0154 { 0155 if (!m_parent->differentialStates()) 0156 return false; 0157 0158 beginInsertRows(QModelIndex(), position, position + rows - 1); 0159 0160 for (int row = 0; row < rows; ++row) 0161 m_parent->differentialStates()->add(); 0162 0163 endInsertRows(); 0164 return true; 0165 } 0166 0167 bool InitialConditionsModel::removeRows(int position, int rows, const QModelIndex & /*parent*/) 0168 { 0169 beginRemoveRows(QModelIndex(), position, position + rows - 1); 0170 m_parent->differentialStates()->remove(position, rows); 0171 endRemoveRows(); 0172 return true; 0173 } 0174 // END class InitialConditionsModel 0175 0176 // BEGIN class InitialConditionsView 0177 InitialConditionsView::InitialConditionsView(QWidget *parent) 0178 : QTableView(parent) 0179 { 0180 setSelectionMode(QAbstractItemView::ExtendedSelection); 0181 setSelectionBehavior(QAbstractItemView::SelectRows); 0182 horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 0183 horizontalHeader()->setSectionsClickable(false); 0184 verticalHeader()->hide(); 0185 } 0186 // END class InitialConditionsView 0187 0188 // BEGIN class InitialConditionsDelegate 0189 InitialConditionsDelegate::InitialConditionsDelegate(InitialConditionsEditor *parent) 0190 : QItemDelegate(parent) 0191 { 0192 m_parent = parent; 0193 m_lastEditor = 0; 0194 } 0195 0196 QWidget *InitialConditionsDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex &index) const 0197 { 0198 Value *v = value(m_parent->differentialStates(), index.row(), index.column()); 0199 if (!v) 0200 return 0; 0201 0202 m_lastEditor = new EquationEdit(parent); 0203 connect(m_lastEditor, &EquationEdit::returnPressed, this, &InitialConditionsDelegate::equationEditDone); 0204 m_lastEditor->setFocus(); 0205 return m_lastEditor; 0206 } 0207 0208 void InitialConditionsDelegate::equationEditDone() 0209 { 0210 emit commitData(m_lastEditor); 0211 emit closeEditor(m_lastEditor); 0212 } 0213 0214 void InitialConditionsDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const 0215 { 0216 QString expression = index.model()->data(index, Qt::DisplayRole).toString(); 0217 static_cast<EquationEdit *>(editor)->setText(expression); 0218 } 0219 0220 void InitialConditionsDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const 0221 { 0222 EquationEdit *edit = static_cast<EquationEdit *>(editor); 0223 model->setData(index, edit->text()); 0224 } 0225 0226 void InitialConditionsDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex & /* index */) const 0227 { 0228 editor->setGeometry(option.rect); 0229 } 0230 // END class InitialConditionsDelegate 0231 0232 // BEGIN class InitialConditionsEditor 0233 InitialConditionsEditor::InitialConditionsEditor(QWidget *parent) 0234 : QWidget(parent) 0235 { 0236 m_equation = 0; 0237 0238 setupUi(this); 0239 layout()->setContentsMargins(0, 0, 0, 0); 0240 connect(addButton, &QPushButton::clicked, this, &InitialConditionsEditor::add); 0241 connect(removeButton, &QPushButton::clicked, this, &InitialConditionsEditor::remove); 0242 0243 m_model = new InitialConditionsModel(this); 0244 view->setModel(m_model); 0245 view->setItemDelegate(new InitialConditionsDelegate(this)); 0246 0247 connect(m_model, &InitialConditionsModel::dataChanged, this, &InitialConditionsEditor::dataChanged); 0248 } 0249 0250 void InitialConditionsEditor::setOrder(int order) 0251 { 0252 m_model->beginResetModel(); 0253 m_states.setOrder(order); 0254 m_model->endResetModel(); 0255 } 0256 0257 void InitialConditionsEditor::init(Function *function) 0258 { 0259 m_model->beginResetModel(); 0260 0261 if (function) { 0262 m_equation = function->eq[0]; 0263 m_states = m_equation->differentialStates; 0264 } else { 0265 m_equation = 0; 0266 } 0267 0268 m_model->endResetModel(); 0269 } 0270 0271 void InitialConditionsEditor::add() 0272 { 0273 m_model->insertRows(0, 1, QModelIndex()); 0274 emit dataChanged(); 0275 } 0276 0277 void InitialConditionsEditor::remove() 0278 { 0279 const QModelIndexList selected = view->selectionModel()->selectedIndexes(); 0280 0281 QMap<int, void *> sorted; 0282 for (const QModelIndex &index : selected) 0283 sorted.insert(-index.row(), 0l); 0284 const QList<int> indexes = sorted.keys(); 0285 0286 for (int row : indexes) 0287 m_model->removeRows(-row, 1, QModelIndex()); 0288 0289 emit dataChanged(); 0290 } 0291 // END class InitialConditionsEditor