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