File indexing completed on 2024-05-12 15:27:02
0001 0002 /*************************************************************************** 0003 File : Matrix.cpp 0004 Project : Matrix 0005 Description : Spreadsheet with a MxN matrix data model 0006 -------------------------------------------------------------------- 0007 Copyright : (C) 2008-2009 Tilman Benkert (thzs@gmx.net) 0008 Copyright : (C) 2015-2017 Alexander Semke (alexander.semke@web.de) 0009 Copyright : (C) 2017-2020 Stefan Gerlach (stefan.gerlach@uni.kn) 0010 0011 ***************************************************************************/ 0012 0013 /*************************************************************************** 0014 * * 0015 * This program is free software; you can redistribute it and/or modify * 0016 * it under the terms of the GNU General Public License as published by * 0017 * the Free Software Foundation; either version 2 of the License, or * 0018 * (at your option) any later version. * 0019 * * 0020 * This program is distributed in the hope that it will be useful, * 0021 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0023 * GNU General Public License for more details. * 0024 * * 0025 * You should have received a copy of the GNU General Public License * 0026 * along with this program; if not, write to the Free Software * 0027 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0028 * Boston, MA 02110-1301 USA * 0029 * * 0030 ***************************************************************************/ 0031 0032 #include "Matrix.h" 0033 #include "MatrixPrivate.h" 0034 #include "matrixcommands.h" 0035 #include "backend/matrix/MatrixModel.h" 0036 #include "backend/core/Folder.h" 0037 #include "backend/lib/commandtemplates.h" 0038 #include "backend/lib/XmlStreamReader.h" 0039 #include "commonfrontend/matrix/MatrixView.h" 0040 #include "kdefrontend/spreadsheet/ExportSpreadsheetDialog.h" 0041 0042 #include <KLocalizedString> 0043 #include <KConfig> 0044 0045 #include <QHeaderView> 0046 #include <QPrinter> 0047 #include <QPrintDialog> 0048 #include <QPrintPreviewDialog> 0049 0050 /*! 0051 This class manages matrix based data (i.e., mathematically 0052 a MxN matrix with M rows, N columns). This data is typically 0053 used to for 3D plots. 0054 0055 The values of the matrix are stored as generic values. Each column 0056 of the matrix is stored in a QVector<T> objects. 0057 0058 \ingroup backend 0059 */ 0060 Matrix::Matrix(int rows, int cols, const QString& name, const AbstractColumn::ColumnMode mode) 0061 : AbstractDataSource(name, AspectType::Matrix), d(new MatrixPrivate(this, mode)) { 0062 0063 //set initial number of rows and columns 0064 appendColumns(cols); 0065 appendRows(rows); 0066 0067 init(); 0068 } 0069 0070 Matrix::Matrix(const QString& name, bool loading, const AbstractColumn::ColumnMode mode) 0071 : AbstractDataSource(name, AspectType::Matrix), d(new MatrixPrivate(this, mode)) { 0072 0073 if (!loading) 0074 init(); 0075 } 0076 0077 Matrix::~Matrix() { 0078 delete d; 0079 } 0080 0081 void Matrix::init() { 0082 KConfig config; 0083 KConfigGroup group = config.group("Matrix"); 0084 0085 //matrix dimension 0086 int rows = group.readEntry("RowCount", 10); 0087 int cols = group.readEntry("ColumnCount", 10); 0088 appendRows(rows); 0089 appendColumns(cols); 0090 0091 //mapping to logical x- and y-coordinates 0092 d->xStart = group.readEntry("XStart", 0.0); 0093 d->xEnd = group.readEntry("XEnd", 1.0); 0094 d->yStart = group.readEntry("YStart", 0.0); 0095 d->yEnd = group.readEntry("YEnd", 1.0); 0096 0097 //format 0098 QByteArray formatba = group.readEntry("NumericFormat", "f").toLatin1(); 0099 d->numericFormat = *formatba.data(); 0100 d->precision = group.readEntry("Precision", 3); 0101 d->headerFormat = (Matrix::HeaderFormat)group.readEntry("HeaderFormat", static_cast<int>(HeaderFormat::HeaderRowsColumns)); 0102 } 0103 0104 /*! 0105 Returns an icon to be used for decorating my views. 0106 */ 0107 QIcon Matrix::icon() const { 0108 return QIcon::fromTheme("labplot-matrix"); 0109 } 0110 0111 /*! 0112 Returns a new context menu. The caller takes ownership of the menu. 0113 */ 0114 QMenu* Matrix::createContextMenu() { 0115 QMenu* menu = AbstractPart::createContextMenu(); 0116 emit requestProjectContextMenu(menu); 0117 return menu; 0118 } 0119 0120 QWidget* Matrix::view() const { 0121 if (!m_partView) { 0122 m_view = new MatrixView(const_cast<Matrix*>(this)); 0123 m_partView = m_view; 0124 m_model = m_view->model(); 0125 } 0126 return m_partView; 0127 } 0128 0129 bool Matrix::exportView() const { 0130 auto* dlg = new ExportSpreadsheetDialog(m_view); 0131 dlg->setFileName(name()); 0132 dlg->setMatrixMode(true); 0133 0134 //TODO FITS filter to decide if it can be exported to both 0135 dlg->setExportTo(QStringList() << i18n("FITS image") << i18n("FITS table")); 0136 if (m_view->selectedColumnCount() == 0) { 0137 dlg->setExportSelection(false); 0138 } 0139 0140 bool ret; 0141 if ( (ret = (dlg->exec() == QDialog::Accepted)) ) { 0142 const QString path = dlg->path(); 0143 WAIT_CURSOR; 0144 0145 if (dlg->format() == ExportSpreadsheetDialog::Format::LaTeX) { 0146 const bool verticalHeader = dlg->matrixVerticalHeader(); 0147 const bool horizontalHeader = dlg->matrixHorizontalHeader(); 0148 const bool latexHeader = dlg->exportHeader(); 0149 const bool gridLines = dlg->gridLines(); 0150 const bool entire = dlg->entireSpreadheet(); 0151 const bool captions = dlg->captions(); 0152 m_view->exportToLaTeX(path, verticalHeader, horizontalHeader, 0153 latexHeader, gridLines, entire, captions); 0154 } else if (dlg->format() == ExportSpreadsheetDialog::Format::FITS) { 0155 const int exportTo = dlg->exportToFits(); 0156 m_view->exportToFits(path, exportTo ); 0157 } else { 0158 const QString separator = dlg->separator(); 0159 const QLocale::Language format = dlg->numberFormat(); 0160 m_view->exportToFile(path, separator, format); 0161 } 0162 RESET_CURSOR; 0163 } 0164 delete dlg; 0165 0166 return ret; 0167 } 0168 0169 bool Matrix::printView() { 0170 QPrinter printer; 0171 auto* dlg = new QPrintDialog(&printer, m_view); 0172 bool ret; 0173 dlg->setWindowTitle(i18nc("@title:window", "Print Matrix")); 0174 if ( (ret = (dlg->exec() == QDialog::Accepted)) ) 0175 m_view->print(&printer); 0176 0177 delete dlg; 0178 0179 return ret; 0180 } 0181 0182 bool Matrix::printPreview() const { 0183 auto* dlg = new QPrintPreviewDialog(m_view); 0184 connect(dlg, &QPrintPreviewDialog::paintRequested, m_view, &MatrixView::print); 0185 return dlg->exec(); 0186 } 0187 0188 //############################################################################## 0189 //########################## getter methods ################################## 0190 //############################################################################## 0191 void* Matrix::data() const { 0192 return d->data; 0193 } 0194 0195 BASIC_D_READER_IMPL(Matrix, AbstractColumn::ColumnMode, mode, mode) 0196 BASIC_D_READER_IMPL(Matrix, int, rowCount, rowCount) 0197 BASIC_D_READER_IMPL(Matrix, int, columnCount, columnCount) 0198 BASIC_D_READER_IMPL(Matrix, double, xStart, xStart) 0199 BASIC_D_READER_IMPL(Matrix, double, xEnd, xEnd) 0200 BASIC_D_READER_IMPL(Matrix, double, yStart, yStart) 0201 BASIC_D_READER_IMPL(Matrix, double, yEnd, yEnd) 0202 BASIC_D_READER_IMPL(Matrix, char, numericFormat, numericFormat) 0203 BASIC_D_READER_IMPL(Matrix, int, precision, precision) 0204 BASIC_D_READER_IMPL(Matrix, Matrix::HeaderFormat, headerFormat, headerFormat) 0205 CLASS_D_READER_IMPL(Matrix, QString, formula, formula) 0206 0207 void Matrix::setSuppressDataChangedSignal(bool b) { 0208 if (m_model) 0209 m_model->setSuppressDataChangedSignal(b); 0210 } 0211 0212 void Matrix::setChanged() { 0213 if (m_model) 0214 m_model->setChanged(); 0215 } 0216 0217 //############################################################################## 0218 //################# setter methods and undo commands ########################## 0219 //############################################################################## 0220 void Matrix::setRowCount(int count) { 0221 if (count == d->rowCount) 0222 return; 0223 0224 const int diff = count - d->rowCount; 0225 if (diff > 0) 0226 appendRows(diff); 0227 else if (diff < 0) 0228 removeRows(rowCount() + diff, -diff); 0229 } 0230 0231 void Matrix::setColumnCount(int count) { 0232 if (count == d->columnCount) 0233 return; 0234 0235 const int diff = count - columnCount(); 0236 if (diff > 0) 0237 appendColumns(diff); 0238 else if (diff < 0) 0239 removeColumns(columnCount() + diff, -diff); 0240 } 0241 0242 STD_SETTER_CMD_IMPL_F_S(Matrix, SetXStart, double, xStart, updateViewHeader) 0243 void Matrix::setXStart(double xStart) { 0244 if (xStart != d->xStart) 0245 exec(new MatrixSetXStartCmd(d, xStart, ki18n("%1: x-start changed"))); 0246 } 0247 0248 STD_SETTER_CMD_IMPL_F_S(Matrix, SetXEnd, double, xEnd, updateViewHeader) 0249 void Matrix::setXEnd(double xEnd) { 0250 if (xEnd != d->xEnd) 0251 exec(new MatrixSetXEndCmd(d, xEnd, ki18n("%1: x-end changed"))); 0252 } 0253 0254 STD_SETTER_CMD_IMPL_F_S(Matrix, SetYStart, double, yStart, updateViewHeader) 0255 void Matrix::setYStart(double yStart) { 0256 if (yStart != d->yStart) 0257 exec(new MatrixSetYStartCmd(d, yStart, ki18n("%1: y-start changed"))); 0258 } 0259 0260 STD_SETTER_CMD_IMPL_F_S(Matrix, SetYEnd, double, yEnd, updateViewHeader) 0261 void Matrix::setYEnd(double yEnd) { 0262 if (yEnd != d->yEnd) 0263 exec(new MatrixSetYEndCmd(d, yEnd, ki18n("%1: y-end changed"))); 0264 } 0265 0266 STD_SETTER_CMD_IMPL_S(Matrix, SetNumericFormat, char, numericFormat) 0267 void Matrix::setNumericFormat(char format) { 0268 if (format != d->numericFormat) 0269 exec(new MatrixSetNumericFormatCmd(d, format, ki18n("%1: numeric format changed"))); 0270 } 0271 0272 STD_SETTER_CMD_IMPL_S(Matrix, SetPrecision, int, precision) 0273 void Matrix::setPrecision(int precision) { 0274 if (precision != d->precision) 0275 exec(new MatrixSetPrecisionCmd(d, precision, ki18n("%1: precision changed"))); 0276 } 0277 0278 //TODO: make this undoable? 0279 void Matrix::setHeaderFormat(Matrix::HeaderFormat format) { 0280 d->headerFormat = format; 0281 m_model->updateHeader(); 0282 0283 if (m_view) 0284 m_view->resizeHeaders(); 0285 0286 emit headerFormatChanged(format); 0287 } 0288 0289 //columns 0290 void Matrix::insertColumns(int before, int count) { 0291 if (count < 1 || before < 0 || before > columnCount()) return; 0292 WAIT_CURSOR; 0293 exec(new MatrixInsertColumnsCmd(d, before, count)); 0294 RESET_CURSOR; 0295 } 0296 0297 void Matrix::appendColumns(int count) { 0298 insertColumns(columnCount(), count); 0299 } 0300 0301 void Matrix::removeColumns(int first, int count) { 0302 if (count < 1 || first < 0 || first+count > columnCount()) return; 0303 WAIT_CURSOR; 0304 switch (d->mode) { 0305 case AbstractColumn::ColumnMode::Numeric: 0306 exec(new MatrixRemoveColumnsCmd<double>(d, first, count)); 0307 break; 0308 case AbstractColumn::ColumnMode::Text: 0309 exec(new MatrixRemoveColumnsCmd<QString>(d, first, count)); 0310 break; 0311 case AbstractColumn::ColumnMode::Integer: 0312 exec(new MatrixRemoveColumnsCmd<int>(d, first, count)); 0313 break; 0314 case AbstractColumn::ColumnMode::BigInt: 0315 exec(new MatrixRemoveColumnsCmd<qint64>(d, first, count)); 0316 break; 0317 case AbstractColumn::ColumnMode::Day: 0318 case AbstractColumn::ColumnMode::Month: 0319 case AbstractColumn::ColumnMode::DateTime: 0320 exec(new MatrixRemoveColumnsCmd<QDateTime>(d, first, count)); 0321 break; 0322 } 0323 RESET_CURSOR; 0324 } 0325 0326 void Matrix::clearColumn(int c) { 0327 WAIT_CURSOR; 0328 switch (d->mode) { 0329 case AbstractColumn::ColumnMode::Numeric: 0330 exec(new MatrixClearColumnCmd<double>(d, c)); 0331 break; 0332 case AbstractColumn::ColumnMode::Text: 0333 exec(new MatrixClearColumnCmd<QString>(d, c)); 0334 break; 0335 case AbstractColumn::ColumnMode::Integer: 0336 exec(new MatrixClearColumnCmd<int>(d, c)); 0337 break; 0338 case AbstractColumn::ColumnMode::BigInt: 0339 exec(new MatrixClearColumnCmd<qint64>(d, c)); 0340 break; 0341 case AbstractColumn::ColumnMode::Day: 0342 case AbstractColumn::ColumnMode::Month: 0343 case AbstractColumn::ColumnMode::DateTime: 0344 exec(new MatrixClearColumnCmd<QDateTime>(d, c)); 0345 break; 0346 } 0347 RESET_CURSOR; 0348 } 0349 0350 //rows 0351 void Matrix::insertRows(int before, int count) { 0352 if (count < 1 || before < 0 || before > rowCount()) return; 0353 WAIT_CURSOR; 0354 exec(new MatrixInsertRowsCmd(d, before, count)); 0355 RESET_CURSOR; 0356 } 0357 0358 void Matrix::appendRows(int count) { 0359 insertRows(rowCount(), count); 0360 } 0361 0362 void Matrix::removeRows(int first, int count) { 0363 if (count < 1 || first < 0 || first+count > rowCount()) return; 0364 WAIT_CURSOR; 0365 switch (d->mode) { 0366 case AbstractColumn::ColumnMode::Numeric: 0367 exec(new MatrixRemoveRowsCmd<double>(d, first, count)); 0368 break; 0369 case AbstractColumn::ColumnMode::Text: 0370 exec(new MatrixRemoveRowsCmd<QString>(d, first, count)); 0371 break; 0372 case AbstractColumn::ColumnMode::Integer: 0373 exec(new MatrixRemoveRowsCmd<int>(d, first, count)); 0374 break; 0375 case AbstractColumn::ColumnMode::BigInt: 0376 exec(new MatrixRemoveRowsCmd<qint64>(d, first, count)); 0377 break; 0378 case AbstractColumn::ColumnMode::Day: 0379 case AbstractColumn::ColumnMode::Month: 0380 case AbstractColumn::ColumnMode::DateTime: 0381 exec(new MatrixRemoveRowsCmd<QDateTime>(d, first, count)); 0382 break; 0383 } 0384 RESET_CURSOR; 0385 } 0386 0387 void Matrix::clearRow(int r) { 0388 switch (d->mode) { 0389 case AbstractColumn::ColumnMode::Numeric: 0390 for (int c = 0; c < columnCount(); ++c) 0391 exec(new MatrixSetCellValueCmd<double>(d, r, c, 0.0)); 0392 break; 0393 case AbstractColumn::ColumnMode::Text: 0394 for (int c = 0; c < columnCount(); ++c) 0395 exec(new MatrixSetCellValueCmd<QString>(d, r, c, QString())); 0396 break; 0397 case AbstractColumn::ColumnMode::Integer: 0398 for (int c = 0; c < columnCount(); ++c) 0399 exec(new MatrixSetCellValueCmd<int>(d, r, c, 0)); 0400 break; 0401 case AbstractColumn::ColumnMode::BigInt: 0402 for (int c = 0; c < columnCount(); ++c) 0403 exec(new MatrixSetCellValueCmd<qint64>(d, r, c, 0)); 0404 break; 0405 case AbstractColumn::ColumnMode::Day: 0406 case AbstractColumn::ColumnMode::Month: 0407 case AbstractColumn::ColumnMode::DateTime: 0408 for (int c = 0; c < columnCount(); ++c) 0409 exec(new MatrixSetCellValueCmd<QDateTime>(d, r, c, QDateTime())); 0410 break; 0411 } 0412 } 0413 0414 //! Return the value in the given cell (needs explicit instantiation) 0415 template <typename T> 0416 T Matrix::cell(int row, int col) const { 0417 return d->cell<T>(row, col); 0418 } 0419 template double Matrix::cell<double>(int row, int col) const; 0420 template int Matrix::cell<int>(int row, int col) const; 0421 template qint64 Matrix::cell<qint64>(int row, int col) const; 0422 template QDateTime Matrix::cell<QDateTime>(int row, int col) const; 0423 template QString Matrix::cell<QString>(int row, int col) const; 0424 0425 //! Return the text displayed in the given cell (needs explicit instantiation) 0426 template <typename T> 0427 QString Matrix::text(int row, int col) { 0428 SET_NUMBER_LOCALE 0429 return numberLocale.toString(cell<T>(row,col)); 0430 } 0431 template <> 0432 QString Matrix::text<double>(int row, int col) { 0433 SET_NUMBER_LOCALE 0434 return numberLocale.toString(cell<double>(row,col), d->numericFormat, d->precision); 0435 } 0436 template <> 0437 QString Matrix::text<QString>(int row, int col) { 0438 return cell<QString>(row,col); 0439 } 0440 template QString Matrix::text<int>(int row, int col); 0441 template QString Matrix::text<qint64>(int row, int col); 0442 template QString Matrix::text<QDateTime>(int row, int col); 0443 0444 //! Set the value of the cell (needs explicit instantiation) 0445 template <typename T> 0446 void Matrix::setCell(int row, int col, T value) { 0447 if (row < 0 || row >= rowCount()) return; 0448 if (col < 0 || col >= columnCount()) return; 0449 exec(new MatrixSetCellValueCmd<T>(d, row, col, value)); 0450 } 0451 template void Matrix::setCell<double>(int row, int col, double value); 0452 template void Matrix::setCell<int>(int row, int col, int value); 0453 template void Matrix::setCell<qint64>(int row, int col, qint64 value); 0454 template void Matrix::setCell<QString>(int row, int col, QString value); 0455 template void Matrix::setCell<QDateTime>(int row, int col, QDateTime value); 0456 0457 void Matrix::clearCell(int row, int col) { 0458 switch (d->mode) { 0459 case AbstractColumn::ColumnMode::Numeric: 0460 exec(new MatrixSetCellValueCmd<double>(d, row, col, 0.0)); 0461 break; 0462 case AbstractColumn::ColumnMode::Text: 0463 exec(new MatrixSetCellValueCmd<QString>(d, row, col, QString())); 0464 break; 0465 case AbstractColumn::ColumnMode::Integer: 0466 exec(new MatrixSetCellValueCmd<int>(d, row, col, 0)); 0467 break; 0468 case AbstractColumn::ColumnMode::BigInt: 0469 exec(new MatrixSetCellValueCmd<qint64>(d, row, col, 0)); 0470 break; 0471 case AbstractColumn::ColumnMode::Day: 0472 case AbstractColumn::ColumnMode::Month: 0473 case AbstractColumn::ColumnMode::DateTime: 0474 exec(new MatrixSetCellValueCmd<QDateTime>(d, row, col, QDateTime())); 0475 break; 0476 } 0477 } 0478 0479 void Matrix::setDimensions(int rows, int cols) { 0480 if ( (rows < 0) || (cols < 0 ) || (rows == rowCount() && cols == columnCount()) ) 0481 return; 0482 0483 WAIT_CURSOR; 0484 beginMacro(i18n("%1: set matrix size to %2x%3", name(), rows, cols)); 0485 0486 int col_diff = cols - columnCount(); 0487 if (col_diff > 0) 0488 insertColumns(columnCount(), col_diff); 0489 else if (col_diff < 0) 0490 removeColumns(columnCount() + col_diff, -col_diff); 0491 0492 int row_diff = rows - rowCount(); 0493 if (row_diff > 0) 0494 appendRows(row_diff); 0495 else if (row_diff < 0) 0496 removeRows(rowCount() + row_diff, -row_diff); 0497 0498 endMacro(); 0499 RESET_CURSOR; 0500 } 0501 0502 void Matrix::copy(Matrix* other) { 0503 WAIT_CURSOR; 0504 beginMacro(i18n("%1: copy %2", name(), other->name())); 0505 0506 int rows = other->rowCount(); 0507 int columns = other->columnCount(); 0508 setDimensions(rows, columns); 0509 0510 for (int i = 0; i < rows; i++) 0511 setRowHeight(i, other->rowHeight(i)); 0512 0513 for (int i = 0; i < columns; i++) 0514 setColumnWidth(i, other->columnWidth(i)); 0515 0516 d->suppressDataChange = true; 0517 switch (d->mode) { 0518 case AbstractColumn::ColumnMode::Numeric: 0519 for (int i = 0; i < columns; i++) 0520 setColumnCells(i, 0, rows-1, other->columnCells<double>(i, 0, rows-1)); 0521 break; 0522 case AbstractColumn::ColumnMode::Text: 0523 for (int i = 0; i < columns; i++) 0524 setColumnCells(i, 0, rows-1, other->columnCells<QString>(i, 0, rows-1)); 0525 break; 0526 case AbstractColumn::ColumnMode::Integer: 0527 for (int i = 0; i < columns; i++) 0528 setColumnCells(i, 0, rows-1, other->columnCells<int>(i, 0, rows-1)); 0529 break; 0530 case AbstractColumn::ColumnMode::BigInt: 0531 for (int i = 0; i < columns; i++) 0532 setColumnCells(i, 0, rows-1, other->columnCells<qint64>(i, 0, rows-1)); 0533 break; 0534 case AbstractColumn::ColumnMode::Day: 0535 case AbstractColumn::ColumnMode::Month: 0536 case AbstractColumn::ColumnMode::DateTime: 0537 for (int i = 0; i < columns; i++) 0538 setColumnCells(i, 0, rows-1, other->columnCells<QDateTime>(i, 0, rows-1)); 0539 break; 0540 } 0541 0542 setCoordinates(other->xStart(), other->xEnd(), other->yStart(), other->yEnd()); 0543 setNumericFormat(other->numericFormat()); 0544 setPrecision(other->precision()); 0545 d->formula = other->formula(); 0546 d->suppressDataChange = false; 0547 emit dataChanged(0, 0, rows-1, columns-1); 0548 if (m_view) 0549 m_view->adjustHeaders(); 0550 0551 endMacro(); 0552 RESET_CURSOR; 0553 } 0554 0555 //! Duplicate the matrix inside its folder 0556 void Matrix::duplicate() { 0557 Matrix* matrix = new Matrix(rowCount(), columnCount(), name()); 0558 matrix->copy(this); 0559 if (folder()) 0560 folder()->addChild(matrix); 0561 } 0562 0563 void Matrix::addRows() { 0564 if (!m_view) return; 0565 WAIT_CURSOR; 0566 int count = m_view->selectedRowCount(false); 0567 beginMacro(i18np("%1: add %2 rows", "%1: add %2 rows", name(), count)); 0568 exec(new MatrixInsertRowsCmd(d, rowCount(), count)); 0569 endMacro(); 0570 RESET_CURSOR; 0571 } 0572 0573 void Matrix::addColumns() { 0574 if (!m_view) return; 0575 WAIT_CURSOR; 0576 int count = m_view->selectedRowCount(false); 0577 beginMacro(i18np("%1: add %2 column", "%1: add %2 columns", name(), count)); 0578 exec(new MatrixInsertColumnsCmd(d, columnCount(), count)); 0579 endMacro(); 0580 RESET_CURSOR; 0581 } 0582 0583 void Matrix::setCoordinates(double x1, double x2, double y1, double y2) { 0584 exec(new MatrixSetCoordinatesCmd(d, x1, x2, y1, y2)); 0585 } 0586 0587 void Matrix::setFormula(const QString& formula) { 0588 exec(new MatrixSetFormulaCmd(d, formula)); 0589 } 0590 0591 //! This method should only be called by the view. 0592 /** This method does not change the view, it only changes the 0593 * values that are saved when the matrix is saved. The view 0594 * has to take care of reading and applying these values */ 0595 void Matrix::setRowHeight(int row, int height) { 0596 d->setRowHeight(row, height); 0597 } 0598 0599 //! This method should only be called by the view. 0600 /** This method does not change the view, it only changes the 0601 * values that are saved when the matrix is saved. The view 0602 * has to take care of reading and applying these values */ 0603 void Matrix::setColumnWidth(int col, int width) { 0604 d->setColumnWidth(col, width); 0605 } 0606 0607 int Matrix::rowHeight(int row) const { 0608 return d->rowHeight(row); 0609 } 0610 0611 int Matrix::columnWidth(int col) const { 0612 return d->columnWidth(col); 0613 } 0614 0615 //! Return the values in the given cells as vector 0616 template <typename T> 0617 QVector<T> Matrix::columnCells(int col, int first_row, int last_row) { 0618 return d->columnCells<T>(col, first_row, last_row); 0619 } 0620 0621 //! Set the values in the given cells from a type T vector 0622 template <typename T> 0623 void Matrix::setColumnCells(int col, int first_row, int last_row, const QVector<T>& values) { 0624 WAIT_CURSOR; 0625 exec(new MatrixSetColumnCellsCmd<T>(d, col, first_row, last_row, values)); 0626 RESET_CURSOR; 0627 } 0628 0629 //! Return the values in the given cells as vector (needs explicit instantiation) 0630 template <typename T> 0631 QVector<T> Matrix::rowCells(int row, int first_column, int last_column) { 0632 return d->rowCells<T>(row, first_column, last_column); 0633 } 0634 template QVector<double> Matrix::rowCells<double>(int row, int first_column, int last_column); 0635 template QVector<QString> Matrix::rowCells<QString>(int row, int first_column, int last_column); 0636 template QVector<int> Matrix::rowCells<int>(int row, int first_column, int last_column); 0637 template QVector<QDateTime> Matrix::rowCells<QDateTime>(int row, int first_column, int last_column); 0638 0639 //! Set the values in the given cells from a type T vector 0640 template <typename T> 0641 void Matrix::setRowCells(int row, int first_column, int last_column, const QVector<T>& values) { 0642 WAIT_CURSOR; 0643 exec(new MatrixSetRowCellsCmd<T>(d, row, first_column, last_column, values)); 0644 RESET_CURSOR; 0645 } 0646 0647 void Matrix::setData(void* data) { 0648 bool isEmpty = false; 0649 0650 switch (d->mode) { 0651 case AbstractColumn::ColumnMode::Numeric: 0652 if (static_cast<QVector<QVector<double>>*>(data)->isEmpty()) 0653 isEmpty = true; 0654 break; 0655 case AbstractColumn::ColumnMode::Text: 0656 if (static_cast<QVector<QVector<QString>>*>(data)->isEmpty()) 0657 isEmpty = true; 0658 break; 0659 case AbstractColumn::ColumnMode::Integer: 0660 if (static_cast<QVector<QVector<int>>*>(data)->isEmpty()) 0661 isEmpty = true; 0662 break; 0663 case AbstractColumn::ColumnMode::BigInt: 0664 if (static_cast<QVector<QVector<qint64>>*>(data)->isEmpty()) 0665 isEmpty = true; 0666 break; 0667 case AbstractColumn::ColumnMode::Day: 0668 case AbstractColumn::ColumnMode::Month: 0669 case AbstractColumn::ColumnMode::DateTime: 0670 if (static_cast<QVector<QVector<QDateTime>>*>(data)->isEmpty()) 0671 isEmpty = true; 0672 break; 0673 } 0674 0675 if (!isEmpty) 0676 exec(new MatrixReplaceValuesCmd(d, data)); 0677 } 0678 0679 //############################################################################## 0680 //######################### Public slots ##################################### 0681 //############################################################################## 0682 //! Clear the whole matrix (i.e. reset all cells) 0683 void Matrix::clear() { 0684 WAIT_CURSOR; 0685 beginMacro(i18n("%1: clear", name())); 0686 switch (d->mode) { 0687 case AbstractColumn::ColumnMode::Numeric: 0688 exec(new MatrixClearCmd<double>(d)); 0689 break; 0690 case AbstractColumn::ColumnMode::Text: 0691 exec(new MatrixClearCmd<QString>(d)); 0692 break; 0693 case AbstractColumn::ColumnMode::Integer: 0694 exec(new MatrixClearCmd<int>(d)); 0695 break; 0696 case AbstractColumn::ColumnMode::BigInt: 0697 exec(new MatrixClearCmd<qint64>(d)); 0698 break; 0699 case AbstractColumn::ColumnMode::Day: 0700 case AbstractColumn::ColumnMode::Month: 0701 case AbstractColumn::ColumnMode::DateTime: 0702 exec(new MatrixClearCmd<QDateTime>(d)); 0703 break; 0704 } 0705 endMacro(); 0706 RESET_CURSOR; 0707 } 0708 0709 void Matrix::transpose() { 0710 WAIT_CURSOR; 0711 switch (d->mode) { 0712 case AbstractColumn::ColumnMode::Numeric: 0713 exec(new MatrixTransposeCmd<double>(d)); 0714 break; 0715 case AbstractColumn::ColumnMode::Text: 0716 exec(new MatrixTransposeCmd<QString>(d)); 0717 break; 0718 case AbstractColumn::ColumnMode::Integer: 0719 exec(new MatrixTransposeCmd<int>(d)); 0720 break; 0721 case AbstractColumn::ColumnMode::BigInt: 0722 exec(new MatrixTransposeCmd<qint64>(d)); 0723 break; 0724 case AbstractColumn::ColumnMode::Day: 0725 case AbstractColumn::ColumnMode::Month: 0726 case AbstractColumn::ColumnMode::DateTime: 0727 exec(new MatrixTransposeCmd<QDateTime>(d)); 0728 break; 0729 } 0730 RESET_CURSOR; 0731 } 0732 0733 void Matrix::mirrorHorizontally() { 0734 WAIT_CURSOR; 0735 switch (d->mode) { 0736 case AbstractColumn::ColumnMode::Numeric: 0737 exec(new MatrixMirrorHorizontallyCmd<double>(d)); 0738 break; 0739 case AbstractColumn::ColumnMode::Text: 0740 exec(new MatrixMirrorHorizontallyCmd<QString>(d)); 0741 break; 0742 case AbstractColumn::ColumnMode::Integer: 0743 exec(new MatrixMirrorHorizontallyCmd<int>(d)); 0744 break; 0745 case AbstractColumn::ColumnMode::BigInt: 0746 exec(new MatrixMirrorHorizontallyCmd<qint64>(d)); 0747 break; 0748 case AbstractColumn::ColumnMode::Day: 0749 case AbstractColumn::ColumnMode::Month: 0750 case AbstractColumn::ColumnMode::DateTime: 0751 exec(new MatrixMirrorHorizontallyCmd<QDateTime>(d)); 0752 break; 0753 } 0754 RESET_CURSOR; 0755 } 0756 0757 void Matrix::mirrorVertically() { 0758 WAIT_CURSOR; 0759 switch (d->mode) { 0760 case AbstractColumn::ColumnMode::Numeric: 0761 exec(new MatrixMirrorVerticallyCmd<double>(d)); 0762 break; 0763 case AbstractColumn::ColumnMode::Text: 0764 exec(new MatrixMirrorVerticallyCmd<QString>(d)); 0765 break; 0766 case AbstractColumn::ColumnMode::Integer: 0767 exec(new MatrixMirrorVerticallyCmd<int>(d)); 0768 break; 0769 case AbstractColumn::ColumnMode::BigInt: 0770 exec(new MatrixMirrorVerticallyCmd<qint64>(d)); 0771 break; 0772 case AbstractColumn::ColumnMode::Day: 0773 case AbstractColumn::ColumnMode::Month: 0774 case AbstractColumn::ColumnMode::DateTime: 0775 exec(new MatrixMirrorVerticallyCmd<QDateTime>(d)); 0776 break; 0777 } 0778 RESET_CURSOR; 0779 } 0780 0781 //############################################################################## 0782 //###################### Private implementation ############################### 0783 //############################################################################## 0784 0785 MatrixPrivate::MatrixPrivate(Matrix* owner, const AbstractColumn::ColumnMode m) 0786 : q(owner), data(nullptr), mode(m), rowCount(0), columnCount(0), suppressDataChange(false) { 0787 0788 switch (mode) { 0789 case AbstractColumn::ColumnMode::Numeric: 0790 data = new QVector<QVector<double>>(); 0791 break; 0792 case AbstractColumn::ColumnMode::Text: 0793 data = new QVector<QVector<QString>>(); 0794 break; 0795 case AbstractColumn::ColumnMode::Integer: 0796 data = new QVector<QVector<int>>(); 0797 break; 0798 case AbstractColumn::ColumnMode::BigInt: 0799 data = new QVector<QVector<qint64>>(); 0800 break; 0801 case AbstractColumn::ColumnMode::Month: 0802 case AbstractColumn::ColumnMode::Day: 0803 case AbstractColumn::ColumnMode::DateTime: 0804 data = new QVector<QVector<QDateTime>>(); 0805 break; 0806 } 0807 } 0808 0809 MatrixPrivate::~MatrixPrivate() { 0810 if (data) { 0811 switch (mode) { 0812 case AbstractColumn::ColumnMode::Numeric: 0813 delete static_cast<QVector<QVector<double>>*>(data); 0814 break; 0815 case AbstractColumn::ColumnMode::Text: 0816 delete static_cast<QVector<QVector<QString>>*>(data); 0817 break; 0818 case AbstractColumn::ColumnMode::Integer: 0819 delete static_cast<QVector<QVector<int>>*>(data); 0820 break; 0821 case AbstractColumn::ColumnMode::BigInt: 0822 delete static_cast<QVector<QVector<qint64>>*>(data); 0823 break; 0824 case AbstractColumn::ColumnMode::Day: 0825 case AbstractColumn::ColumnMode::Month: 0826 case AbstractColumn::ColumnMode::DateTime: 0827 delete static_cast<QVector<QVector<QDateTime>>*>(data); 0828 break; 0829 } 0830 } 0831 } 0832 0833 void MatrixPrivate::updateViewHeader() { 0834 q->m_view->model()->updateHeader(); 0835 } 0836 0837 /*! 0838 Insert \p count columns before column number \c before 0839 */ 0840 void MatrixPrivate::insertColumns(int before, int count) { 0841 Q_ASSERT(before >= 0); 0842 Q_ASSERT(before <= columnCount); 0843 0844 emit q->columnsAboutToBeInserted(before, count); 0845 switch (mode) { 0846 case AbstractColumn::ColumnMode::Numeric: 0847 for (int i = 0; i < count; i++) { 0848 static_cast<QVector<QVector<double>>*>(data)->insert(before+i, QVector<double>(rowCount)); 0849 columnWidths.insert(before+i, 0); 0850 } 0851 break; 0852 case AbstractColumn::ColumnMode::Text: 0853 for (int i = 0; i < count; i++) { 0854 static_cast<QVector<QVector<QString>>*>(data)->insert(before+i, QVector<QString>(rowCount)); 0855 columnWidths.insert(before+i, 0); 0856 } 0857 break; 0858 case AbstractColumn::ColumnMode::Integer: 0859 for (int i = 0; i < count; i++) { 0860 static_cast<QVector<QVector<int>>*>(data)->insert(before+i, QVector<int>(rowCount)); 0861 columnWidths.insert(before+i, 0); 0862 } 0863 break; 0864 case AbstractColumn::ColumnMode::BigInt: 0865 for (int i = 0; i < count; i++) { 0866 static_cast<QVector<QVector<qint64>>*>(data)->insert(before+i, QVector<qint64>(rowCount)); 0867 columnWidths.insert(before+i, 0); 0868 } 0869 break; 0870 case AbstractColumn::ColumnMode::Day: 0871 case AbstractColumn::ColumnMode::Month: 0872 case AbstractColumn::ColumnMode::DateTime: 0873 for (int i = 0; i < count; i++) { 0874 static_cast<QVector<QVector<QDateTime>>*>(data)->insert(before+i, QVector<QDateTime>(rowCount)); 0875 columnWidths.insert(before+i, 0); 0876 } 0877 break; 0878 } 0879 0880 columnCount += count; 0881 emit q->columnsInserted(before, count); 0882 } 0883 0884 /*! 0885 Remove \c count columns starting with column index \c first 0886 */ 0887 void MatrixPrivate::removeColumns(int first, int count) { 0888 emit q->columnsAboutToBeRemoved(first, count); 0889 Q_ASSERT(first >= 0); 0890 Q_ASSERT(first + count <= columnCount); 0891 0892 switch (mode) { 0893 case AbstractColumn::ColumnMode::Numeric: 0894 (static_cast<QVector<QVector<double>>*>(data))->remove(first, count); 0895 break; 0896 case AbstractColumn::ColumnMode::Text: 0897 (static_cast<QVector<QVector<QString>>*>(data))->remove(first, count); 0898 break; 0899 case AbstractColumn::ColumnMode::Integer: 0900 (static_cast<QVector<QVector<int>>*>(data))->remove(first, count); 0901 break; 0902 case AbstractColumn::ColumnMode::BigInt: 0903 (static_cast<QVector<QVector<qint64>>*>(data))->remove(first, count); 0904 break; 0905 case AbstractColumn::ColumnMode::Day: 0906 case AbstractColumn::ColumnMode::Month: 0907 case AbstractColumn::ColumnMode::DateTime: 0908 (static_cast<QVector<QVector<QDateTime>>*>(data))->remove(first, count); 0909 break; 0910 } 0911 0912 for (int i = 0; i < count; i++) 0913 columnWidths.remove(first); 0914 columnCount -= count; 0915 emit q->columnsRemoved(first, count); 0916 } 0917 0918 /*! 0919 Insert \c count rows before row with the index \c before 0920 */ 0921 void MatrixPrivate::insertRows(int before, int count) { 0922 emit q->rowsAboutToBeInserted(before, count); 0923 Q_ASSERT(before >= 0); 0924 Q_ASSERT(before <= rowCount); 0925 0926 switch (mode) { 0927 case AbstractColumn::ColumnMode::Numeric: 0928 for (int col = 0; col < columnCount; col++) 0929 for (int i = 0; i < count; i++) 0930 (static_cast<QVector<QVector<double>>*>(data))->operator[](col).insert(before+i, 0.0); 0931 break; 0932 case AbstractColumn::ColumnMode::Text: 0933 for (int col = 0; col < columnCount; col++) 0934 for (int i = 0; i < count; i++) 0935 (static_cast<QVector<QVector<QString>>*>(data))->operator[](col).insert(before+i, QString()); 0936 break; 0937 case AbstractColumn::ColumnMode::Integer: 0938 for (int col = 0; col < columnCount; col++) 0939 for (int i = 0; i < count; i++) 0940 (static_cast<QVector<QVector<int>>*>(data))->operator[](col).insert(before+i, 0); 0941 break; 0942 case AbstractColumn::ColumnMode::BigInt: 0943 for (int col = 0; col < columnCount; col++) 0944 for (int i = 0; i < count; i++) 0945 (static_cast<QVector<QVector<qint64>>*>(data))->operator[](col).insert(before+i, 0); 0946 break; 0947 case AbstractColumn::ColumnMode::Day: 0948 case AbstractColumn::ColumnMode::Month: 0949 case AbstractColumn::ColumnMode::DateTime: 0950 for (int col = 0; col < columnCount; col++) 0951 for (int i = 0; i < count; i++) 0952 (static_cast<QVector<QVector<QDateTime>>*>(data))->operator[](col).insert(before+i, QDateTime()); 0953 } 0954 0955 for (int i = 0; i < count; i++) 0956 rowHeights.insert(before+i, 0); 0957 0958 rowCount += count; 0959 emit q->rowsInserted(before, count); 0960 } 0961 0962 /*! 0963 Remove \c count columns starting from the column with index \c first 0964 */ 0965 void MatrixPrivate::removeRows(int first, int count) { 0966 emit q->rowsAboutToBeRemoved(first, count); 0967 Q_ASSERT(first >= 0); 0968 Q_ASSERT(first+count <= rowCount); 0969 0970 switch (mode) { 0971 case AbstractColumn::ColumnMode::Numeric: 0972 for (int col = 0; col < columnCount; col++) 0973 (static_cast<QVector<QVector<double>>*>(data))->operator[](col).remove(first, count); 0974 break; 0975 case AbstractColumn::ColumnMode::Text: 0976 for (int col = 0; col < columnCount; col++) 0977 (static_cast<QVector<QVector<QString>>*>(data))->operator[](col).remove(first, count); 0978 break; 0979 case AbstractColumn::ColumnMode::Integer: 0980 for (int col = 0; col < columnCount; col++) 0981 (static_cast<QVector<QVector<int>>*>(data))->operator[](col).remove(first, count); 0982 break; 0983 case AbstractColumn::ColumnMode::BigInt: 0984 for (int col = 0; col < columnCount; col++) 0985 (static_cast<QVector<QVector<qint64>>*>(data))->operator[](col).remove(first, count); 0986 break; 0987 case AbstractColumn::ColumnMode::Day: 0988 case AbstractColumn::ColumnMode::Month: 0989 case AbstractColumn::ColumnMode::DateTime: 0990 for (int col = 0; col < columnCount; col++) 0991 (static_cast<QVector<QVector<QDateTime>>*>(data))->operator[](col).remove(first, count); 0992 break; 0993 } 0994 0995 for (int i = 0; i < count; i++) 0996 rowHeights.remove(first); 0997 0998 rowCount -= count; 0999 emit q->rowsRemoved(first, count); 1000 } 1001 1002 //! Fill column with zeroes 1003 void MatrixPrivate::clearColumn(int col) { 1004 switch (mode) { 1005 case AbstractColumn::ColumnMode::Numeric: 1006 static_cast<QVector<QVector<double>>*>(data)->operator[](col).fill(0.0); 1007 break; 1008 case AbstractColumn::ColumnMode::Text: 1009 static_cast<QVector<QVector<QString>>*>(data)->operator[](col).fill(QString()); 1010 break; 1011 case AbstractColumn::ColumnMode::Integer: 1012 static_cast<QVector<QVector<int>>*>(data)->operator[](col).fill(0); 1013 break; 1014 case AbstractColumn::ColumnMode::BigInt: 1015 static_cast<QVector<QVector<qint64>>*>(data)->operator[](col).fill(0); 1016 break; 1017 case AbstractColumn::ColumnMode::Day: 1018 case AbstractColumn::ColumnMode::Month: 1019 case AbstractColumn::ColumnMode::DateTime: 1020 static_cast<QVector<QVector<QDateTime>>*>(data)->operator[](col).fill(QDateTime()); 1021 break; 1022 } 1023 1024 if (!suppressDataChange) 1025 emit q->dataChanged(0, col, rowCount-1, col); 1026 } 1027 1028 //############################################################################## 1029 //################## Serialization/Deserialization ########################### 1030 //############################################################################## 1031 void Matrix::save(QXmlStreamWriter* writer) const { 1032 DEBUG("Matrix::save()"); 1033 writer->writeStartElement("matrix"); 1034 writeBasicAttributes(writer); 1035 writeCommentElement(writer); 1036 1037 //formula 1038 writer->writeStartElement("formula"); 1039 writer->writeCharacters(d->formula); 1040 writer->writeEndElement(); 1041 1042 //format 1043 writer->writeStartElement("format"); 1044 writer->writeAttribute("mode", QString::number(static_cast<int>(d->mode))); 1045 writer->writeAttribute("headerFormat", QString::number(static_cast<int>(d->headerFormat))); 1046 writer->writeAttribute("numericFormat", QString(QChar(d->numericFormat))); 1047 writer->writeAttribute("precision", QString::number(d->precision)); 1048 writer->writeEndElement(); 1049 1050 //dimensions 1051 writer->writeStartElement("dimension"); 1052 writer->writeAttribute("columns", QString::number(d->columnCount)); 1053 writer->writeAttribute("rows", QString::number(d->rowCount)); 1054 writer->writeAttribute("x_start", QString::number(d->xStart)); 1055 writer->writeAttribute("x_end", QString::number(d->xEnd)); 1056 writer->writeAttribute("y_start", QString::number(d->yStart)); 1057 writer->writeAttribute("y_end", QString::number(d->yEnd)); 1058 writer->writeEndElement(); 1059 1060 //vector with row heights 1061 writer->writeStartElement("row_heights"); 1062 const char* data = reinterpret_cast<const char*>(d->rowHeights.constData()); 1063 int size = d->rowHeights.size() * sizeof(int); 1064 writer->writeCharacters(QByteArray::fromRawData(data,size).toBase64()); 1065 writer->writeEndElement(); 1066 1067 //vector with column widths 1068 writer->writeStartElement("column_widths"); 1069 data = reinterpret_cast<const char*>(d->columnWidths.constData()); 1070 size = d->columnWidths.size()*sizeof(int); 1071 writer->writeCharacters(QByteArray::fromRawData(data, size).toBase64()); 1072 writer->writeEndElement(); 1073 1074 //columns 1075 DEBUG(" mode = " << static_cast<int>(d->mode)); 1076 switch (d->mode) { 1077 case AbstractColumn::ColumnMode::Numeric: 1078 size = d->rowCount*sizeof(double); 1079 for (int i = 0; i < d->columnCount; ++i) { 1080 data = reinterpret_cast<const char*>(static_cast<QVector<QVector<double>>*>(d->data)->at(i).constData()); 1081 writer->writeStartElement("column"); 1082 writer->writeCharacters(QByteArray::fromRawData(data, size).toBase64()); 1083 writer->writeEndElement(); 1084 } 1085 break; 1086 case AbstractColumn::ColumnMode::Text: 1087 size = d->rowCount*sizeof(QString); 1088 for (int i = 0; i < d->columnCount; ++i) { 1089 QDEBUG(" string: " << static_cast<QVector<QVector<QString>>*>(d->data)->at(i)); 1090 data = reinterpret_cast<const char*>(static_cast<QVector<QVector<QString>>*>(d->data)->at(i).constData()); 1091 writer->writeStartElement("column"); 1092 writer->writeCharacters(QByteArray::fromRawData(data, size).toBase64()); 1093 writer->writeEndElement(); 1094 } 1095 break; 1096 case AbstractColumn::ColumnMode::Integer: 1097 size = d->rowCount*sizeof(int); 1098 for (int i = 0; i < d->columnCount; ++i) { 1099 data = reinterpret_cast<const char*>(static_cast<QVector<QVector<int>>*>(d->data)->at(i).constData()); 1100 writer->writeStartElement("column"); 1101 writer->writeCharacters(QByteArray::fromRawData(data, size).toBase64()); 1102 writer->writeEndElement(); 1103 } 1104 break; 1105 case AbstractColumn::ColumnMode::BigInt: 1106 size = d->rowCount*sizeof(qint64); 1107 for (int i = 0; i < d->columnCount; ++i) { 1108 data = reinterpret_cast<const char*>(static_cast<QVector<QVector<qint64>>*>(d->data)->at(i).constData()); 1109 writer->writeStartElement("column"); 1110 writer->writeCharacters(QByteArray::fromRawData(data, size).toBase64()); 1111 writer->writeEndElement(); 1112 } 1113 break; 1114 case AbstractColumn::ColumnMode::Day: 1115 case AbstractColumn::ColumnMode::Month: 1116 case AbstractColumn::ColumnMode::DateTime: 1117 size = d->rowCount*sizeof(QDateTime); 1118 for (int i = 0; i < d->columnCount; ++i) { 1119 data = reinterpret_cast<const char*>(static_cast<QVector<QVector<QDateTime>>*>(d->data)->at(i).constData()); 1120 writer->writeStartElement("column"); 1121 writer->writeCharacters(QByteArray::fromRawData(data, size).toBase64()); 1122 writer->writeEndElement(); 1123 } 1124 break; 1125 } 1126 1127 writer->writeEndElement(); // "matrix" 1128 } 1129 1130 bool Matrix::load(XmlStreamReader* reader, bool preview) { 1131 DEBUG("Matrix::load()"); 1132 if (!readBasicAttributes(reader)) 1133 return false; 1134 1135 KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used"); 1136 QXmlStreamAttributes attribs; 1137 QString str; 1138 1139 // read child elements 1140 while (!reader->atEnd()) { 1141 reader->readNext(); 1142 1143 if (reader->isEndElement() && reader->name() == "matrix") 1144 break; 1145 1146 if (!reader->isStartElement()) 1147 continue; 1148 1149 if (reader->name() == "comment") { 1150 if (!readCommentElement(reader)) return false; 1151 } else if (!preview && reader->name() == "formula") { 1152 d->formula = reader->text().toString().trimmed(); 1153 } else if (!preview && reader->name() == "format") { 1154 attribs = reader->attributes(); 1155 1156 str = attribs.value("mode").toString(); 1157 if (str.isEmpty()) 1158 reader->raiseWarning(attributeWarning.subs("mode").toString()); 1159 else 1160 d->mode = AbstractColumn::ColumnMode(str.toInt()); 1161 1162 str = attribs.value("headerFormat").toString(); 1163 if (str.isEmpty()) 1164 reader->raiseWarning(attributeWarning.subs("headerFormat").toString()); 1165 else 1166 d->headerFormat = Matrix::HeaderFormat(str.toInt()); 1167 1168 str = attribs.value("numericFormat").toString(); 1169 if (str.isEmpty()) 1170 reader->raiseWarning(attributeWarning.subs("numericFormat").toString()); 1171 else { 1172 QByteArray formatba = str.toLatin1(); 1173 d->numericFormat = *formatba.data(); 1174 } 1175 1176 str = attribs.value("precision").toString(); 1177 if (str.isEmpty()) 1178 reader->raiseWarning(attributeWarning.subs("precision").toString()); 1179 else 1180 d->precision = str.toInt(); 1181 1182 } else if (!preview && reader->name() == "dimension") { 1183 attribs = reader->attributes(); 1184 1185 str = attribs.value("columns").toString(); 1186 if (str.isEmpty()) 1187 reader->raiseWarning(attributeWarning.subs("columns").toString()); 1188 else 1189 d->columnCount = str.toInt(); 1190 1191 str = attribs.value("rows").toString(); 1192 if (str.isEmpty()) 1193 reader->raiseWarning(attributeWarning.subs("rows").toString()); 1194 else 1195 d->rowCount = str.toInt(); 1196 1197 str = attribs.value("x_start").toString(); 1198 if (str.isEmpty()) 1199 reader->raiseWarning(attributeWarning.subs("x_start").toString()); 1200 else 1201 d->xStart = str.toDouble(); 1202 1203 str = attribs.value("x_end").toString(); 1204 if (str.isEmpty()) 1205 reader->raiseWarning(attributeWarning.subs("x_end").toString()); 1206 else 1207 d->xEnd = str.toDouble(); 1208 1209 str = attribs.value("y_start").toString(); 1210 if (str.isEmpty()) 1211 reader->raiseWarning(attributeWarning.subs("y_start").toString()); 1212 else 1213 d->yStart = str.toDouble(); 1214 1215 str = attribs.value("y_end").toString(); 1216 if (str.isEmpty()) 1217 reader->raiseWarning(attributeWarning.subs("y_end").toString()); 1218 else 1219 d->yEnd = str.toDouble(); 1220 } else if (!preview && reader->name() == "row_heights") { 1221 reader->readNext(); 1222 QString content = reader->text().toString().trimmed(); 1223 QByteArray bytes = QByteArray::fromBase64(content.toLatin1()); 1224 int count = bytes.size()/sizeof(int); 1225 d->rowHeights.resize(count); 1226 memcpy(d->rowHeights.data(), bytes.data(), count*sizeof(int)); 1227 } else if (!preview && reader->name() == "column_widths") { 1228 reader->readNext(); 1229 QString content = reader->text().toString().trimmed(); 1230 QByteArray bytes = QByteArray::fromBase64(content.toLatin1()); 1231 int count = bytes.size()/sizeof(int); 1232 d->columnWidths.resize(count); 1233 memcpy(d->columnWidths.data(), bytes.data(), count*sizeof(int)); 1234 } else if (!preview && reader->name() == "column") { 1235 //TODO: parallelize reading of columns? 1236 reader->readNext(); 1237 QString content = reader->text().toString().trimmed(); 1238 QByteArray bytes = QByteArray::fromBase64(content.toLatin1()); 1239 1240 switch (d->mode) { 1241 case AbstractColumn::ColumnMode::Numeric: { 1242 int count = bytes.size()/sizeof(double); 1243 QVector<double> column; 1244 column.resize(count); 1245 memcpy(column.data(), bytes.data(), count*sizeof(double)); 1246 static_cast<QVector<QVector<double>>*>(d->data)->append(column); 1247 break; 1248 } 1249 case AbstractColumn::ColumnMode::Text: { 1250 int count = bytes.size()/sizeof(char); 1251 QVector<QString> column; 1252 column.resize(count); 1253 //TODO: warning (GCC8): writing to an object of type 'class QString' with no trivial copy-assignment; use copy-assignment or copy-initialization instead 1254 //memcpy(column.data(), bytes.data(), count*sizeof(QString)); 1255 //QDEBUG(" string: " << column.data()); 1256 static_cast<QVector<QVector<QString>>*>(d->data)->append(column); 1257 break; 1258 } 1259 case AbstractColumn::ColumnMode::Integer: { 1260 int count = bytes.size()/sizeof(int); 1261 QVector<int> column; 1262 column.resize(count); 1263 memcpy(column.data(), bytes.data(), count*sizeof(int)); 1264 static_cast<QVector<QVector<int>>*>(d->data)->append(column); 1265 break; 1266 } 1267 case AbstractColumn::ColumnMode::BigInt: { 1268 int count = bytes.size()/sizeof(qint64); 1269 QVector<qint64> column; 1270 column.resize(count); 1271 memcpy(column.data(), bytes.data(), count*sizeof(qint64)); 1272 static_cast<QVector<QVector<qint64>>*>(d->data)->append(column); 1273 break; 1274 } 1275 case AbstractColumn::ColumnMode::Day: 1276 case AbstractColumn::ColumnMode::Month: 1277 case AbstractColumn::ColumnMode::DateTime: { 1278 int count = bytes.size()/sizeof(QDateTime); 1279 QVector<QDateTime> column; 1280 column.resize(count); 1281 //TODO: warning (GCC8): writing to an object of type 'class QDateTime' with no trivial copy-assignment; use copy-assignment or copy-initialization instead 1282 //memcpy(column.data(), bytes.data(), count*sizeof(QDateTime)); 1283 static_cast<QVector<QVector<QDateTime>>*>(d->data)->append(column); 1284 break; 1285 } 1286 } 1287 } else { // unknown element 1288 reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString())); 1289 if (!reader->skipToEndElement()) 1290 return false; 1291 } 1292 } 1293 1294 return true; 1295 } 1296 1297 //############################################################################## 1298 //######################## Data Import ####################################### 1299 //############################################################################## 1300 int Matrix::prepareImport(std::vector<void*>& dataContainer, AbstractFileFilter::ImportMode mode, 1301 int actualRows, int actualCols, QStringList colNameList, QVector<AbstractColumn::ColumnMode> columnMode) { 1302 QDEBUG("prepareImport() rows =" << actualRows << " cols =" << actualCols); 1303 //QDEBUG(" column modes = " << columnMode); 1304 Q_UNUSED(colNameList); 1305 int columnOffset = 0; 1306 setUndoAware(false); 1307 1308 setSuppressDataChangedSignal(true); 1309 1310 // resize the matrix 1311 if (mode == AbstractFileFilter::ImportMode::Replace) { 1312 clear(); 1313 setDimensions(actualRows, actualCols); 1314 } else { 1315 if (rowCount() < actualRows) 1316 setDimensions(actualRows, actualCols); 1317 else 1318 setDimensions(rowCount(), actualCols); 1319 } 1320 1321 // data() returns a void* which is a pointer to a matrix of any data type (see ColumnPrivate.cpp) 1322 dataContainer.resize(actualCols); 1323 switch (columnMode[0]) { // only columnMode[0] is used 1324 case AbstractColumn::ColumnMode::Numeric: 1325 for (int n = 0; n < actualCols; n++) { 1326 QVector<double>* vector = &(static_cast<QVector<QVector<double>>*>(data())->operator[](n)); 1327 vector->resize(actualRows); 1328 dataContainer[n] = static_cast<void*>(vector); 1329 } 1330 d->mode = AbstractColumn::ColumnMode::Numeric; 1331 break; 1332 case AbstractColumn::ColumnMode::Integer: 1333 for (int n = 0; n < actualCols; n++) { 1334 QVector<int>* vector = &(static_cast<QVector<QVector<int>>*>(data())->operator[](n)); 1335 vector->resize(actualRows); 1336 dataContainer[n] = static_cast<void*>(vector); 1337 } 1338 d->mode = AbstractColumn::ColumnMode::Integer; 1339 break; 1340 case AbstractColumn::ColumnMode::BigInt: 1341 for (int n = 0; n < actualCols; n++) { 1342 QVector<qint64>* vector = &(static_cast<QVector<QVector<qint64>>*>(data())->operator[](n)); 1343 vector->resize(actualRows); 1344 dataContainer[n] = static_cast<void*>(vector); 1345 } 1346 d->mode = AbstractColumn::ColumnMode::BigInt; 1347 break; 1348 case AbstractColumn::ColumnMode::Text: 1349 for (int n = 0; n < actualCols; n++) { 1350 QVector<QString>* vector = &(static_cast<QVector<QVector<QString>>*>(data())->operator[](n)); 1351 vector->resize(actualRows); 1352 dataContainer[n] = static_cast<void*>(vector); 1353 } 1354 d->mode = AbstractColumn::ColumnMode::Text; 1355 break; 1356 case AbstractColumn::ColumnMode::Day: 1357 case AbstractColumn::ColumnMode::Month: 1358 case AbstractColumn::ColumnMode::DateTime: 1359 for (int n = 0; n < actualCols; n++) { 1360 QVector<QDateTime>* vector = &(static_cast<QVector<QVector<QDateTime>>*>(data())->operator[](n)); 1361 vector->resize(actualRows); 1362 dataContainer[n] = static_cast<void*>(vector); 1363 } 1364 d->mode = AbstractColumn::ColumnMode::DateTime; 1365 break; 1366 } 1367 1368 return columnOffset; 1369 } 1370 1371 void Matrix::finalizeImport(int columnOffset, int startColumn, int endColumn, const QString& dateTimeFormat, AbstractFileFilter::ImportMode importMode) { 1372 DEBUG("Matrix::finalizeImport()"); 1373 Q_UNUSED(columnOffset); 1374 Q_UNUSED(startColumn); 1375 Q_UNUSED(endColumn); 1376 Q_UNUSED(dateTimeFormat); 1377 Q_UNUSED(importMode); 1378 1379 setSuppressDataChangedSignal(false); 1380 setChanged(); 1381 setUndoAware(true); 1382 DEBUG("Matrix::finalizeImport() DONE"); 1383 }