1
/***************************************************************************
4
Description : Aspect providing a spreadsheet to manage MxN matrix data
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)
11
***************************************************************************/
13
/***************************************************************************
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. *
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. *
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 *
30
***************************************************************************/
31
#include "matrix/future_Matrix.h"
33
#include "core/AbstractScript.h"
34
#include "core/future_Folder.h"
35
#include "matrixcommands.h"
36
#include "lib/ActionManager.h"
37
#include "lib/XmlStreamReader.h"
47
#include <gsl/gsl_linalg.h>
48
#include <gsl/gsl_math.h>
52
#define WAIT_CURSOR QApplication::setOverrideCursor(QCursor(Qt::WaitCursor))
53
#define RESET_CURSOR QApplication::restoreOverrideCursor()
55
int Matrix::default_column_width = 120;
56
int Matrix::default_row_height = 20;
58
#ifndef LEGACY_CODE_0_2_x
59
Matrix::Matrix(AbstractScriptingEngine *engine, int rows, int cols, const QString& name)
60
: AbstractPart(name), d_plot_menu(0), scripted(engine)
62
Matrix::Matrix(void *, int rows, int cols, const QString& name)
63
: AbstractPart(name), d_plot_menu(0)
66
d_matrix_private = new Private(this);
67
// set initial number of rows and columns
76
#ifndef LEGACY_CODE_0_2_x
78
: AbstractPart("temp"), scripted(0)
81
: AbstractPart("temp")
93
void Matrix::setView(MatrixView * view)
97
connect(d_view, SIGNAL(controlTabBarStatusChanged(bool)), this, SLOT(adjustTabBarAction(bool)));
98
adjustTabBarAction(true);
101
QWidget *Matrix::view()
103
#ifndef LEGACY_CODE_0_2_x
106
d_view = new MatrixView(this);
108
connect(d_view, SIGNAL(controlTabBarStatusChanged(bool)), this, SLOT(adjustTabBarAction(bool)));
109
adjustTabBarAction(true);
112
Q_ASSERT(d_view != NULL);
117
void Matrix::insertColumns(int before, int count)
119
if( count < 1 || before < 0 || before > columnCount()) return;
121
beginMacro(QObject::tr("%1: insert %2 column(s)").arg(name()).arg(count));
122
exec(new MatrixInsertColumnsCmd(d_matrix_private, before, count));
127
void Matrix::removeColumns(int first, int count)
129
if( count < 1 || first < 0 || first+count > columnCount()) return;
131
beginMacro(QObject::tr("%1: remove %2 column(s)").arg(name()).arg(count));
132
exec(new MatrixRemoveColumnsCmd(d_matrix_private, first, count));
137
void Matrix::removeRows(int first, int count)
139
if( count < 1 || first < 0 || first+count > rowCount()) return;
141
beginMacro(QObject::tr("%1: remove %2 row(s)").arg(name()).arg(count));
142
exec(new MatrixRemoveRowsCmd(d_matrix_private, first, count));
147
void Matrix::insertRows(int before, int count)
149
if( count < 1 || before < 0 || before > rowCount()) return;
151
beginMacro(QObject::tr("%1: insert %2 row(s)").arg(name()).arg(count));
152
exec(new MatrixInsertRowsCmd(d_matrix_private, before, count));
157
void Matrix::setDimensions(int rows, int cols)
159
if( (rows < 0) || (cols < 0 ) || (rows == rowCount() && cols == columnCount()) ) return;
161
beginMacro(QObject::tr("%1: set matrix size to %2x%3").arg(name()).arg(rows).arg(cols));
162
int col_diff = cols - columnCount();
163
int row_diff = rows - rowCount();
165
exec(new MatrixInsertColumnsCmd(d_matrix_private, columnCount(), col_diff));
166
else if(col_diff < 0)
167
exec(new MatrixRemoveColumnsCmd(d_matrix_private, columnCount()+col_diff, -col_diff));
169
exec(new MatrixInsertRowsCmd(d_matrix_private, rowCount(), row_diff));
170
else if(row_diff < 0)
171
exec(new MatrixRemoveRowsCmd(d_matrix_private, rowCount()+row_diff, -row_diff));
176
int Matrix::columnCount() const
178
return d_matrix_private->columnCount();
181
int Matrix::rowCount() const
183
return d_matrix_private->rowCount();
189
beginMacro(QObject::tr("%1: clear").arg(name()));
190
exec(new MatrixClearCmd(d_matrix_private));
195
double Matrix::cell(int row, int col) const
197
if(row < 0 || row >= rowCount() ||
198
col < 0 || col >= columnCount()) return 0.0;
199
return d_matrix_private->cell(row, col);
202
void Matrix::cutSelection()
205
int first = d_view->firstSelectedRow();
206
if( first < 0 ) return;
209
beginMacro(tr("%1: cut selected cell(s)").arg(name()));
211
clearSelectedCells();
216
void Matrix::copySelection()
219
int first_col = d_view->firstSelectedColumn(false);
220
if(first_col == -1) return;
221
int last_col = d_view->lastSelectedColumn(false);
222
if(last_col == -2) return;
223
int first_row = d_view->firstSelectedRow(false);
224
if(first_row == -1) return;
225
int last_row = d_view->lastSelectedRow(false);
226
if(last_row == -2) return;
227
int cols = last_col - first_col +1;
228
int rows = last_row - first_row +1;
233
for(int r=0; r<rows; r++)
235
for(int c=0; c<cols; c++)
237
if(d_view->isCellSelected(first_row + r, first_col + c))
238
output_str += QLocale().toString(cell(first_row + r, first_col + c),
239
d_matrix_private->numericFormat(), 16); // copy with max. precision
246
QApplication::clipboard()->setText(output_str);
250
void Matrix::pasteIntoSelection()
253
if(columnCount() < 1 || rowCount() < 1) return;
256
beginMacro(tr("%1: paste from clipboard").arg(name()));
257
const QMimeData * mime_data = QApplication::clipboard()->mimeData();
259
int first_col = d_view->firstSelectedColumn(false);
260
int last_col = d_view->lastSelectedColumn(false);
261
int first_row = d_view->firstSelectedRow(false);
262
int last_row = d_view->lastSelectedRow(false);
263
int input_row_count = 0;
264
int input_col_count = 0;
267
if(mime_data->hasFormat("text/plain"))
269
QString input_str = QString(mime_data->data("text/plain"));
270
QList< QStringList > cell_texts;
271
QStringList input_rows(input_str.split("\n"));
272
input_row_count = input_rows.count();
274
for(int i=0; i<input_row_count; i++)
276
cell_texts.append(input_rows.at(i).split("\t"));
277
if(cell_texts.at(i).count() > input_col_count) input_col_count = cell_texts.at(i).count();
280
if( (first_col == -1 || first_row == -1) ||
281
(last_row == first_row && last_col == first_col) )
282
// if the is no selection or only one cell selected, the
283
// selection will be expanded to the needed size from the current cell
285
int current_row, current_col;
286
d_view->getCurrentCell(¤t_row, ¤t_col);
287
if(current_row == -1) current_row = 0;
288
if(current_col == -1) current_col = 0;
289
d_view->setCellSelected(current_row, current_col);
290
first_col = current_col;
291
first_row = current_row;
292
last_row = first_row + input_row_count -1;
293
last_col = first_col + input_col_count -1;
294
// resize the matrix if necessary
295
if(last_col >= columnCount())
296
appendColumns(last_col+1-columnCount());
297
if(last_row >= rowCount())
298
appendRows(last_row+1-rowCount());
299
// select the rectangle to be pasted in
300
d_view->setCellsSelected(first_row, first_col, last_row, last_col);
303
rows = last_row - first_row + 1;
304
cols = last_col - first_col + 1;
305
for(int r=0; r<rows && r<input_row_count; r++)
307
for(int c=0; c<cols && c<input_col_count; c++)
309
if(d_view->isCellSelected(first_row + r, first_col + c) && (c < cell_texts.at(r).count()) )
311
setCell(first_row + r, first_col + c, cell_texts.at(r).at(c).toDouble());
320
void Matrix::insertEmptyColumns()
323
int first = d_view->firstSelectedColumn();
324
int last = d_view->lastSelectedColumn();
325
if( first < 0 ) return;
326
int count, current = first;
329
beginMacro(QObject::tr("%1: insert empty column(s)").arg(name()));
330
while( current <= last )
333
while( current <= last && d_view->isColumnSelected(current) ) current++;
334
count = current-first;
335
insertColumns(first, count);
338
while( current <= last && !d_view->isColumnSelected(current) ) current++;
345
void Matrix::removeSelectedColumns()
348
int first = d_view->firstSelectedColumn();
349
int last = d_view->lastSelectedColumn();
350
if( first < 0 ) return;
353
beginMacro(QObject::tr("%1: remove selected column(s)").arg(name()));
354
for(int i=last; i>=first; i--)
355
if(d_view->isColumnSelected(i, false)) removeColumns(i, 1);
360
void Matrix::clearSelectedColumns()
364
beginMacro(QObject::tr("%1: clear selected column(s)").arg(name()));
365
for(int i=0; i<columnCount(); i++)
366
if(d_view->isColumnSelected(i, false))
367
exec(new MatrixClearColumnCmd(d_matrix_private, i));
372
void Matrix::insertEmptyRows()
375
int first = d_view->firstSelectedRow();
376
int last = d_view->lastSelectedRow();
377
int count, current = first;
379
if( first < 0 ) return;
382
beginMacro(QObject::tr("%1: insert empty rows(s)").arg(name()));
383
while( current <= last )
386
while( current <= last && d_view->isRowSelected(current) ) current++;
387
count = current-first;
388
insertRows(first, count);
391
while( current <= last && !d_view->isRowSelected(current) ) current++;
398
void Matrix::removeSelectedRows()
401
int first = d_view->firstSelectedRow();
402
int last = d_view->lastSelectedRow();
403
if( first < 0 ) return;
406
beginMacro(QObject::tr("%1: remove selected rows(s)").arg(name()));
407
for(int i=last; i>=first; i--)
408
if(d_view->isRowSelected(i, false)) removeRows(i, 1);
413
void Matrix::clearSelectedRows()
416
int first = d_view->firstSelectedRow();
417
int last = d_view->lastSelectedRow();
418
if( first < 0 ) return;
421
beginMacro(QObject::tr("%1: clear selected rows(s)").arg(name()));
422
for(int i=first; i<=last; i++)
424
if(d_view->isRowSelected(i))
425
for(int j=0; j<columnCount(); j++)
426
exec(new MatrixSetCellValueCmd(d_matrix_private, i, j, 0.0));
432
void Matrix::clearSelectedCells()
435
int first_row = d_view->firstSelectedRow();
436
int last_row = d_view->lastSelectedRow();
437
if( first_row < 0 ) return;
438
int first_col = d_view->firstSelectedColumn();
439
int last_col = d_view->lastSelectedColumn();
440
if( first_col < 0 ) return;
443
beginMacro(tr("%1: clear selected cell(s)").arg(name()));
444
for(int i=first_row; i<=last_row; i++)
445
for(int j=first_col; j<=last_col; j++)
446
if(d_view->isCellSelected(i, j))
447
exec(new MatrixSetCellValueCmd(d_matrix_private, i, j, 0.0));
452
QMenu *Matrix::createContextMenu() const
454
QMenu *menu = AbstractPart::createContextMenu();
456
menu->addSeparator();
458
menu->addAction(action_duplicate);
459
// TODO menu->addAction( ....
464
QMenu * Matrix::createSelectionMenu(QMenu * append_to)
466
QMenu * menu = append_to;
470
menu->addAction(action_cut_selection);
471
menu->addAction(action_copy_selection);
472
menu->addAction(action_paste_into_selection);
473
menu->addAction(action_clear_selection);
479
QMenu * Matrix::createColumnMenu(QMenu * append_to)
481
QMenu * menu = append_to;
485
menu->addAction(action_insert_columns);
486
menu->addAction(action_remove_columns);
487
menu->addAction(action_clear_columns);
488
menu->addSeparator();
489
menu->addAction(action_edit_coordinates);
494
QMenu * Matrix::createMatrixMenu(QMenu * append_to)
496
QMenu * menu = append_to;
500
menu->addAction(action_toggle_tabbar);
501
menu->addSeparator();
502
menu->addAction(action_select_all);
503
menu->addAction(action_clear_matrix);
504
menu->addSeparator();
505
menu->addAction(action_set_formula);
506
menu->addAction(action_recalculate);
507
menu->addSeparator();
508
menu->addAction(action_edit_format);
509
menu->addSeparator();
510
menu->addAction(action_go_to_cell);
515
QMenu * Matrix::createRowMenu(QMenu * append_to)
517
QMenu * menu = append_to;
521
menu->addAction(action_insert_rows);
522
menu->addAction(action_remove_rows);
523
menu->addAction(action_clear_rows);
524
menu->addSeparator();
525
menu->addAction(action_edit_coordinates);
531
void Matrix::createActions()
535
// selection related actions
536
action_cut_selection = new QAction(QIcon(QPixmap(":/cut.xpm")), tr("Cu&t"), this);
537
actionManager()->addAction(action_cut_selection, "cut_selection");
539
action_copy_selection = new QAction(QIcon(QPixmap(":/copy.xpm")), tr("&Copy"), this);
540
actionManager()->addAction(action_copy_selection, "copy_selection");
542
action_paste_into_selection = new QAction(QIcon(QPixmap(":/paste.xpm")), tr("Past&e"), this);
543
actionManager()->addAction(action_paste_into_selection, "paste_into_selection");
545
icon_temp = new QIcon();
546
icon_temp->addPixmap(QPixmap(":/16x16/clear.png"));
547
icon_temp->addPixmap(QPixmap(":/32x32/clear.png"));
548
action_clear_selection = new QAction(*icon_temp, tr("Clea&r","clear selection"), this);
549
actionManager()->addAction(action_clear_selection, "clear_selection");
552
// matrix related actions
553
icon_temp = new QIcon();
554
icon_temp->addPixmap(QPixmap(":/16x16/fx.png"));
555
icon_temp->addPixmap(QPixmap(":/32x32/fx.png"));
556
action_set_formula = new QAction(*icon_temp, tr("Assign &Formula"), this);
557
action_set_formula->setShortcut(tr("Alt+Q"));
558
actionManager()->addAction(action_set_formula, "set_formula");
561
icon_temp = new QIcon();
562
icon_temp->addPixmap(QPixmap(":/16x16/recalculate.png"));
563
icon_temp->addPixmap(QPixmap(":/32x32/recalculate.png"));
564
action_recalculate = new QAction(*icon_temp, tr("Recalculate"), this);
565
action_recalculate->setShortcut(tr("Ctrl+Return"));
566
actionManager()->addAction(action_recalculate, "recalculate");
569
icon_temp = new QIcon();
570
icon_temp->addPixmap(QPixmap(":/16x16/table_options.png"));
571
icon_temp->addPixmap(QPixmap(":/32x32/table_options.png"));
572
action_toggle_tabbar = new QAction(*icon_temp, QString("Show/Hide Controls"), this); // show/hide control tabs
573
action_toggle_tabbar->setShortcut(tr("F12"));
574
actionManager()->addAction(action_toggle_tabbar, "toggle_tabbar");
577
icon_temp = new QIcon();
578
icon_temp->addPixmap(QPixmap(":/16x16/select_all.png"));
579
icon_temp->addPixmap(QPixmap(":/32x32/select_all.png"));
580
action_select_all = new QAction(*icon_temp, tr("Select All"), this);
581
actionManager()->addAction(action_select_all, "select_all");
584
icon_temp = new QIcon();
585
icon_temp->addPixmap(QPixmap(":/16x16/clear_table.png"));
586
icon_temp->addPixmap(QPixmap(":/32x32/clear_table.png"));
587
action_clear_matrix = new QAction(*icon_temp, tr("Clear Matrix"), this);
588
actionManager()->addAction(action_clear_matrix, "clear_matrix");
591
icon_temp = new QIcon();
592
icon_temp->addPixmap(QPixmap(":/16x16/go_to_cell.png"));
593
icon_temp->addPixmap(QPixmap(":/32x32/go_to_cell.png"));
594
action_go_to_cell = new QAction(*icon_temp, tr("&Go to Cell"), this);
595
action_go_to_cell->setShortcut(tr("Ctrl+Alt+G"));
596
actionManager()->addAction(action_go_to_cell, "go_to_cell");
599
action_transpose = new QAction(tr("&Transpose"), this);
600
actionManager()->addAction(action_transpose, "transpose");
602
action_mirror_horizontally = new QAction(tr("Mirror &Horizontally"), this);
603
actionManager()->addAction(action_mirror_horizontally, "mirror_horizontally");
605
action_mirror_vertically = new QAction(tr("Mirror &Vertically"), this);
606
actionManager()->addAction(action_mirror_vertically, "mirror_vertically");
608
action_import_image = new QAction(tr("&Import Image", "import image as matrix"), this);
609
actionManager()->addAction(action_import_image, "import_image");
611
action_duplicate = new QAction(QIcon(QPixmap(":/duplicate.xpm")), tr("&Duplicate", "duplicate matrix"), this);
612
actionManager()->addAction(action_duplicate, "duplicate");
614
action_dimensions_dialog = new QAction(QIcon(QPixmap(":/resize.xpm")), tr("&Dimensions", "matrix size"), this);
615
actionManager()->addAction(action_dimensions_dialog, "dimensions_dialog");
617
action_edit_coordinates = new QAction(tr("Set &Coordinates"), this);
618
actionManager()->addAction(action_edit_coordinates, "edit_coordinates");
620
action_edit_format = new QAction(tr("Set Display &Format"), this);
621
actionManager()->addAction(action_edit_format, "edit_format");
623
// column related actions
624
icon_temp = new QIcon();
625
icon_temp->addPixmap(QPixmap(":/16x16/insert_column.png"));
626
icon_temp->addPixmap(QPixmap(":/32x32/insert_column.png"));
627
action_insert_columns = new QAction(*icon_temp, tr("&Insert Empty Columns"), this);
628
actionManager()->addAction(action_insert_columns, "insert_columns");
631
icon_temp = new QIcon();
632
icon_temp->addPixmap(QPixmap(":/16x16/remove_column.png"));
633
icon_temp->addPixmap(QPixmap(":/32x32/remove_column.png"));
634
action_remove_columns = new QAction(*icon_temp, tr("Remo&ve Columns"), this);
635
actionManager()->addAction(action_remove_columns, "remove_columns");
638
icon_temp = new QIcon();
639
icon_temp->addPixmap(QPixmap(":/16x16/clear_column.png"));
640
icon_temp->addPixmap(QPixmap(":/32x32/clear_column.png"));
641
action_clear_columns = new QAction(*icon_temp, tr("Clea&r Columns"), this);
642
actionManager()->addAction(action_clear_columns, "clear_columns");
645
icon_temp = new QIcon();
646
icon_temp->addPixmap(QPixmap(":/16x16/add_columns.png"));
647
icon_temp->addPixmap(QPixmap(":/32x32/add_columns.png"));
648
action_add_columns = new QAction(*icon_temp, tr("&Add Columns"), this);
649
actionManager()->addAction(action_add_columns, "add_columns");
652
// row related actions
653
icon_temp = new QIcon();
654
icon_temp->addPixmap(QPixmap(":/16x16/insert_row.png"));
655
icon_temp->addPixmap(QPixmap(":/32x32/insert_row.png"));
656
action_insert_rows = new QAction(*icon_temp ,tr("&Insert Empty Rows"), this);;
657
actionManager()->addAction(action_insert_rows, "insert_rows");
660
icon_temp = new QIcon();
661
icon_temp->addPixmap(QPixmap(":/16x16/remove_row.png"));
662
icon_temp->addPixmap(QPixmap(":/32x32/remove_row.png"));
663
action_remove_rows = new QAction(*icon_temp, tr("Remo&ve Rows"), this);;
664
actionManager()->addAction(action_remove_rows, "remove_rows");
667
icon_temp = new QIcon();
668
icon_temp->addPixmap(QPixmap(":/16x16/clear_row.png"));
669
icon_temp->addPixmap(QPixmap(":/32x32/clear_row.png"));
670
action_clear_rows = new QAction(*icon_temp, tr("Clea&r Rows"), this);;
671
actionManager()->addAction(action_clear_rows, "clear_rows");
674
icon_temp = new QIcon();
675
icon_temp->addPixmap(QPixmap(":/16x16/add_rows.png"));
676
icon_temp->addPixmap(QPixmap(":/32x32/add_rows.png"));
677
action_add_rows = new QAction(*icon_temp, tr("&Add Rows"), this);;
678
actionManager()->addAction(action_add_rows, "add_rows");
682
void Matrix::connectActions()
684
connect(action_cut_selection, SIGNAL(triggered()), this, SLOT(cutSelection()));
685
connect(action_copy_selection, SIGNAL(triggered()), this, SLOT(copySelection()));
686
connect(action_paste_into_selection, SIGNAL(triggered()), this, SLOT(pasteIntoSelection()));
687
connect(action_set_formula, SIGNAL(triggered()), this, SLOT(editFormula()));
688
connect(action_edit_coordinates, SIGNAL(triggered()), this, SLOT(editCoordinates()));
689
connect(action_edit_format, SIGNAL(triggered()), this, SLOT(editFormat()));
690
connect(action_clear_selection, SIGNAL(triggered()), this, SLOT(clearSelectedCells()));
691
#ifdef LEGACY_CODE_0_2_x
692
connect(action_recalculate, SIGNAL(triggered()), this, SLOT(recalculateSelectedCells()));
694
connect(action_select_all, SIGNAL(triggered()), this, SLOT(selectAll()));
695
connect(action_clear_matrix, SIGNAL(triggered()), this, SLOT(clear()));
696
connect(action_transpose, SIGNAL(triggered()), this, SLOT(transpose()));
697
connect(action_mirror_horizontally, SIGNAL(triggered()), this, SLOT(mirrorHorizontally()));
698
connect(action_mirror_vertically, SIGNAL(triggered()), this, SLOT(mirrorVertically()));
699
connect(action_go_to_cell, SIGNAL(triggered()), this, SLOT(goToCell()));
700
connect(action_dimensions_dialog, SIGNAL(triggered()), this, SLOT(dimensionsDialog()));
701
connect(action_import_image, SIGNAL(triggered()), this, SLOT(importImageDialog()));
702
connect(action_duplicate, SIGNAL(triggered()), this, SLOT(duplicate()));
703
connect(action_insert_columns, SIGNAL(triggered()), this, SLOT(insertEmptyColumns()));
704
connect(action_remove_columns, SIGNAL(triggered()), this, SLOT(removeSelectedColumns()));
705
connect(action_clear_columns, SIGNAL(triggered()), this, SLOT(clearSelectedColumns()));
706
connect(action_insert_rows, SIGNAL(triggered()), this, SLOT(insertEmptyRows()));
707
connect(action_remove_rows, SIGNAL(triggered()), this, SLOT(removeSelectedRows()));
708
connect(action_clear_rows, SIGNAL(triggered()), this, SLOT(clearSelectedRows()));
709
connect(action_add_columns, SIGNAL(triggered()), this, SLOT(addColumns()));
710
connect(action_add_rows, SIGNAL(triggered()), this, SLOT(addRows()));
713
void Matrix::addActionsToView()
715
connect(action_toggle_tabbar, SIGNAL(triggered()), d_view, SLOT(toggleControlTabBar()));
717
d_view->addAction(action_cut_selection);
718
d_view->addAction(action_copy_selection);
719
d_view->addAction(action_paste_into_selection);
720
d_view->addAction(action_set_formula);
721
d_view->addAction(action_edit_coordinates);
722
d_view->addAction(action_edit_format);
723
d_view->addAction(action_clear_selection);
724
d_view->addAction(action_recalculate);
725
d_view->addAction(action_toggle_tabbar);
726
d_view->addAction(action_select_all);
727
d_view->addAction(action_clear_matrix);
728
d_view->addAction(action_transpose);
729
d_view->addAction(action_mirror_horizontally);
730
d_view->addAction(action_mirror_vertically);
731
d_view->addAction(action_go_to_cell);
732
d_view->addAction(action_dimensions_dialog);
733
d_view->addAction(action_import_image);
734
#ifndef LEGACY_CODE_0_2_x
735
d_view->addAction(action_duplicate);
737
d_view->addAction(action_insert_columns);
738
d_view->addAction(action_remove_columns);
739
d_view->addAction(action_clear_columns);
740
d_view->addAction(action_insert_rows);
741
d_view->addAction(action_remove_rows);
742
d_view->addAction(action_clear_rows);
743
d_view->addAction(action_add_columns);
744
d_view->addAction(action_add_rows);
748
bool Matrix::fillProjectMenu(QMenu * menu)
750
menu->setTitle(tr("&Matrix"));
752
menu->addAction(action_toggle_tabbar);
753
menu->addSeparator();
754
menu->addAction(action_edit_coordinates);
755
menu->addAction(action_dimensions_dialog);
756
menu->addAction(action_edit_format);
757
menu->addSeparator();
758
menu->addAction(action_set_formula);
759
menu->addAction(action_recalculate);
760
menu->addSeparator();
761
menu->addAction(action_clear_matrix);
762
menu->addAction(action_transpose);
763
menu->addAction(action_mirror_horizontally);
764
menu->addAction(action_mirror_vertically);
765
menu->addSeparator();
766
#ifndef LEGACY_CODE_0_2_x
767
menu->addAction(action_duplicate);
769
menu->addAction(action_import_image);
770
menu->addSeparator();
771
menu->addAction(action_go_to_cell);
780
void Matrix::showMatrixViewContextMenu(const QPoint& pos)
785
createSelectionMenu(&context_menu);
786
context_menu.addSeparator();
787
createMatrixMenu(&context_menu);
788
context_menu.addSeparator();
790
context_menu.exec(pos);
793
void Matrix::showMatrixViewColumnContextMenu(const QPoint& pos)
797
createColumnMenu(&context_menu);
799
context_menu.exec(pos);
802
void Matrix::showMatrixViewRowContextMenu(const QPoint& pos)
806
createRowMenu(&context_menu);
808
context_menu.exec(pos);
811
void Matrix::goToCell()
816
int col = QInputDialog::getInteger(0, tr("Go to Cell"), tr("Enter column"),
817
1, 1, columnCount(), 1, &ok);
820
int row = QInputDialog::getInteger(0, tr("Go to Cell"), tr("Enter row"),
821
1, 1, rowCount(), 1, &ok);
824
d_view->goToCell(row-1, col-1);
827
void Matrix::copy(Matrix * other)
830
beginMacro(QObject::tr("%1: copy %2").arg(name()).arg(other->name()));
831
int rows = other->rowCount();
832
int columns = other->columnCount();
833
setDimensions(rows, columns);
834
for (int i=0; i<rows; i++)
835
setRowHeight(i, other->rowHeight(i));
836
for (int i=0; i<columns; i++)
837
setColumnWidth(i, other->columnWidth(i));
838
d_matrix_private->blockChangeSignals(true);
839
for (int i=0; i<columns; i++)
840
setColumnCells(i, 0, rows-1, other->columnCells(i, 0, rows-1));
841
setCoordinates(other->xStart(), other->xEnd(), other->yStart(), other->yEnd());
842
setNumericFormat(other->numericFormat());
843
setDisplayedDigits(other->displayedDigits());
844
setFormula(other->formula());
845
d_matrix_private->blockChangeSignals(false);
846
emit dataChanged(0, 0, rows-1, columns-1);
847
if (d_view) d_view->rereadSectionSizes();
852
void Matrix::setPlotMenu(QMenu * menu)
857
QIcon Matrix::icon() const
860
ico.addPixmap(QPixmap(":/16x16/matrix.png"));
861
ico.addPixmap(QPixmap(":/24x24/matrix.png"));
862
ico.addPixmap(QPixmap(":/32x32/matrix.png"));
866
QString Matrix::text(int row, int col)
868
return QLocale().toString(cell(row,col), d_matrix_private->numericFormat(), d_matrix_private->displayedDigits());
871
void Matrix::selectAll()
877
void Matrix::setCell(int row, int col, double value)
879
if(row < 0 || row >= rowCount()) return;
880
if(col < 0 || col >= columnCount()) return;
881
exec(new MatrixSetCellValueCmd(d_matrix_private, row, col, value));
884
void Matrix::dimensionsDialog()
888
int cols = QInputDialog::getInteger(0, tr("Set Matrix Dimensions"), tr("Enter number of columns"),
889
columnCount(), 1, 1e9, 1, &ok);
892
int rows = QInputDialog::getInteger(0, tr("Set Matrix Dimensions"), tr("Enter number of rows"),
893
rowCount(), 1, 1e9, 1, &ok);
896
setDimensions(rows, cols);
899
void Matrix::importImageDialog()
901
QList<QByteArray> formats = QImageReader::supportedImageFormats();
902
QString filter = tr("Images") + " (";
903
for (int i=0; i<formats.count(); i++)
904
filter += " *."+formats.at(i)+" ";
906
for (int i=0; i<formats.count(); i++)
907
filter += " *."+formats.at(i)+" (*." + formats.at(i) +");;";
909
QString images_path = global("images_path").toString();
910
QString file_name = QFileDialog::getOpenFileName(0, tr("Import image from file"), images_path, filter);
911
if ( !file_name.isEmpty() )
913
QFileInfo file_info(file_name);
914
images_path = file_info.canonicalPath();
915
setGlobal("images_path", images_path);
916
QImage image(file_name);
917
Matrix * matrix = NULL;
919
matrix = Matrix::fromImage(image);
926
QMessageBox::information(0, tr("Error importing image"), tr("Import of image '%1' failed").arg(file_name));
930
void Matrix::duplicate()
932
#ifndef LEGACY_CODE_0_2_x
933
Matrix * matrix = new Matrix(0, rowCount(), columnCount(), name());
936
folder()->addChild(matrix);
940
void Matrix::editFormat()
943
d_view->showControlFormatTab();
946
void Matrix::editCoordinates()
949
d_view->showControlCoordinatesTab();
952
void Matrix::editFormula()
955
d_view->showControlFormulaTab();
958
void Matrix::addRows()
962
int count = d_view->selectedRowCount(false);
963
beginMacro(QObject::tr("%1: add %2 rows(s)").arg(name()).arg(count));
964
exec(new MatrixInsertRowsCmd(d_matrix_private, rowCount(), count));
969
void Matrix::addColumns()
973
int count = d_view->selectedRowCount(false);
974
beginMacro(QObject::tr("%1: add %2 column(s)").arg(name()).arg(count));
975
exec(new MatrixInsertColumnsCmd(d_matrix_private, columnCount(), count));
980
void Matrix::setXStart(double x)
983
exec(new MatrixSetCoordinatesCmd(d_matrix_private, x, xEnd(), yStart(), yEnd()));
987
void Matrix::setXEnd(double x)
990
exec(new MatrixSetCoordinatesCmd(d_matrix_private, xStart(), x, yStart(), yEnd()));
994
void Matrix::setYStart(double y)
997
exec(new MatrixSetCoordinatesCmd(d_matrix_private, xStart(), xEnd(), y, yEnd()));
1001
void Matrix::setYEnd(double y)
1004
exec(new MatrixSetCoordinatesCmd(d_matrix_private, xStart(), xEnd(), yStart(), y));
1008
void Matrix::setCoordinates(double x1, double x2, double y1, double y2)
1011
exec(new MatrixSetCoordinatesCmd(d_matrix_private, x1, x2, y1, y2));
1015
void Matrix::setNumericFormat(char format)
1017
if (format == numericFormat()) return;
1019
exec(new MatrixSetFormatCmd(d_matrix_private, format));
1023
void Matrix::setDisplayedDigits(int digits)
1025
if (digits == displayedDigits()) return;
1027
exec(new MatrixSetDigitsCmd(d_matrix_private, digits));
1031
double Matrix::xStart() const
1033
return d_matrix_private->xStart();
1036
double Matrix::yStart() const
1038
return d_matrix_private->yStart();
1041
double Matrix::xEnd() const
1043
return d_matrix_private->xEnd();
1046
double Matrix::yEnd() const
1048
return d_matrix_private->yEnd();
1051
QString Matrix::formula() const
1053
return d_matrix_private->formula();
1056
void Matrix::setFormula(const QString & formula)
1059
exec(new MatrixSetFormulaCmd(d_matrix_private, formula));
1063
char Matrix::numericFormat() const
1065
return d_matrix_private->numericFormat();
1068
int Matrix::displayedDigits() const
1070
return d_matrix_private->displayedDigits();
1073
void Matrix::save(QXmlStreamWriter * writer) const
1075
int cols = columnCount();
1076
int rows = rowCount();
1077
writer->writeStartElement("matrix");
1078
writeBasicAttributes(writer);
1079
writer->writeAttribute("columns", QString::number(cols));
1080
writer->writeAttribute("rows", QString::number(rows));
1081
writeCommentElement(writer);
1082
writer->writeStartElement("formula");
1083
writer->writeCharacters(formula());
1084
writer->writeEndElement();
1085
writer->writeStartElement("display");
1086
writer->writeAttribute("numeric_format", QString(QChar(numericFormat())));
1087
writer->writeAttribute("displayed_digits", QString::number(displayedDigits()));
1088
writer->writeEndElement();
1089
writer->writeStartElement("coordinates");
1090
writer->writeAttribute("x_start", QString::number(xStart()));
1091
writer->writeAttribute("x_end", QString::number(xEnd()));
1092
writer->writeAttribute("y_start", QString::number(yStart()));
1093
writer->writeAttribute("y_end", QString::number(yEnd()));
1094
writer->writeEndElement();
1096
for (int col=0; col<cols; col++)
1097
for (int row=0; row<rows; row++)
1099
writer->writeStartElement("cell");
1100
writer->writeAttribute("row", QString::number(row));
1101
writer->writeAttribute("column", QString::number(col));
1102
writer->writeCharacters(QString::number(cell(row, col), 'e', 16));
1103
writer->writeEndElement();
1105
for (int col=0; col<cols; col++)
1107
writer->writeStartElement("column_width");
1108
writer->writeAttribute("column", QString::number(col));
1109
writer->writeCharacters(QString::number(columnWidth(col)));
1110
writer->writeEndElement();
1112
for (int row=0; row<rows; row++)
1114
writer->writeStartElement("row_height");
1115
writer->writeAttribute("row", QString::number(row));
1116
writer->writeCharacters(QString::number(rowHeight(row)));
1117
writer->writeEndElement();
1119
writer->writeEndElement(); // "matrix"
1123
bool Matrix::load(XmlStreamReader * reader)
1125
if(reader->isStartElement() && reader->name() == "matrix")
1127
setDimensions(0, 0);
1130
setNumericFormat('f');
1131
setDisplayedDigits(6);
1132
setCoordinates(0.0, 1.0, 0.0, 1.0);
1134
if (!readBasicAttributes(reader)) return false;
1139
rows = reader->readAttributeInt("rows", &ok1);
1140
cols = reader->readAttributeInt("columns", &ok2);
1143
reader->raiseError(tr("invalid row or column count"));
1146
setDimensions(rows, cols);
1148
// read child elements
1149
while (!reader->atEnd())
1153
if (reader->isEndElement()) break;
1155
if (reader->isStartElement())
1157
bool ret_val = true;
1158
if (reader->name() == "comment")
1159
ret_val = readCommentElement(reader);
1160
else if(reader->name() == "formula")
1161
ret_val = readFormulaElement(reader);
1162
else if(reader->name() == "display")
1163
ret_val = readDisplayElement(reader);
1164
else if(reader->name() == "coordinates")
1165
ret_val = readCoordinatesElement(reader);
1166
else if(reader->name() == "cell")
1167
ret_val = readCellElement(reader);
1168
else if(reader->name() == "row_height")
1169
ret_val = readRowHeightElement(reader);
1170
else if(reader->name() == "column_width")
1171
ret_val = readColumnWidthElement(reader);
1172
else // unknown element
1174
reader->raiseWarning(tr("unknown element '%1'").arg(reader->name().toString()));
1175
if (!reader->skipToEndElement()) return false;
1177
if(!ret_val) return false;
1181
else // no matrix element
1182
reader->raiseError(tr("no matrix element found"));
1184
return !reader->hasError();
1187
bool Matrix::readDisplayElement(XmlStreamReader * reader)
1189
Q_ASSERT(reader->isStartElement() && reader->name() == "display");
1190
QXmlStreamAttributes attribs = reader->attributes();
1192
QString str = attribs.value(reader->namespaceUri().toString(), "numeric_format").toString();
1193
if(str.isEmpty() || str.length() != 1)
1195
reader->raiseError(tr("invalid or missing numeric format"));
1198
setNumericFormat(str.at(0).toAscii());
1201
int digits = reader->readAttributeInt("displayed_digits", &ok);
1204
reader->raiseError(tr("invalid or missing number of displayed digits"));
1207
setDisplayedDigits(digits);
1208
if (!reader->skipToEndElement()) return false;
1213
bool Matrix::readCoordinatesElement(XmlStreamReader * reader)
1215
Q_ASSERT(reader->isStartElement() && reader->name() == "coordinates");
1220
val = reader->readAttributeInt("x_start", &ok);
1223
reader->raiseError(tr("invalid x start value"));
1228
val = reader->readAttributeInt("x_end", &ok);
1231
reader->raiseError(tr("invalid x end value"));
1236
val = reader->readAttributeInt("y_start", &ok);
1239
reader->raiseError(tr("invalid y start value"));
1244
val = reader->readAttributeInt("y_end", &ok);
1247
reader->raiseError(tr("invalid y end value"));
1251
if (!reader->skipToEndElement()) return false;
1256
bool Matrix::readFormulaElement(XmlStreamReader * reader)
1258
Q_ASSERT(reader->isStartElement() && reader->name() == "formula");
1259
setFormula(reader->readElementText());
1263
bool Matrix::readRowHeightElement(XmlStreamReader * reader)
1265
Q_ASSERT(reader->isStartElement() && reader->name() == "row_height");
1267
int row = reader->readAttributeInt("row", &ok);
1270
reader->raiseError(tr("invalid or missing row index"));
1273
QString str = reader->readElementText();
1274
int value = str.toInt(&ok);
1277
reader->raiseError(tr("invalid row height"));
1281
d_view->setRowHeight(row, value);
1283
setRowHeight(row, value);
1287
bool Matrix::readColumnWidthElement(XmlStreamReader * reader)
1289
Q_ASSERT(reader->isStartElement() && reader->name() == "column_width");
1291
int col = reader->readAttributeInt("column", &ok);
1294
reader->raiseError(tr("invalid or missing column index"));
1297
QString str = reader->readElementText();
1298
int value = str.toInt(&ok);
1301
reader->raiseError(tr("invalid column width"));
1305
d_view->setColumnWidth(col, value);
1307
setColumnWidth(col, value);
1311
bool Matrix::readCellElement(XmlStreamReader * reader)
1313
Q_ASSERT(reader->isStartElement() && reader->name() == "cell");
1319
QXmlStreamAttributes attribs = reader->attributes();
1320
row = reader->readAttributeInt("row", &ok);
1323
reader->raiseError(tr("invalid or missing row index"));
1326
col = reader->readAttributeInt("column", &ok);
1329
reader->raiseError(tr("invalid or missing column index"));
1333
str = reader->readElementText();
1334
double value = str.toDouble(&ok);
1337
reader->raiseError(tr("invalid cell value"));
1340
setCell(row, col, value);
1345
void Matrix::setRowHeight(int row, int height)
1347
d_matrix_private->setRowHeight(row, height);
1350
void Matrix::setColumnWidth(int col, int width)
1352
d_matrix_private->setColumnWidth(col, width);
1355
int Matrix::rowHeight(int row) const
1357
return d_matrix_private->rowHeight(row);
1360
int Matrix::columnWidth(int col) const
1362
return d_matrix_private->columnWidth(col);
1365
void Matrix::adjustTabBarAction(bool visible)
1368
action_toggle_tabbar->setText(tr("Hide Controls"));
1370
action_toggle_tabbar->setText(tr("Show Controls"));
1373
QVector<double> Matrix::columnCells(int col, int first_row, int last_row)
1375
return d_matrix_private->columnCells(col, first_row, last_row);
1378
void Matrix::setColumnCells(int col, int first_row, int last_row, const QVector<double> & values)
1381
exec(new MatrixSetColumnCellsCmd(d_matrix_private, col, first_row, last_row, values));
1385
QVector<double> Matrix::rowCells(int row, int first_column, int last_column)
1387
return d_matrix_private->rowCells(row, first_column, last_column);
1390
void Matrix::setRowCells(int row, int first_column, int last_column, const QVector<double> & values)
1393
exec(new MatrixSetRowCellsCmd(d_matrix_private, row, first_column, last_column, values));
1397
void Matrix::transpose()
1400
exec(new MatrixTransposeCmd(d_matrix_private));
1404
void Matrix::mirrorHorizontally()
1407
exec(new MatrixMirrorHorizontallyCmd(d_matrix_private));
1411
void Matrix::mirrorVertically()
1414
exec(new MatrixMirrorVerticallyCmd(d_matrix_private));
1418
void Matrix::recalculateSelectedCells()
1420
if (!d_view) return;
1421
#ifdef LEGACY_CODE_0_2_x
1423
beginMacro(tr("%1: apply formula to selection").arg(name()));
1431
/* ========================= static methods ======================= */
1432
ActionManager * Matrix::action_manager = 0;
1434
ActionManager * Matrix::actionManager()
1436
if (!action_manager)
1437
initActionManager();
1439
return action_manager;
1442
void Matrix::initActionManager()
1444
if (!action_manager)
1445
action_manager = new ActionManager();
1447
action_manager->setTitle(tr("Matrix"));
1448
volatile Matrix * action_creator = new Matrix(); // initialize the action texts
1449
delete action_creator;
1452
Matrix * Matrix::fromImage(const QImage & image)
1454
int cols = image.width();
1455
int rows = image.height();
1457
QProgressDialog progress;
1458
progress.setRange(0, cols);
1459
progress.setWindowTitle(tr("SciDAVis") + " - " + tr("Import image..."));
1462
Matrix * matrix = new Matrix(0, rows, cols, tr("Matrix %1").arg(1));
1464
QVector<double> values;
1465
values.resize(rows);
1467
for (int i=0; i<cols; i++)
1469
for (int j=0; j<rows; j++)
1470
values[j] = qGray(image.pixel(i, rows - 1 - j));
1472
matrix->setColumnCells(i, 0, rows-1, values);
1476
progress.setValue(i);
1477
QApplication::processEvents();
1480
if (progress.wasCanceled())
1484
if (progress.wasCanceled())
1492
/* ========================== Matrix::Private ====================== */
1494
Matrix::Private::Private(Matrix *owner)
1495
: d_owner(owner), d_column_count(0), d_row_count(0)
1497
d_block_change_signals = false;
1498
d_numeric_format = 'f';
1499
d_displayed_digits = 6;
1506
void Matrix::Private::insertColumns(int before, int count)
1508
Q_ASSERT(before >= 0);
1509
Q_ASSERT(before <= d_column_count);
1511
emit d_owner->columnsAboutToBeInserted(before, count);
1512
for(int i=0; i<count; i++)
1514
d_data.insert(before+i, QVector<double>(d_row_count));
1515
d_column_widths.insert(before+i, Matrix::defaultColumnWidth());
1518
d_column_count += count;
1519
emit d_owner->columnsInserted(before, count);
1522
void Matrix::Private::removeColumns(int first, int count)
1524
emit d_owner->columnsAboutToBeRemoved(first, count);
1525
Q_ASSERT(first >= 0);
1526
Q_ASSERT(first+count <= d_column_count);
1527
d_data.remove(first, count);
1528
for (int i=0; i<count; i++)
1529
d_column_widths.removeAt(first);
1530
d_column_count -= count;
1531
emit d_owner->columnsRemoved(first, count);
1534
void Matrix::Private::insertRows(int before, int count)
1536
emit d_owner->rowsAboutToBeInserted(before, count);
1537
Q_ASSERT(before >= 0);
1538
Q_ASSERT(before <= d_row_count);
1539
for(int col=0; col<d_column_count; col++)
1540
for(int i=0; i<count; i++)
1541
d_data[col].insert(before+i, 0.0);
1542
for(int i=0; i<count; i++)
1543
d_row_heights.insert(before+i, Matrix::defaultRowHeight());
1545
d_row_count += count;
1546
emit d_owner->rowsInserted(before, count);
1549
void Matrix::Private::removeRows(int first, int count)
1551
emit d_owner->rowsAboutToBeRemoved(first, count);
1552
Q_ASSERT(first >= 0);
1553
Q_ASSERT(first+count <= d_row_count);
1554
for(int col=0; col<d_column_count; col++)
1555
d_data[col].remove(first, count);
1556
for (int i=0; i<count; i++)
1557
d_row_heights.removeAt(first);
1559
d_row_count -= count;
1560
emit d_owner->rowsRemoved(first, count);
1563
double Matrix::Private::cell(int row, int col) const
1565
Q_ASSERT(row >= 0 && row < d_row_count);
1566
Q_ASSERT(col >= 0 && col < d_column_count);
1567
return d_data.at(col).at(row);
1570
void Matrix::Private::setCell(int row, int col, double value)
1572
Q_ASSERT(row >= 0 && row < d_row_count);
1573
Q_ASSERT(col >= 0 && col < d_column_count);
1574
d_data[col][row] = value;
1575
if (!d_block_change_signals)
1576
emit d_owner->dataChanged(row, col, row, col);
1579
QVector<double> Matrix::Private::columnCells(int col, int first_row, int last_row)
1581
Q_ASSERT(first_row >= 0 && first_row < d_row_count);
1582
Q_ASSERT(last_row >= 0 && last_row < d_row_count);
1584
if(first_row == 0 && last_row == d_row_count-1)
1585
return d_data.at(col);
1587
QVector<double> result;
1588
for(int i=first_row; i<=last_row; i++)
1589
result.append(d_data.at(col).at(i));
1593
void Matrix::Private::setColumnCells(int col, int first_row, int last_row, const QVector<double> & values)
1595
Q_ASSERT(first_row >= 0 && first_row < d_row_count);
1596
Q_ASSERT(last_row >= 0 && last_row < d_row_count);
1597
Q_ASSERT(values.count() > last_row - first_row);
1599
if(first_row == 0 && last_row == d_row_count-1)
1601
d_data[col] = values;
1602
d_data[col].resize(d_row_count); // values may be larger
1603
if (!d_block_change_signals)
1604
emit d_owner->dataChanged(first_row, col, last_row, col);
1608
for(int i=first_row; i<=last_row; i++)
1609
d_data[col][i] = values.at(i-first_row);
1610
if (!d_block_change_signals)
1611
emit d_owner->dataChanged(first_row, col, last_row, col);
1614
QVector<double> Matrix::Private::rowCells(int row, int first_column, int last_column)
1616
Q_ASSERT(first_column >= 0 && first_column < d_column_count);
1617
Q_ASSERT(last_column >= 0 && last_column < d_column_count);
1619
QVector<double> result;
1620
for(int i=first_column; i<=last_column; i++)
1621
result.append(d_data.at(i).at(row));
1625
void Matrix::Private::setRowCells(int row, int first_column, int last_column, const QVector<double> & values)
1627
Q_ASSERT(first_column >= 0 && first_column < d_column_count);
1628
Q_ASSERT(last_column >= 0 && last_column < d_column_count);
1629
Q_ASSERT(values.count() > last_column - first_column);
1631
for(int i=first_column; i<=last_column; i++)
1632
d_data[i][row] = values.at(i-first_column);
1633
if (!d_block_change_signals)
1634
emit d_owner->dataChanged(row, first_column, row, last_column);
1637
void Matrix::Private::clearColumn(int col)
1639
d_data[col].fill(0.0);
1640
if (!d_block_change_signals)
1641
emit d_owner->dataChanged(0, col, d_row_count-1, col);
1644
double Matrix::Private::xStart() const
1649
double Matrix::Private::yStart() const
1654
double Matrix::Private::xEnd() const
1659
double Matrix::Private::yEnd() const
1664
void Matrix::Private::setXStart(double x)
1667
emit d_owner->coordinatesChanged();
1670
void Matrix::Private::setXEnd(double x)
1673
emit d_owner->coordinatesChanged();
1676
void Matrix::Private::setYStart(double y)
1679
emit d_owner->coordinatesChanged();
1682
void Matrix::Private::setYEnd(double y)
1685
emit d_owner->coordinatesChanged();
1688
QString Matrix::Private::formula() const
1693
void Matrix::Private::setFormula(const QString & formula)
1695
d_formula = formula;
1696
emit d_owner->formulaChanged();