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