File indexing completed on 2024-05-12 15:27:02
0001 /*************************************************************************** 0002 File : matrixcommands.h 0003 Project : LabPlot 0004 Description : Commands used in Matrix (part of the undo/redo framework) 0005 -------------------------------------------------------------------- 0006 Copyright : (C) 2008 Tilman Benkert (thzs@gmx.net) 0007 Copyright : (C) 2015 Alexander Semke (alexander.semke@web.de) 0008 Copyright : (C) 2017 Stefan Gerlach (stefan.gerlach@uni.kn) 0009 0010 ***************************************************************************/ 0011 0012 /*************************************************************************** 0013 * * 0014 * This program is free software; you can redistribute it and/or modify * 0015 * it under the terms of the GNU General Public License as published by * 0016 * the Free Software Foundation; either version 2 of the License, or * 0017 * (at your option) any later version. * 0018 * * 0019 * This program is distributed in the hope that it will be useful, * 0020 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0021 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0022 * GNU General Public License for more details. * 0023 * * 0024 * You should have received a copy of the GNU General Public License * 0025 * along with this program; if not, write to the Free Software * 0026 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0027 * Boston, MA 02110-1301 USA * 0028 * * 0029 ***************************************************************************/ 0030 0031 #ifndef MATRIX_COMMANDS_H 0032 #define MATRIX_COMMANDS_H 0033 0034 #include <QUndoCommand> 0035 #include <KLocalizedString> 0036 #include "Matrix.h" 0037 #include "MatrixPrivate.h" 0038 0039 //! Insert columns 0040 class MatrixInsertColumnsCmd : public QUndoCommand { 0041 public: 0042 MatrixInsertColumnsCmd(MatrixPrivate*, int before, int count, QUndoCommand* = nullptr); 0043 void redo() override; 0044 void undo() override; 0045 0046 private: 0047 MatrixPrivate* m_private_obj; 0048 int m_before; //! Column to insert before 0049 int m_count; //! The number of new columns 0050 }; 0051 0052 //! Insert rows 0053 class MatrixInsertRowsCmd : public QUndoCommand { 0054 public: 0055 MatrixInsertRowsCmd(MatrixPrivate*, int before, int count, QUndoCommand* = nullptr); 0056 void redo() override; 0057 void undo() override; 0058 0059 private: 0060 MatrixPrivate* m_private_obj; 0061 int m_before; //! Row to insert before 0062 int m_count; //! The number of new rows 0063 }; 0064 0065 //! Remove columns 0066 template <typename T> 0067 class MatrixRemoveColumnsCmd : public QUndoCommand { 0068 public: 0069 MatrixRemoveColumnsCmd(MatrixPrivate* private_obj, int first, int count, QUndoCommand* parent = nullptr) 0070 : QUndoCommand(parent), m_private_obj(private_obj), m_first(first), m_count(count) { 0071 setText(i18np("%1: remove %2 column", "%1: remove %2 columns", m_private_obj->name(), m_count)); 0072 } 0073 void redo() override { 0074 if(m_backups.isEmpty()) { 0075 int last_row = m_private_obj->rowCount-1; 0076 for (int i = 0; i < m_count; i++) 0077 m_backups.append(m_private_obj->columnCells<T>(m_first+i, 0, last_row)); 0078 } 0079 m_private_obj->removeColumns(m_first, m_count); 0080 emit m_private_obj->q->columnCountChanged(m_private_obj->columnCount); 0081 } 0082 void undo() override { 0083 m_private_obj->insertColumns(m_first, m_count); 0084 int last_row = m_private_obj->rowCount-1; 0085 //TODO: use memcopy to copy from the backup vector 0086 for (int i = 0; i < m_count; i++) 0087 m_private_obj->setColumnCells(m_first+i, 0, last_row, m_backups.at(i)); 0088 0089 emit m_private_obj->q->columnCountChanged(m_private_obj->columnCount); 0090 } 0091 0092 private: 0093 MatrixPrivate* m_private_obj; 0094 0095 int m_first; //! First column to remove 0096 int m_count; //! The number of columns to remove 0097 QVector<QVector<T>> m_backups; //! Backups of the removed columns 0098 }; 0099 0100 //! Remove rows 0101 template <typename T> 0102 class MatrixRemoveRowsCmd : public QUndoCommand { 0103 public: 0104 MatrixRemoveRowsCmd(MatrixPrivate* private_obj, int first, int count, QUndoCommand* parent = nullptr) 0105 : QUndoCommand(parent), m_private_obj(private_obj), m_first(first), m_count(count) { 0106 setText(i18np("%1: remove %2 row", "%1: remove %2 rows", m_private_obj->name(), m_count)); 0107 } 0108 void redo() override { 0109 if(m_backups.isEmpty()) { 0110 int last_row = m_first+m_count-1; 0111 for (int col = 0; col < m_private_obj->columnCount; col++) 0112 m_backups.append(m_private_obj->columnCells<T>(col, m_first, last_row)); 0113 } 0114 m_private_obj->removeRows(m_first, m_count); 0115 emit m_private_obj->q->rowCountChanged(m_private_obj->rowCount); 0116 } 0117 void undo() override { 0118 m_private_obj->insertRows(m_first, m_count); 0119 int last_row = m_first+m_count-1; 0120 for (int col = 0; col < m_private_obj->columnCount; col++) 0121 m_private_obj->setColumnCells(col, m_first, last_row, m_backups.at(col)); 0122 emit m_private_obj->q->rowCountChanged(m_private_obj->rowCount); 0123 } 0124 0125 private: 0126 MatrixPrivate* m_private_obj; 0127 int m_first; //! First row to remove 0128 int m_count; //! The number of rows to remove 0129 QVector< QVector<T> > m_backups; //! Backups of the removed rows 0130 }; 0131 0132 //! Clear matrix 0133 template <typename T> 0134 class MatrixClearCmd : public QUndoCommand { 0135 public: 0136 explicit MatrixClearCmd(MatrixPrivate* private_obj, QUndoCommand* parent = nullptr) 0137 : QUndoCommand(parent), m_private_obj(private_obj) { 0138 setText(i18n("%1: clear", m_private_obj->name())); 0139 } 0140 void redo() override { 0141 if(m_backups.isEmpty()) { 0142 int last_row = m_private_obj->rowCount-1; 0143 0144 for (int i = 0; i < m_private_obj->columnCount; i++) 0145 m_backups.append(m_private_obj->columnCells<T>(i, 0, last_row)); 0146 } 0147 0148 for (int i = 0; i < m_private_obj->columnCount; i++) 0149 m_private_obj->clearColumn(i); 0150 } 0151 void undo() override { 0152 int last_row = m_private_obj->rowCount-1; 0153 for (int i = 0; i < m_private_obj->columnCount; i++) 0154 m_private_obj->setColumnCells(i, 0, last_row, m_backups.at(i)); 0155 } 0156 0157 private: 0158 MatrixPrivate* m_private_obj; 0159 QVector<QVector<T>> m_backups; //! Backups of the cleared cells 0160 }; 0161 0162 //! Clear matrix column 0163 template <typename T> 0164 class MatrixClearColumnCmd : public QUndoCommand { 0165 public: 0166 MatrixClearColumnCmd(MatrixPrivate* private_obj, int col, QUndoCommand* parent = nullptr) 0167 : QUndoCommand(parent), m_private_obj(private_obj), m_col(col) { 0168 setText(i18n("%1: clear column %2", m_private_obj->name(), m_col+1)); 0169 } 0170 void redo() override { 0171 if(m_backup.isEmpty()) 0172 m_backup = m_private_obj->columnCells<T>(m_col, 0, m_private_obj->rowCount-1); 0173 m_private_obj->clearColumn(m_col); 0174 } 0175 void undo() override { 0176 m_private_obj->setColumnCells(m_col, 0, m_private_obj->rowCount-1, m_backup); 0177 } 0178 0179 private: 0180 MatrixPrivate* m_private_obj; 0181 int m_col; //! The index of the column 0182 QVector<T> m_backup; //! Backup of the cleared column 0183 }; 0184 0185 // Set cell value 0186 template <typename T> 0187 class MatrixSetCellValueCmd : public QUndoCommand { 0188 public: 0189 MatrixSetCellValueCmd(MatrixPrivate* private_obj, int row, int col, T value, QUndoCommand* parent = nullptr) 0190 : QUndoCommand(parent), m_private_obj(private_obj), m_row(row), m_col(col), m_value(value), m_old_value(value) { 0191 // remark: don't use many QString::arg() calls in ctors of commands that might be called often, 0192 // they use a lot of execution time 0193 setText(i18n("%1: set cell value", m_private_obj->name())); 0194 } 0195 void redo() override { 0196 m_old_value = m_private_obj->cell<T>(m_row, m_col); 0197 m_private_obj->setCell(m_row, m_col, m_value); 0198 } 0199 void undo() override { 0200 m_private_obj->setCell(m_row, m_col, m_old_value); 0201 } 0202 0203 private: 0204 MatrixPrivate* m_private_obj; 0205 int m_row; //! The index of the row 0206 int m_col; //! The index of the column 0207 T m_value; //! New cell value 0208 T m_old_value; //! Backup of the changed value 0209 }; 0210 0211 // Set matrix coordinates 0212 class MatrixSetCoordinatesCmd : public QUndoCommand { 0213 public: 0214 MatrixSetCoordinatesCmd(MatrixPrivate*, double x1, double x2, double y1, double y2, QUndoCommand* = nullptr); 0215 void redo() override; 0216 void undo() override; 0217 0218 private: 0219 MatrixPrivate* m_private_obj; 0220 double m_new_x1; 0221 double m_new_x2; 0222 double m_new_y1; 0223 double m_new_y2; 0224 double m_old_x1{-1}; 0225 double m_old_x2{-1}; 0226 double m_old_y1{-1}; 0227 double m_old_y2{-1}; 0228 }; 0229 0230 //! Set matrix formula 0231 class MatrixSetFormulaCmd : public QUndoCommand { 0232 public: 0233 MatrixSetFormulaCmd(MatrixPrivate*, QString formula); 0234 void redo() override; 0235 void undo() override; 0236 0237 private: 0238 MatrixPrivate* m_private_obj; 0239 QString m_other_formula; 0240 }; 0241 0242 // Set cell values for (a part of) a column at once 0243 template <typename T> 0244 class MatrixSetColumnCellsCmd : public QUndoCommand { 0245 public: 0246 MatrixSetColumnCellsCmd(MatrixPrivate* private_obj, int col, int first_row, int last_row, const QVector<T>& values, QUndoCommand* parent = nullptr) 0247 : QUndoCommand(parent), m_private_obj(private_obj), m_col(col), m_first_row(first_row), m_last_row(last_row), m_values(values) { 0248 setText(i18n("%1: set cell values", m_private_obj->name())); 0249 } 0250 void redo() override { 0251 if (m_old_values.isEmpty()) 0252 m_old_values = m_private_obj->columnCells<T>(m_col, m_first_row, m_last_row); 0253 m_private_obj->setColumnCells(m_col, m_first_row, m_last_row, m_values); 0254 } 0255 void undo() override { 0256 m_private_obj->setColumnCells(m_col, m_first_row, m_last_row, m_old_values); 0257 } 0258 0259 private: 0260 MatrixPrivate* m_private_obj; 0261 int m_col; //! The index of the column 0262 int m_first_row; //! The index of the first row 0263 int m_last_row; //! The index of the last row 0264 QVector<T> m_values; //! New cell values 0265 QVector<T> m_old_values; //! Backup of the changed values 0266 }; 0267 0268 //! Set cell values for (a part of) a row at once 0269 template <typename T> 0270 class MatrixSetRowCellsCmd : public QUndoCommand { 0271 public: 0272 MatrixSetRowCellsCmd(MatrixPrivate* private_obj, int row, int first_column, int last_column, const QVector<T>& values, QUndoCommand* parent = nullptr) 0273 : QUndoCommand(parent), m_private_obj(private_obj), m_row(row), m_first_column(first_column), 0274 m_last_column(last_column), m_values(values) { 0275 setText(i18n("%1: set cell values", m_private_obj->name())); 0276 } 0277 void redo() override { 0278 if (m_old_values.isEmpty()) 0279 m_old_values = m_private_obj->rowCells<T>(m_row, m_first_column, m_last_column); 0280 m_private_obj->setRowCells(m_row, m_first_column, m_last_column, m_values); 0281 } 0282 void undo() override { 0283 m_private_obj->setRowCells(m_row, m_first_column, m_last_column, m_old_values); 0284 } 0285 0286 private: 0287 MatrixPrivate* m_private_obj; 0288 int m_row; //! The index of the row 0289 int m_first_column; //! The index of the first column 0290 int m_last_column; //! The index of the last column 0291 QVector<T> m_values; //! New cell values 0292 QVector<T> m_old_values; //! Backup of the changed values 0293 }; 0294 0295 //! Transpose the matrix 0296 template <typename T> 0297 class MatrixTransposeCmd : public QUndoCommand { 0298 public: 0299 explicit MatrixTransposeCmd(MatrixPrivate* private_obj, QUndoCommand* parent = nullptr) 0300 : QUndoCommand(parent), m_private_obj(private_obj) { 0301 setText(i18n("%1: transpose", m_private_obj->name())); 0302 } 0303 void redo() override { 0304 int rows = m_private_obj->rowCount; 0305 int cols = m_private_obj->columnCount; 0306 int temp_size = qMax(rows, cols); 0307 m_private_obj->suppressDataChange = true; 0308 if (cols < rows) 0309 m_private_obj->insertColumns(cols, temp_size - cols); 0310 else if (cols > rows) 0311 m_private_obj->insertRows(rows, temp_size - rows); 0312 0313 for (int i = 1; i < temp_size; i++) { 0314 QVector<T> row = m_private_obj->rowCells<T>(i, 0, i-1); 0315 QVector<T> col = m_private_obj->columnCells<T>(i, 0, i-1); 0316 m_private_obj->setRowCells(i, 0, i-1, col); 0317 m_private_obj->setColumnCells(i, 0, i-1, row); 0318 } 0319 0320 if (cols < rows) 0321 m_private_obj->removeRows(cols, temp_size - cols); 0322 else if (cols > rows) 0323 m_private_obj->removeColumns(rows, temp_size - rows); 0324 m_private_obj->suppressDataChange = false; 0325 m_private_obj->emitDataChanged(0, 0, m_private_obj->rowCount-1, m_private_obj->columnCount-1); 0326 } 0327 void undo() override { 0328 redo(); 0329 } 0330 0331 private: 0332 MatrixPrivate* m_private_obj; 0333 }; 0334 0335 //! Mirror the matrix horizontally 0336 template <typename T> 0337 class MatrixMirrorHorizontallyCmd : public QUndoCommand { 0338 public: 0339 explicit MatrixMirrorHorizontallyCmd(MatrixPrivate* private_obj, QUndoCommand* parent = nullptr) 0340 : QUndoCommand(parent), m_private_obj(private_obj) { 0341 setText(i18n("%1: mirror horizontally", m_private_obj->name())); 0342 } 0343 void redo() override { 0344 int rows = m_private_obj->rowCount; 0345 int cols = m_private_obj->columnCount; 0346 int middle = cols/2; 0347 m_private_obj->suppressDataChange = true; 0348 0349 for (int i = 0; i<middle; i++) { 0350 QVector<T> temp = m_private_obj->columnCells<T>(i, 0, rows-1); 0351 m_private_obj->setColumnCells(i, 0, rows-1, m_private_obj->columnCells<T>(cols-i-1, 0, rows-1)); 0352 m_private_obj->setColumnCells(cols-i-1, 0, rows-1, temp); 0353 } 0354 m_private_obj->suppressDataChange = false; 0355 m_private_obj->emitDataChanged(0, 0, rows-1, cols-1); 0356 } 0357 void undo() override { 0358 redo(); 0359 } 0360 0361 private: 0362 MatrixPrivate* m_private_obj; 0363 }; 0364 0365 // Mirror the matrix vertically 0366 template <typename T> 0367 class MatrixMirrorVerticallyCmd : public QUndoCommand { 0368 public: 0369 explicit MatrixMirrorVerticallyCmd(MatrixPrivate* private_obj, QUndoCommand* parent = nullptr) 0370 : QUndoCommand(parent), m_private_obj(private_obj) { 0371 setText(i18n("%1: mirror vertically", m_private_obj->name())); 0372 } 0373 void redo() override { 0374 int rows = m_private_obj->rowCount; 0375 int cols = m_private_obj->columnCount; 0376 int middle = rows/2; 0377 m_private_obj->suppressDataChange = true; 0378 0379 for (int i = 0; i < middle; i++) { 0380 QVector<T> temp = m_private_obj->rowCells<T>(i, 0, cols-1); 0381 m_private_obj->setRowCells(i, 0, cols-1, m_private_obj->rowCells<T>(rows-i-1, 0, cols-1)); 0382 m_private_obj->setRowCells(rows-i-1, 0, cols-1, temp); 0383 } 0384 0385 m_private_obj->suppressDataChange = false; 0386 m_private_obj->emitDataChanged(0, 0, rows-1, cols-1); 0387 } 0388 void undo() override { 0389 redo(); 0390 } 0391 0392 private: 0393 MatrixPrivate* m_private_obj; 0394 }; 0395 0396 // Replace matrix values 0397 class MatrixReplaceValuesCmd : public QUndoCommand { 0398 public: 0399 explicit MatrixReplaceValuesCmd(MatrixPrivate*, void* new_values, QUndoCommand* = nullptr); 0400 void redo() override; 0401 void undo() override; 0402 0403 private: 0404 MatrixPrivate* m_private_obj; 0405 void* m_old_values{nullptr}; 0406 void* m_new_values; 0407 }; 0408 0409 #endif // MATRIX_COMMANDS_H