1 /***************************************************************************
2 File : Matrix.cpp
3 Project : SciDAVis
4 Description : Matrix worksheet class
5 --------------------------------------------------------------------
6 Copyright : (C) 2006-2009 Tilman Benkert (thzs*gmx.net)
7 Copyright : (C) 2006-2009 Knut Franke (knut.franke*gmx.de)
8 Copyright : (C) 2006-2007 Ion Vasilief (ion_vasilief*yahoo.fr)
9 (replace * with @ in the email addresses)
10
11 ***************************************************************************/
12
13 /***************************************************************************
14 * *
15 * This program is free software; you can redistribute it and/or modify *
16 * it under the terms of the GNU General Public License as published by *
17 * the Free Software Foundation; either version 2 of the License, or *
18 * (at your option) any later version. *
19 * *
20 * This program is distributed in the hope that it will be useful, *
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
23 * GNU General Public License for more details. *
24 * *
25 * You should have received a copy of the GNU General Public License *
26 * along with this program; if not, write to the Free Software *
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
28 * Boston, MA 02110-1301 USA *
29 * *
30 ***************************************************************************/
31 #include "Matrix.h"
32 #include "future/matrix/MatrixView.h"
33 #include "ScriptEdit.h"
34
35 #include <QtGlobal>
36 #include <QTextStream>
37 #include <QList>
38 #include <QEvent>
39 #include <QContextMenuEvent>
40 #include <QVBoxLayout>
41 #include <QMouseEvent>
42 #include <QHeaderView>
43 #include <QDateTime>
44 #include <QApplication>
45 #include <QMessageBox>
46 #include <QVarLengthArray>
47 #include <QClipboard>
48 #include <QShortcut>
49 #include <QPrinter>
50 #include <QPrintDialog>
51 #include <QPainter>
52 #include <QLocale>
53 #include <QXmlStreamWriter>
54 #include <QtDebug>
55
56 #include <stdlib.h>
57 #include <math.h>
58 #include <stdio.h>
59
60 #include <gsl/gsl_linalg.h>
61 #include <gsl/gsl_math.h>
62
Matrix(ScriptingEnv * env,int r,int c,const QString & label,QWidget * parent,const char * name,Qt::WindowFlags f)63 Matrix::Matrix(ScriptingEnv *env, int r, int c, const QString &label, QWidget *parent,
64 const char *name, Qt::WindowFlags f)
65 : MatrixView(label, parent, name, f), scripted(env)
66 {
67 d_future_matrix = new future::Matrix(0, r, c, label);
68 init(r, c);
69 }
70
Matrix(future::Matrix * future_matrix,ScriptingEnv * env,int r,int c,const QString & label,QWidget * parent,const char * name,Qt::WindowFlags f)71 Matrix::Matrix(future::Matrix *future_matrix, ScriptingEnv *env, int r, int c, const QString &label,
72 QWidget *parent, const char *name, Qt::WindowFlags f)
73 : MatrixView(label, parent, name, f), scripted(env)
74 {
75 d_future_matrix = future_matrix;
76 init(r, c);
77 }
78
init(int,int)79 void Matrix::init(int, int)
80 {
81 MatrixView::setMatrix(d_future_matrix);
82 d_future_matrix->setView(this);
83 d_future_matrix->setNumericFormat('f');
84 d_future_matrix->setDisplayedDigits(6);
85 d_future_matrix->setCoordinates(1.0, 10.0, 1.0, 10.0);
86 dMatrix = 0;
87
88 birthdate = QLocale().toString(d_future_matrix->creationTime());
89
90 // this is not very nice but works for the moment
91 ui.gridLayout2->removeWidget(ui.formula_box);
92 delete ui.formula_box;
93 ui.formula_box = new ScriptEdit(scriptEnv, ui.formula_tab);
94 ui.formula_box->setObjectName(QString::fromUtf8("formula_box"));
95 ui.formula_box->setMinimumSize(QSize(60, 10));
96 ui.formula_box->setAcceptRichText(false);
97 ui.formula_box->setLineWrapMode(QTextEdit::WidgetWidth);
98 ui.gridLayout2->addWidget(ui.formula_box, 1, 0, 1, 3);
99
100 ui.add_cell_combobox->addItem("cell(i, j)");
101 ui.add_function_combobox->addItems(scriptEnv->mathFunctions());
102 updateFunctionDoc();
103
104 connect(ui.add_function_combobox, SIGNAL(currentIndexChanged(int)), this,
105 SLOT(updateFunctionDoc()));
106 connect(ui.button_set_formula, SIGNAL(pressed()), this, SLOT(applyFormula()));
107 connect(ui.add_function_button, SIGNAL(pressed()), this, SLOT(addFunction()));
108 connect(ui.add_cell_button, SIGNAL(pressed()), this, SLOT(addCell()));
109
110 connect(d_future_matrix, SIGNAL(columnsInserted(int, int)), this, SLOT(handleChange()));
111 connect(d_future_matrix, SIGNAL(columnsRemoved(int, int)), this, SLOT(handleChange()));
112 connect(d_future_matrix, SIGNAL(rowsInserted(int, int)), this, SLOT(handleChange()));
113 connect(d_future_matrix, SIGNAL(rowsRemoved(int, int)), this, SLOT(handleChange()));
114 connect(d_future_matrix, SIGNAL(dataChanged(int, int, int, int)), this, SLOT(handleChange()));
115 connect(d_future_matrix, SIGNAL(coordinatesChanged()), this, SLOT(handleChange()));
116 connect(d_future_matrix, SIGNAL(formulaChanged()), this, SLOT(handleChange()));
117 connect(d_future_matrix, SIGNAL(formatChanged()), this, SLOT(handleChange()));
118 connect(d_future_matrix, SIGNAL(recalculate()), this, SLOT(recalculate()));
119
120 connect(d_future_matrix, SIGNAL(aspectDescriptionChanged(const AbstractAspect *)), this,
121 SLOT(handleAspectDescriptionChange(const AbstractAspect *)));
122 }
123
~Matrix()124 Matrix::~Matrix() { }
125
handleChange()126 void Matrix::handleChange()
127 {
128 emit modifiedWindow(this);
129 }
130
cell(int row,int col)131 double Matrix::cell(int row, int col)
132 {
133 if (dMatrix)
134 return dMatrix[row][col];
135 else
136 return d_future_matrix->cell(row, col);
137 }
138
setCell(int row,int col,double value)139 void Matrix::setCell(int row, int col, double value)
140 {
141 d_future_matrix->setCell(row, col, value);
142 }
143
setCells(const QVector<qreal> & data)144 void Matrix::setCells(const QVector<qreal> &data)
145 {
146 d_future_matrix->setCells(data);
147 }
148
text(int row,int col)149 QString Matrix::text(int row, int col)
150 {
151 return d_future_matrix->text(row, col);
152 }
153
setText(int row,int col,const QString & new_text)154 void Matrix::setText(int row, int col, const QString &new_text)
155 {
156 bool ok = true;
157 QLocale locale;
158 double res = locale.toDouble(new_text, &ok);
159 if (ok)
160 d_future_matrix->setCell(row, col, res);
161 else {
162 Script *script = scriptEnv->newScript(new_text, this,
163 QString("<%1_%2_%3>").arg(name()).arg(row).arg(col));
164 connect(script, SIGNAL(error(const QString &, const QString &, int)), scriptEnv,
165 SIGNAL(error(const QString &, const QString &, int)));
166
167 script->setInt(row + 1, "row");
168 script->setInt(row + 1, "i");
169 script->setInt(col + 1, "col");
170 script->setInt(col + 1, "j");
171
172 QVariant ret = script->eval();
173 setCell(row, col, ret.toDouble());
174 }
175 }
176
setCoordinates(double xs,double xe,double ys,double ye)177 void Matrix::setCoordinates(double xs, double xe, double ys, double ye)
178 {
179 d_future_matrix->setCoordinates(xs, xe, ys, ye);
180 }
181
saveToString(const QString & geometry)182 QString Matrix::saveToString(const QString &geometry)
183 {
184 QString s = "<matrix>\n";
185 QString xml;
186 QXmlStreamWriter writer(&xml);
187 d_future_matrix->save(&writer);
188 s += QString::number(xml.length()) + "\n"; // this is need in case there are newlines in the XML
189 s += xml + "\n";
190 s += geometry + "\n";
191 s += "</matrix>\n";
192 return s;
193
194 #if 0
195 QString s = "<matrix>\n";
196 s += QString(name()) + "\t";
197 s += QString::number(numRows())+"\t";
198 s += QString::number(numCols())+"\t";
199 s += birthDate() + "\n";
200 s += info;
201 s += "ColWidth\t" + QString::number(columnWidth(0))+"\n";
202 s += "<formula>\n" + formula() + "\n</formula>\n";
203 s += "TextFormat\t" + QString(d_future_matrix->numericFormat()) + "\t" + QString::number(d_future_matrix->displayedDigits()) + "\n";
204 s += "WindowLabel\t" + windowLabel() + "\t" + QString::number(captionPolicy()) + "\n";
205 s += "Coordinates\t" + QString::number(xStart(),'g',15) + "\t" +QString::number(xEnd(),'g',15) + "\t";
206 s += QString::number(yStart(),'g',15) + "\t" + QString::number(yEnd(),'g',15) + "\n";
207 s += saveText();
208 s +="</matrix>\n";
209 return s;
210 #endif
211 }
212
saveAsTemplate(const QString & info)213 QString Matrix::saveAsTemplate(const QString &info)
214 {
215 QString s = "<matrix>\t";
216 s += QString::number(numRows()) + "\t";
217 s += QString::number(numCols()) + "\n";
218 s += info;
219 s += "ColWidth\t" + QString::number(columnWidth(0)) + "\n";
220 s += "<formula>\n" + formula() + "\n</formula>\n";
221 s += "TextFormat\t" + QString(d_future_matrix->numericFormat()) + "\t"
222 + QString::number(d_future_matrix->displayedDigits()) + "\n";
223 s += "Coordinates\t" + QString::number(xStart(), 'g', 15) + "\t"
224 + QString::number(xEnd(), 'g', 15) + "\t";
225 s += QString::number(yStart(), 'g', 15) + "\t" + QString::number(yEnd(), 'g', 15) + "\n";
226 s += "</matrix>\n";
227 return s;
228 }
229
saveText()230 QString Matrix::saveText()
231 {
232 QString out_text = "<data>\n";
233 int cols = d_future_matrix->columnCount();
234 for (int i = 0; i < d_future_matrix->rowCount(); i++) {
235 out_text += QString::number(i) + "\t";
236 for (int j = 0; j < cols - 1; j++)
237 out_text += QString::number(cell(i, j), 'e', 16) + "\t";
238
239 out_text += QString::number(cell(i, cols - 1), 'e', 16) + "\n";
240 }
241 return out_text + "</data>\n";
242 }
243
setFormula(const QString & s)244 void Matrix::setFormula(const QString &s)
245 {
246 d_future_matrix->setFormula(s);
247 }
248
formula()249 QString Matrix::formula()
250 {
251 return d_future_matrix->formula();
252 }
253
setNumericFormat(const QChar & f,int prec)254 void Matrix::setNumericFormat(const QChar &f, int prec)
255 {
256 if (d_future_matrix->numericFormat() == f && d_future_matrix->displayedDigits() == prec)
257 return;
258
259 d_future_matrix->setNumericFormat(f.toLatin1());
260 d_future_matrix->setDisplayedDigits(prec);
261
262 emit modifiedWindow(this);
263 }
264
setTextFormat(const QChar & format,int precision)265 void Matrix::setTextFormat(const QChar &format, int precision)
266 {
267 d_future_matrix->setNumericFormat(format.toLatin1());
268 d_future_matrix->setDisplayedDigits(precision);
269 }
270
setColumnsWidth(int width)271 void Matrix::setColumnsWidth(int width)
272 {
273 for (int i = 0; i < d_future_matrix->columnCount(); i++)
274 setColumnWidth(i, width);
275 }
276
setDimensions(int rows,int cols)277 void Matrix::setDimensions(int rows, int cols)
278 {
279 d_future_matrix->setDimensions(rows, cols);
280 }
281
numRows()282 int Matrix::numRows()
283 {
284 return d_future_matrix->rowCount();
285 }
286
setNumRows(int rows)287 void Matrix::setNumRows(int rows)
288 {
289 d_future_matrix->setDimensions(rows, d_future_matrix->columnCount());
290 }
291
numCols()292 int Matrix::numCols()
293 {
294 return d_future_matrix->columnCount();
295 }
296
setNumCols(int cols)297 void Matrix::setNumCols(int cols)
298 {
299 d_future_matrix->setDimensions(d_future_matrix->rowCount(), cols);
300 }
301
determinant()302 double Matrix::determinant()
303 {
304 int rows = numRows();
305 int cols = numCols();
306
307 if (rows != cols) {
308 QMessageBox::critical(0, tr("Error"), tr("Calculation failed, the matrix is not square!"));
309 return GSL_POSINF;
310 }
311
312 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
313
314 gsl_matrix *A = gsl_matrix_alloc(rows, cols);
315 int i;
316 for (i = 0; i < rows; i++)
317 for (int j = 0; j < cols; j++)
318 gsl_matrix_set(A, i, j, cell(i, j));
319
320 gsl_permutation *p = gsl_permutation_alloc(rows);
321 gsl_linalg_LU_decomp(A, p, &i);
322
323 double det = gsl_linalg_LU_det(A, i);
324
325 gsl_matrix_free(A);
326 gsl_permutation_free(p);
327
328 QApplication::restoreOverrideCursor();
329 return det;
330 }
331
invert()332 void Matrix::invert()
333 {
334 int rows = numRows();
335 int cols = numCols();
336
337 if (rows != cols) {
338 QMessageBox::critical(0, tr("Error"), tr("Inversion failed, the matrix is not square!"));
339 return;
340 }
341
342 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
343
344 gsl_matrix *A = gsl_matrix_alloc(rows, cols);
345 int i;
346 for (i = 0; i < rows; i++) {
347 for (int j = 0; j < cols; j++)
348 gsl_matrix_set(A, i, j, cell(i, j));
349 }
350
351 gsl_permutation *p = gsl_permutation_alloc(cols);
352 gsl_linalg_LU_decomp(A, p, &i);
353
354 gsl_matrix *inverse = gsl_matrix_alloc(rows, cols);
355 gsl_linalg_LU_invert(A, p, inverse);
356
357 gsl_matrix_free(A);
358 gsl_permutation_free(p);
359
360 this->blockSignals(true);
361 for (i = 0; i < rows; i++) {
362 for (int j = 0; j < cols; j++)
363 setCell(i, j, gsl_matrix_get(inverse, i, j));
364 }
365 this->blockSignals(false);
366
367 gsl_matrix_free(inverse);
368 QApplication::restoreOverrideCursor();
369 emit modifiedWindow(this);
370 }
371
transpose()372 void Matrix::transpose()
373 {
374 d_future_matrix->transpose();
375 }
376
saveCellsToMemory()377 void Matrix::saveCellsToMemory()
378 {
379 int rows = numRows();
380 int cols = numCols();
381 dMatrix = allocateMatrixData(rows, cols);
382 for (int i = 0; i < rows; i++)
383 for (int j = 0; j < cols; j++)
384 dMatrix[i][j] = d_future_matrix->cell(i, j);
385 }
386
forgetSavedCells()387 void Matrix::forgetSavedCells()
388 {
389 freeMatrixData(dMatrix, numRows());
390 dMatrix = 0;
391 }
392
recalculate()393 bool Matrix::recalculate()
394 {
395 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
396 Script *script = scriptEnv->newScript(formula(), this, QString("<%1>").arg(name()));
397 connect(script, SIGNAL(error(const QString &, const QString &, int)), scriptEnv,
398 SIGNAL(error(const QString &, const QString &, int)));
399 connect(script, SIGNAL(print(const QString &)), scriptEnv, SIGNAL(print(const QString &)));
400 if (!script->compile()) {
401 QApplication::restoreOverrideCursor();
402 return false;
403 }
404
405 this->blockSignals(true);
406
407 int startRow = firstSelectedRow(false);
408 int endRow = lastSelectedRow(false);
409 int startCol = firstSelectedColumn(false);
410 int endCol = lastSelectedColumn(false);
411
412 QVariant ret;
413 saveCellsToMemory();
414 double dx = fabs(xEnd() - xStart()) / (double)(numRows() - 1);
415 double dy = fabs(yEnd() - yStart()) / (double)(numCols() - 1);
416 std::pair<double, bool> unsetValue(std::numeric_limits<double>::quiet_NaN(), false);
417 std::vector<std::vector<std::pair<double, bool>>> calculatedValues(
418 endRow - startRow + 1,
419 std::vector<std::pair<double, bool>>(endCol - startCol + 1, unsetValue));
420 for (int row = startRow; row <= endRow; row++)
421 for (int col = startCol; col <= endCol; col++) {
422 if (!isCellSelected(row, col))
423 continue;
424 script->setInt(row + 1, "i");
425 script->setInt(row + 1, "row");
426 script->setDouble(yStart() + row * dy, "y");
427 script->setInt(col + 1, "j");
428 script->setInt(col + 1, "col");
429 script->setDouble(xStart() + col * dx, "x");
430 ret = script->eval();
431 if (!ret.isValid()) {
432 forgetSavedCells();
433 blockSignals(false);
434 emit modifiedWindow(this);
435 QApplication::restoreOverrideCursor();
436 return false;
437 }
438 calculatedValues[row - startRow][col - startCol] = std::make_pair(ret.toDouble(), true);
439 }
440 d_future_matrix->setCells(startRow, startCol, calculatedValues);
441 forgetSavedCells();
442
443 blockSignals(false);
444 emit modifiedWindow(this);
445 QApplication::restoreOverrideCursor();
446 return true;
447 }
448
clearSelection()449 void Matrix::clearSelection()
450 {
451 d_future_matrix->clearSelectedCells();
452 }
453
copySelection()454 void Matrix::copySelection()
455 {
456 d_future_matrix->copySelection();
457 }
458
cutSelection()459 void Matrix::cutSelection()
460 {
461 copySelection();
462 clearSelection();
463 }
464
rowsSelected()465 bool Matrix::rowsSelected()
466 {
467 for (int i = 0; i < numRows(); i++) {
468 if (this->isRowSelected(i, true))
469 return true;
470 }
471 return false;
472 }
473
deleteSelectedRows()474 void Matrix::deleteSelectedRows()
475 {
476 d_future_matrix->removeSelectedRows();
477 }
478
insertColumn()479 void Matrix::insertColumn()
480 {
481 d_future_matrix->insertEmptyColumns();
482 }
483
columnsSelected()484 bool Matrix::columnsSelected()
485 {
486 for (int i = 0; i < numCols(); i++) {
487 if (this->isColumnSelected(i, true))
488 return true;
489 }
490 return false;
491 }
492
deleteSelectedColumns()493 void Matrix::deleteSelectedColumns()
494 {
495 d_future_matrix->removeSelectedColumns();
496 }
497
numSelectedRows()498 int Matrix::numSelectedRows()
499 {
500 int r = 0;
501 for (int i = 0; i < numRows(); i++)
502 if (this->isRowSelected(i, true))
503 r++;
504 return r;
505 }
506
numSelectedColumns()507 int Matrix::numSelectedColumns()
508 {
509 int c = 0;
510 for (int i = 0; i < numCols(); i++)
511 if (this->isColumnSelected(i, true))
512 c++;
513 return c;
514 }
515
insertRow()516 void Matrix::insertRow()
517 {
518 d_future_matrix->insertEmptyRows();
519 }
520
pasteSelection()521 void Matrix::pasteSelection()
522 {
523 d_future_matrix->pasteIntoSelection();
524 }
525
customEvent(QEvent * e)526 void Matrix::customEvent(QEvent *e)
527 {
528 if (e->type() == SCRIPTING_CHANGE_EVENT)
529 scriptingChangeEvent((ScriptingChangeEvent *)e);
530 }
531
closeEvent(QCloseEvent * e)532 void Matrix::closeEvent(QCloseEvent *e)
533 {
534 if (askOnClose) {
535 switch (QMessageBox::information(this, tr("SciDAVis"),
536 tr("Do you want to hide or delete") + "<p><b>'"
537 + objectName() + "'</b> ?",
538 tr("Delete"), tr("Hide"), tr("Cancel"), 0, 2)) {
539 case 0:
540 e->accept();
541 d_future_matrix->remove();
542 return;
543
544 case 1:
545 e->ignore();
546 emit hiddenWindow(this);
547 break;
548
549 case 2:
550 e->ignore();
551 break;
552 }
553 } else {
554 e->accept();
555 d_future_matrix->remove();
556 return;
557 }
558 }
559
exportPDF(const QString & fileName)560 void Matrix::exportPDF(const QString &fileName)
561 {
562 print(fileName);
563 }
564
print()565 void Matrix::print()
566 {
567 print(QString());
568 }
569
print(const QString & fileName)570 void Matrix::print(const QString &fileName)
571 {
572 QPrinter printer;
573 printer.setColorMode(QPrinter::GrayScale);
574
575 if (!fileName.isEmpty()) {
576 printer.setCreator("SciDAVis");
577 printer.setOutputFormat(QPrinter::PdfFormat);
578 printer.setOutputFileName(fileName);
579 } else {
580 QPrintDialog printDialog(&printer);
581 if (printDialog.exec() != QDialog::Accepted)
582 return;
583 }
584
585 printer.setFullPage(true);
586 QPainter p;
587 if (!p.begin(&printer))
588 return; // paint on printer
589 int dpiy = printer.logicalDpiY();
590 const int margin = (int)((1 / 2.54) * dpiy); // 1 cm margins
591
592 QHeaderView *vHeader = d_view_widget->verticalHeader();
593
594 int rows = numRows();
595 int cols = numCols();
596 int height = margin;
597 int i, vertHeaderWidth = vHeader->width();
598 int right = margin + vertHeaderWidth;
599
600 // print header
601 p.setFont(QFont());
602 QString header_label = d_view_widget->model()->headerData(0, Qt::Horizontal).toString();
603 QRect br = p.boundingRect(br, Qt::AlignCenter, header_label);
604 p.drawLine(right, height, right, height + br.height());
605 QRect tr(br);
606
607 for (i = 0; i < cols; i++) {
608 int w = columnWidth(i);
609 tr.setTopLeft(QPoint(right, height));
610 tr.setWidth(w);
611 tr.setHeight(br.height());
612 header_label = d_view_widget->model()->headerData(i, Qt::Horizontal).toString();
613 p.drawText(tr, Qt::AlignCenter, header_label);
614 right += w;
615 p.drawLine(right, height, right, height + tr.height());
616
617 if (right >= printer.width() - 2 * margin)
618 break;
619 }
620
621 p.drawLine(margin + vertHeaderWidth, height, right - 1, height); // first horizontal line
622 height += tr.height();
623 p.drawLine(margin, height, right - 1, height);
624
625 // print table values
626 for (i = 0; i < rows; i++) {
627 right = margin;
628 QString cell_text = d_view_widget->model()->headerData(i, Qt::Vertical).toString() + "\t";
629 tr = p.boundingRect(tr, Qt::AlignCenter, cell_text);
630 p.drawLine(right, height, right, height + tr.height());
631
632 br.setTopLeft(QPoint(right, height));
633 br.setWidth(vertHeaderWidth);
634 br.setHeight(tr.height());
635 p.drawText(br, Qt::AlignCenter, cell_text);
636 right += vertHeaderWidth;
637 p.drawLine(right, height, right, height + tr.height());
638
639 for (int j = 0; j < cols; j++) {
640 int w = columnWidth(j);
641 cell_text = text(i, j) + "\t";
642 tr = p.boundingRect(tr, Qt::AlignCenter, cell_text);
643 br.setTopLeft(QPoint(right, height));
644 br.setWidth(w);
645 br.setHeight(tr.height());
646 p.drawText(br, Qt::AlignCenter, cell_text);
647 right += w;
648 p.drawLine(right, height, right, height + tr.height());
649
650 if (right >= printer.width() - 2 * margin)
651 break;
652 }
653 height += br.height();
654 p.drawLine(margin, height, right - 1, height);
655
656 if (height >= printer.height() - margin) {
657 printer.newPage();
658 height = margin;
659 p.drawLine(margin, height, right, height);
660 }
661 }
662 }
663
range(double * min,double * max)664 void Matrix::range(double *min, double *max)
665 {
666 double d_min = cell(0, 0);
667 double d_max = d_min;
668
669 for (int i = 0; i < numRows(); i++) {
670 for (int j = 0; j < numCols(); j++) {
671 double aux = cell(i, j);
672 if (aux <= d_min)
673 d_min = aux;
674
675 if (aux >= d_max)
676 d_max = aux;
677 }
678 }
679
680 *min = d_min;
681 *max = d_max;
682 }
683
allocateMatrixData(int rows,int columns)684 double **Matrix::allocateMatrixData(int rows, int columns)
685 {
686 double **data = new double *[rows];
687 for (int i = 0; i < rows; ++i)
688 data[i] = new double[columns];
689
690 return data;
691 }
692
freeMatrixData(double ** data,int rows)693 void Matrix::freeMatrixData(double **data, int rows)
694 {
695 for (int i = 0; i < rows; i++)
696 delete[] data[i];
697
698 delete[] data;
699 }
700
updateDecimalSeparators()701 void Matrix::updateDecimalSeparators()
702 {
703 this->update();
704 }
705
copy(Matrix * m)706 void Matrix::copy(Matrix *m)
707 {
708 if (!m)
709 return;
710
711 d_future_matrix->copy(m->d_future_matrix);
712 }
713
fromImage(const QImage & image,ScriptingEnv * env)714 Matrix *Matrix::fromImage(const QImage &image, ScriptingEnv *env)
715 {
716 future::Matrix *fm = future::Matrix::fromImage(image);
717 if (!fm)
718 return NULL;
719 return new Matrix(fm, env, image.height(), image.width(), tr("Matrix %1").arg(1));
720 }
721
applyFormula()722 void Matrix::applyFormula()
723 {
724 QApplication::setOverrideCursor(Qt::WaitCursor);
725 d_future_matrix->beginMacro(tr("%1: apply formula to selection").arg(name()));
726
727 setFormula(ui.formula_box->toPlainText());
728 recalculate();
729
730 d_future_matrix->endMacro();
731 QApplication::restoreOverrideCursor();
732 }
733
addFunction()734 void Matrix::addFunction()
735 {
736 static_cast<ScriptEdit *>(ui.formula_box)
737 ->insertFunction(ui.add_function_combobox->currentText());
738 }
739
addCell()740 void Matrix::addCell()
741 {
742 ui.formula_box->insertPlainText(ui.add_cell_combobox->currentText());
743 }
744
updateFunctionDoc()745 void Matrix::updateFunctionDoc()
746 {
747 ui.add_function_combobox->setToolTip(
748 scriptEnv->mathFunctionDoc(ui.add_function_combobox->currentText()));
749 }
750
handleAspectDescriptionChange(const AbstractAspect * aspect)751 void Matrix::handleAspectDescriptionChange(const AbstractAspect *aspect)
752 {
753 if (aspect != d_future_matrix)
754 return;
755 setObjectName(d_future_matrix->name());
756 updateCaption();
757 }
758