~valavanisalex/ubuntu/maverick/scidavis/fix-604811

« back to all changes in this revision

Viewing changes to scidavis/src/future/matrix/future_Matrix.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Ruben Molina
  • Date: 2009-09-06 11:34:04 UTC
  • Revision ID: james.westby@ubuntu.com-20090906113404-4awaey82l3686w4q
Tags: upstream-0.2.3
ImportĀ upstreamĀ versionĀ 0.2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
    File                 : Matrix.cpp
 
3
    Project              : SciDAVis
 
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) 
 
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/future_Matrix.h"
 
32
#include "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"
 
38
 
 
39
#include <QtCore>
 
40
#include <QtGui>
 
41
#include <QtDebug>
 
42
 
 
43
#include <stdlib.h>
 
44
#include <math.h>
 
45
#include <stdio.h>
 
46
 
 
47
#include <gsl/gsl_linalg.h>
 
48
#include <gsl/gsl_math.h>
 
49
 
 
50
namespace future{
 
51
 
 
52
#define WAIT_CURSOR QApplication::setOverrideCursor(QCursor(Qt::WaitCursor))
 
53
#define RESET_CURSOR QApplication::restoreOverrideCursor()
 
54
 
 
55
int Matrix::default_column_width = 120;
 
56
int Matrix::default_row_height = 20;
 
57
 
 
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)
 
61
#else
 
62
Matrix::Matrix(void *, int rows, int cols, const QString& name)
 
63
        : AbstractPart(name), d_plot_menu(0)
 
64
#endif
 
65
{
 
66
        d_matrix_private = new Private(this);
 
67
        // set initial number of rows and columns
 
68
        appendColumns(cols);
 
69
        appendRows(rows);
 
70
 
 
71
        d_view = NULL;
 
72
        createActions();
 
73
        connectActions();
 
74
}
 
75
 
 
76
#ifndef LEGACY_CODE_0_2_x
 
77
Matrix::Matrix()
 
78
        : AbstractPart("temp"), scripted(0)
 
79
#else
 
80
Matrix::Matrix()
 
81
        : AbstractPart("temp")
 
82
#endif
 
83
{
 
84
        d_view = NULL;
 
85
        createActions();
 
86
}
 
87
 
 
88
Matrix::~Matrix()
 
89
{
 
90
        delete d_view;
 
91
}
 
92
 
 
93
void Matrix::setView(MatrixView * view)
 
94
{
 
95
        d_view = view; 
 
96
        addActionsToView();
 
97
        connect(d_view, SIGNAL(controlTabBarStatusChanged(bool)), this, SLOT(adjustTabBarAction(bool)));
 
98
        adjustTabBarAction(true);
 
99
}
 
100
 
 
101
QWidget *Matrix::view()
 
102
{
 
103
#ifndef LEGACY_CODE_0_2_x
 
104
        if (!d_view)
 
105
        {
 
106
                d_view = new MatrixView(this); 
 
107
                addActionsToView();
 
108
                connect(d_view, SIGNAL(controlTabBarStatusChanged(bool)), this, SLOT(adjustTabBarAction(bool)));
 
109
                adjustTabBarAction(true);
 
110
        }
 
111
#else
 
112
        Q_ASSERT(d_view != NULL);
 
113
#endif
 
114
        return d_view;
 
115
}
 
116
 
 
117
void Matrix::insertColumns(int before, int count)
 
118
{
 
119
        if( count < 1 || before < 0 || before > columnCount()) return;
 
120
        WAIT_CURSOR;
 
121
        beginMacro(QObject::tr("%1: insert %2 column(s)").arg(name()).arg(count));
 
122
        exec(new MatrixInsertColumnsCmd(d_matrix_private, before, count));
 
123
        endMacro();
 
124
        RESET_CURSOR;
 
125
}
 
126
 
 
127
void Matrix::removeColumns(int first, int count)
 
128
{
 
129
        if( count < 1 || first < 0 || first+count > columnCount()) return;
 
130
        WAIT_CURSOR;
 
131
        beginMacro(QObject::tr("%1: remove %2 column(s)").arg(name()).arg(count));
 
132
        exec(new MatrixRemoveColumnsCmd(d_matrix_private, first, count));
 
133
        endMacro();
 
134
        RESET_CURSOR;
 
135
}
 
136
 
 
137
void Matrix::removeRows(int first, int count)
 
138
{
 
139
        if( count < 1 || first < 0 || first+count > rowCount()) return;
 
140
        WAIT_CURSOR;
 
141
        beginMacro(QObject::tr("%1: remove %2 row(s)").arg(name()).arg(count));
 
142
        exec(new MatrixRemoveRowsCmd(d_matrix_private, first, count));
 
143
        endMacro();
 
144
        RESET_CURSOR;
 
145
}
 
146
 
 
147
void Matrix::insertRows(int before, int count)
 
148
{
 
149
        if( count < 1 || before < 0 || before > rowCount()) return;
 
150
        WAIT_CURSOR;
 
151
        beginMacro(QObject::tr("%1: insert %2 row(s)").arg(name()).arg(count));
 
152
        exec(new MatrixInsertRowsCmd(d_matrix_private, before, count));
 
153
        endMacro();
 
154
        RESET_CURSOR;
 
155
}
 
156
 
 
157
void Matrix::setDimensions(int rows, int cols)
 
158
{
 
159
        if( (rows < 0) || (cols < 0 ) || (rows == rowCount() && cols == columnCount()) ) return;
 
160
        WAIT_CURSOR;
 
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();
 
164
        if(col_diff > 0)
 
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));
 
168
        if(row_diff > 0)
 
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));
 
172
        endMacro();
 
173
        RESET_CURSOR;
 
174
}
 
175
 
 
176
int Matrix::columnCount() const
 
177
{
 
178
        return d_matrix_private->columnCount();
 
179
}
 
180
 
 
181
int Matrix::rowCount() const
 
182
{
 
183
        return d_matrix_private->rowCount();
 
184
}
 
185
 
 
186
void Matrix::clear()
 
187
{
 
188
        WAIT_CURSOR;
 
189
        beginMacro(QObject::tr("%1: clear").arg(name()));
 
190
        exec(new MatrixClearCmd(d_matrix_private));
 
191
        endMacro();
 
192
        RESET_CURSOR;
 
193
}
 
194
 
 
195
double Matrix::cell(int row, int col) const
 
196
{
 
197
        if(row < 0 || row >= rowCount() ||
 
198
           col < 0 || col >= columnCount()) return 0.0;
 
199
        return d_matrix_private->cell(row, col);
 
200
}
 
201
 
 
202
void Matrix::cutSelection()
 
203
{
 
204
        if (!d_view) return;
 
205
        int first = d_view->firstSelectedRow();
 
206
        if( first < 0 ) return;
 
207
 
 
208
        WAIT_CURSOR;
 
209
        beginMacro(tr("%1: cut selected cell(s)").arg(name()));
 
210
        copySelection();
 
211
        clearSelectedCells();
 
212
        endMacro();
 
213
        RESET_CURSOR;
 
214
}
 
215
 
 
216
void Matrix::copySelection()
 
217
{
 
218
        if (!d_view) return;
 
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;
 
229
        
 
230
        WAIT_CURSOR;
 
231
        QString output_str;
 
232
 
 
233
        for(int r=0; r<rows; r++)
 
234
        {
 
235
                for(int c=0; c<cols; c++)
 
236
                {
 
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
 
240
                        if(c < cols-1)
 
241
                                output_str += "\t";
 
242
                }
 
243
                if(r < rows-1)
 
244
                        output_str += "\n";
 
245
        }
 
246
        QApplication::clipboard()->setText(output_str);
 
247
        RESET_CURSOR;
 
248
}
 
249
 
 
250
void Matrix::pasteIntoSelection()
 
251
{
 
252
        if (!d_view) return;
 
253
        if(columnCount() < 1 || rowCount() < 1) return;
 
254
 
 
255
        WAIT_CURSOR;
 
256
        beginMacro(tr("%1: paste from clipboard").arg(name()));
 
257
        const QMimeData * mime_data = QApplication::clipboard()->mimeData();
 
258
 
 
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;
 
265
        int rows, cols;
 
266
 
 
267
        if(mime_data->hasFormat("text/plain"))
 
268
        {
 
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();
 
273
                input_col_count = 0;
 
274
                for(int i=0; i<input_row_count; i++)
 
275
                {
 
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();
 
278
                }
 
279
 
 
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
 
284
                {
 
285
                        int current_row, current_col;
 
286
                        d_view->getCurrentCell(&current_row, &current_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);
 
301
                }
 
302
 
 
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++)
 
306
                {
 
307
                        for(int c=0; c<cols && c<input_col_count; c++)
 
308
                        {
 
309
                                if(d_view->isCellSelected(first_row + r, first_col + c) && (c < cell_texts.at(r).count()) )
 
310
                                {
 
311
                                        setCell(first_row + r, first_col + c, cell_texts.at(r).at(c).toDouble());
 
312
                                }
 
313
                        }
 
314
                }
 
315
        }
 
316
        endMacro();
 
317
        RESET_CURSOR;
 
318
}
 
319
 
 
320
void Matrix::insertEmptyColumns()
 
321
{
 
322
        if (!d_view) return;
 
323
        int first = d_view->firstSelectedColumn();
 
324
        int last = d_view->lastSelectedColumn();
 
325
        if( first < 0 ) return;
 
326
        int count, current = first;
 
327
 
 
328
        WAIT_CURSOR;
 
329
        beginMacro(QObject::tr("%1: insert empty column(s)").arg(name()));
 
330
        while( current <= last )
 
331
        {
 
332
                current = first+1;
 
333
                while( current <= last && d_view->isColumnSelected(current) ) current++;
 
334
                count = current-first;
 
335
                insertColumns(first, count);
 
336
                current += count;
 
337
                last += count;
 
338
                while( current <= last && !d_view->isColumnSelected(current) ) current++;
 
339
                first = current;
 
340
        }
 
341
        endMacro();
 
342
        RESET_CURSOR;
 
343
}
 
344
 
 
345
void Matrix::removeSelectedColumns()
 
346
{
 
347
        if (!d_view) return;
 
348
        int first = d_view->firstSelectedColumn();
 
349
        int last = d_view->lastSelectedColumn();
 
350
        if( first < 0 ) return;
 
351
 
 
352
        WAIT_CURSOR;
 
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);
 
356
        endMacro();
 
357
        RESET_CURSOR;
 
358
}
 
359
 
 
360
void Matrix::clearSelectedColumns()
 
361
{
 
362
        if (!d_view) return;
 
363
        WAIT_CURSOR;
 
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));
 
368
        endMacro();
 
369
        RESET_CURSOR;
 
370
}
 
371
 
 
372
void Matrix::insertEmptyRows()
 
373
{
 
374
        if (!d_view) return;
 
375
        int first = d_view->firstSelectedRow();
 
376
        int last = d_view->lastSelectedRow();
 
377
        int count, current = first;
 
378
 
 
379
        if( first < 0 ) return;
 
380
 
 
381
        WAIT_CURSOR;
 
382
        beginMacro(QObject::tr("%1: insert empty rows(s)").arg(name()));
 
383
        while( current <= last )
 
384
        {
 
385
                current = first+1;
 
386
                while( current <= last && d_view->isRowSelected(current) ) current++;
 
387
                count = current-first;
 
388
                insertRows(first, count);
 
389
                current += count;
 
390
                last += count;
 
391
                while( current <= last && !d_view->isRowSelected(current) ) current++;
 
392
                first = current;
 
393
        }
 
394
        endMacro();
 
395
        RESET_CURSOR;
 
396
}
 
397
 
 
398
void Matrix::removeSelectedRows()
 
399
{
 
400
        if (!d_view) return;
 
401
        int first = d_view->firstSelectedRow();
 
402
        int last = d_view->lastSelectedRow();
 
403
        if( first < 0 ) return;
 
404
 
 
405
        WAIT_CURSOR;
 
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);
 
409
        endMacro();
 
410
        RESET_CURSOR;
 
411
}
 
412
 
 
413
void Matrix::clearSelectedRows()
 
414
{
 
415
        if (!d_view) return;
 
416
        int first = d_view->firstSelectedRow();
 
417
        int last = d_view->lastSelectedRow();
 
418
        if( first < 0 ) return;
 
419
 
 
420
        WAIT_CURSOR;
 
421
        beginMacro(QObject::tr("%1: clear selected rows(s)").arg(name()));
 
422
        for(int i=first; i<=last; i++)
 
423
        {
 
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));
 
427
        }
 
428
        endMacro();
 
429
        RESET_CURSOR;
 
430
}
 
431
 
 
432
void Matrix::clearSelectedCells()
 
433
{
 
434
        if (!d_view) return;
 
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;
 
441
 
 
442
        WAIT_CURSOR;
 
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));
 
448
        endMacro();
 
449
        RESET_CURSOR;
 
450
}
 
451
 
 
452
QMenu *Matrix::createContextMenu() const
 
453
{
 
454
        QMenu *menu = AbstractPart::createContextMenu();
 
455
        Q_ASSERT(menu);
 
456
        menu->addSeparator();
 
457
        
 
458
        menu->addAction(action_duplicate);
 
459
        // TODO menu->addAction( ....
 
460
 
 
461
        return menu;
 
462
}
 
463
 
 
464
QMenu * Matrix::createSelectionMenu(QMenu * append_to)
 
465
{
 
466
        QMenu * menu = append_to;
 
467
        if(!menu)
 
468
                menu = new QMenu();
 
469
 
 
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);
 
474
 
 
475
        return menu;
 
476
}
 
477
 
 
478
 
 
479
QMenu * Matrix::createColumnMenu(QMenu * append_to)
 
480
{
 
481
        QMenu * menu = append_to;
 
482
        if(!menu)
 
483
                menu = new QMenu();
 
484
 
 
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);
 
490
        
 
491
        return menu;
 
492
}
 
493
 
 
494
QMenu * Matrix::createMatrixMenu(QMenu * append_to) 
 
495
{
 
496
        QMenu * menu = append_to;
 
497
        if(!menu)
 
498
                menu = new QMenu();
 
499
 
 
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);
 
511
 
 
512
        return menu;
 
513
}
 
514
 
 
515
QMenu * Matrix::createRowMenu(QMenu * append_to) 
 
516
{
 
517
        QMenu * menu = append_to;
 
518
        if(!menu)
 
519
                menu = new QMenu();
 
520
 
 
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);
 
526
 
 
527
        return menu;
 
528
}
 
529
 
 
530
 
 
531
void Matrix::createActions()
 
532
{
 
533
        QIcon * icon_temp;
 
534
 
 
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");
 
538
 
 
539
        action_copy_selection = new QAction(QIcon(QPixmap(":/copy.xpm")), tr("&Copy"), this);
 
540
        actionManager()->addAction(action_copy_selection, "copy_selection");
 
541
 
 
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"); 
 
544
 
 
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"); 
 
550
        delete icon_temp;
 
551
 
 
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"); 
 
559
        delete icon_temp;
 
560
        
 
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"); 
 
567
        delete icon_temp;
 
568
 
 
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"); 
 
575
        delete icon_temp;
 
576
 
 
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"); 
 
582
        delete icon_temp;
 
583
 
 
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"); 
 
589
        delete icon_temp;
 
590
 
 
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"); 
 
597
        delete icon_temp;
 
598
 
 
599
        action_transpose = new QAction(tr("&Transpose"), this);
 
600
        actionManager()->addAction(action_transpose, "transpose"); 
 
601
 
 
602
        action_mirror_horizontally = new QAction(tr("Mirror &Horizontally"), this);
 
603
        actionManager()->addAction(action_mirror_horizontally, "mirror_horizontally"); 
 
604
 
 
605
        action_mirror_vertically = new QAction(tr("Mirror &Vertically"), this);
 
606
        actionManager()->addAction(action_mirror_vertically, "mirror_vertically"); 
 
607
 
 
608
        action_import_image = new QAction(tr("&Import Image", "import image as matrix"), this);
 
609
        actionManager()->addAction(action_import_image, "import_image"); 
 
610
        
 
611
        action_duplicate = new QAction(QIcon(QPixmap(":/duplicate.xpm")), tr("&Duplicate", "duplicate matrix"), this);
 
612
        actionManager()->addAction(action_duplicate, "duplicate"); 
 
613
        
 
614
        action_dimensions_dialog = new QAction(QIcon(QPixmap(":/resize.xpm")), tr("&Dimensions", "matrix size"), this);
 
615
        actionManager()->addAction(action_dimensions_dialog, "dimensions_dialog"); 
 
616
        
 
617
        action_edit_coordinates = new QAction(tr("Set &Coordinates"), this);
 
618
        actionManager()->addAction(action_edit_coordinates, "edit_coordinates"); 
 
619
        
 
620
        action_edit_format = new QAction(tr("Set Display &Format"), this);
 
621
        actionManager()->addAction(action_edit_format, "edit_format"); 
 
622
 
 
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"); 
 
629
        delete icon_temp;
 
630
 
 
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"); 
 
636
        delete icon_temp;
 
637
 
 
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"); 
 
643
        delete icon_temp;
 
644
 
 
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"); 
 
650
        delete icon_temp;
 
651
 
 
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"); 
 
658
        delete icon_temp;
 
659
 
 
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"); 
 
665
        delete icon_temp;
 
666
 
 
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"); 
 
672
        delete icon_temp;
 
673
 
 
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"); 
 
679
        delete icon_temp;
 
680
}
 
681
 
 
682
void Matrix::connectActions()
 
683
{
 
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()));
 
693
#endif
 
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()));
 
711
}
 
712
 
 
713
void Matrix::addActionsToView()
 
714
{
 
715
        connect(action_toggle_tabbar, SIGNAL(triggered()), d_view, SLOT(toggleControlTabBar()));
 
716
 
 
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);
 
736
#endif
 
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);
 
745
}
 
746
 
 
747
 
 
748
bool Matrix::fillProjectMenu(QMenu * menu)
 
749
{
 
750
        menu->setTitle(tr("&Matrix"));
 
751
 
 
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);
 
768
#endif
 
769
        menu->addAction(action_import_image);
 
770
        menu->addSeparator();
 
771
        menu->addAction(action_go_to_cell);
 
772
 
 
773
        return true;
 
774
 
 
775
        // TODO:
 
776
        // Convert to Table
 
777
        // Export 
 
778
}
 
779
 
 
780
void Matrix::showMatrixViewContextMenu(const QPoint& pos)
 
781
{
 
782
        if (!d_view) return;
 
783
        QMenu context_menu;
 
784
        
 
785
        createSelectionMenu(&context_menu);
 
786
        context_menu.addSeparator();
 
787
        createMatrixMenu(&context_menu);
 
788
        context_menu.addSeparator();
 
789
 
 
790
        context_menu.exec(pos);
 
791
}
 
792
 
 
793
void Matrix::showMatrixViewColumnContextMenu(const QPoint& pos)
 
794
{
 
795
        QMenu context_menu;
 
796
        
 
797
        createColumnMenu(&context_menu);
 
798
 
 
799
        context_menu.exec(pos);
 
800
}
 
801
 
 
802
void Matrix::showMatrixViewRowContextMenu(const QPoint& pos)
 
803
{
 
804
        QMenu context_menu;
 
805
        
 
806
        createRowMenu(&context_menu);
 
807
 
 
808
        context_menu.exec(pos);
 
809
}
 
810
 
 
811
void Matrix::goToCell()
 
812
{
 
813
        if (!d_view) return;
 
814
        bool ok;
 
815
 
 
816
        int col = QInputDialog::getInteger(0, tr("Go to Cell"), tr("Enter column"),
 
817
                        1, 1, columnCount(), 1, &ok);
 
818
        if ( !ok ) return;
 
819
 
 
820
        int row = QInputDialog::getInteger(0, tr("Go to Cell"), tr("Enter row"),
 
821
                        1, 1, rowCount(), 1, &ok);
 
822
        if ( !ok ) return;
 
823
 
 
824
        d_view->goToCell(row-1, col-1);
 
825
}
 
826
 
 
827
void Matrix::copy(Matrix * other)
 
828
{
 
829
        WAIT_CURSOR;
 
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();
 
848
        endMacro();
 
849
        RESET_CURSOR;
 
850
}
 
851
 
 
852
void Matrix::setPlotMenu(QMenu * menu)
 
853
{
 
854
        d_plot_menu = menu;
 
855
}
 
856
 
 
857
QIcon Matrix::icon() const
 
858
{
 
859
        QIcon ico;
 
860
        ico.addPixmap(QPixmap(":/16x16/matrix.png"));
 
861
        ico.addPixmap(QPixmap(":/24x24/matrix.png"));
 
862
        ico.addPixmap(QPixmap(":/32x32/matrix.png"));
 
863
        return ico;
 
864
}
 
865
 
 
866
QString Matrix::text(int row, int col)
 
867
{
 
868
        return QLocale().toString(cell(row,col), d_matrix_private->numericFormat(), d_matrix_private->displayedDigits());
 
869
}
 
870
 
 
871
void Matrix::selectAll()
 
872
{
 
873
        if (!d_view) return;
 
874
        d_view->selectAll();
 
875
}
 
876
 
 
877
void Matrix::setCell(int row, int col, double value)
 
878
{
 
879
        if(row < 0 || row >= rowCount()) return;
 
880
        if(col < 0 || col >= columnCount()) return;
 
881
        exec(new MatrixSetCellValueCmd(d_matrix_private, row, col, value));
 
882
}
 
883
 
 
884
void Matrix::dimensionsDialog()
 
885
{
 
886
        bool ok;
 
887
 
 
888
        int cols = QInputDialog::getInteger(0, tr("Set Matrix Dimensions"), tr("Enter number of columns"),
 
889
                        columnCount(), 1, 1e9, 1, &ok);
 
890
        if ( !ok ) return;
 
891
 
 
892
        int rows = QInputDialog::getInteger(0, tr("Set Matrix Dimensions"), tr("Enter number of rows"),
 
893
                        rowCount(), 1, 1e9, 1, &ok);
 
894
        if ( !ok ) return;
 
895
        
 
896
        setDimensions(rows, cols);
 
897
}
 
898
 
 
899
void Matrix::importImageDialog()
 
900
{
 
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)+" ";
 
905
        filter += ");;";
 
906
        for (int i=0; i<formats.count(); i++)
 
907
                filter += " *."+formats.at(i)+" (*." + formats.at(i) +");;";
 
908
 
 
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() )
 
912
        {
 
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;
 
918
                if (!image.isNull())
 
919
                        matrix = Matrix::fromImage(image);
 
920
                if (matrix)
 
921
                {
 
922
                        copy(matrix);
 
923
                        delete matrix;
 
924
                }
 
925
                else
 
926
                        QMessageBox::information(0, tr("Error importing image"), tr("Import of image '%1' failed").arg(file_name));
 
927
        }
 
928
}
 
929
 
 
930
void Matrix::duplicate()
 
931
{
 
932
#ifndef LEGACY_CODE_0_2_x
 
933
        Matrix * matrix = new Matrix(0, rowCount(), columnCount(), name());
 
934
        matrix->copy(this);
 
935
        if (folder())
 
936
                folder()->addChild(matrix);
 
937
#endif
 
938
}
 
939
 
 
940
void Matrix::editFormat()
 
941
{
 
942
        if (!d_view) return;
 
943
        d_view->showControlFormatTab();
 
944
}
 
945
 
 
946
void Matrix::editCoordinates()
 
947
{
 
948
        if (!d_view) return;
 
949
        d_view->showControlCoordinatesTab();
 
950
}
 
951
 
 
952
void Matrix::editFormula()
 
953
{
 
954
        if (!d_view) return;
 
955
        d_view->showControlFormulaTab();
 
956
}
 
957
 
 
958
void Matrix::addRows()
 
959
{
 
960
        if (!d_view) return;
 
961
        WAIT_CURSOR;
 
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));
 
965
        endMacro();
 
966
        RESET_CURSOR;
 
967
}
 
968
 
 
969
void Matrix::addColumns()
 
970
{
 
971
        if (!d_view) return;
 
972
        WAIT_CURSOR;
 
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));
 
976
        endMacro();
 
977
        RESET_CURSOR;
 
978
}
 
979
 
 
980
void Matrix::setXStart(double x)
 
981
{
 
982
        WAIT_CURSOR;
 
983
        exec(new MatrixSetCoordinatesCmd(d_matrix_private, x, xEnd(), yStart(), yEnd()));
 
984
        RESET_CURSOR;
 
985
}
 
986
 
 
987
void Matrix::setXEnd(double x)
 
988
{
 
989
        WAIT_CURSOR;
 
990
        exec(new MatrixSetCoordinatesCmd(d_matrix_private, xStart(), x, yStart(), yEnd()));
 
991
        RESET_CURSOR;
 
992
}
 
993
 
 
994
void Matrix::setYStart(double y)
 
995
{
 
996
        WAIT_CURSOR;
 
997
        exec(new MatrixSetCoordinatesCmd(d_matrix_private, xStart(), xEnd(), y, yEnd()));
 
998
        RESET_CURSOR;
 
999
}
 
1000
 
 
1001
void Matrix::setYEnd(double y)
 
1002
{
 
1003
        WAIT_CURSOR;
 
1004
        exec(new MatrixSetCoordinatesCmd(d_matrix_private, xStart(), xEnd(), yStart(), y));
 
1005
        RESET_CURSOR;
 
1006
}
 
1007
 
 
1008
void Matrix::setCoordinates(double x1, double x2, double y1, double y2)
 
1009
{
 
1010
        WAIT_CURSOR;
 
1011
        exec(new MatrixSetCoordinatesCmd(d_matrix_private, x1, x2, y1, y2));
 
1012
        RESET_CURSOR;
 
1013
}
 
1014
 
 
1015
void Matrix::setNumericFormat(char format)
 
1016
{
 
1017
        if (format == numericFormat()) return;
 
1018
        WAIT_CURSOR;
 
1019
        exec(new MatrixSetFormatCmd(d_matrix_private, format));
 
1020
        RESET_CURSOR;
 
1021
}
 
1022
 
 
1023
void Matrix::setDisplayedDigits(int digits)
 
1024
{
 
1025
        if (digits == displayedDigits()) return;
 
1026
        WAIT_CURSOR;
 
1027
        exec(new MatrixSetDigitsCmd(d_matrix_private, digits));
 
1028
        RESET_CURSOR;
 
1029
}
 
1030
 
 
1031
double Matrix::xStart() const
 
1032
 
1033
        return d_matrix_private->xStart(); 
 
1034
}
 
1035
 
 
1036
double Matrix::yStart() const
 
1037
 
1038
        return d_matrix_private->yStart(); 
 
1039
}
 
1040
 
 
1041
double Matrix::xEnd() const
 
1042
 
1043
        return d_matrix_private->xEnd(); 
 
1044
}
 
1045
 
 
1046
double Matrix::yEnd() const
 
1047
 
1048
        return d_matrix_private->yEnd(); 
 
1049
}
 
1050
 
 
1051
QString Matrix::formula() const
 
1052
 
1053
        return d_matrix_private->formula(); 
 
1054
}
 
1055
 
 
1056
void Matrix::setFormula(const QString & formula)
 
1057
{
 
1058
        WAIT_CURSOR;
 
1059
        exec(new MatrixSetFormulaCmd(d_matrix_private, formula));
 
1060
        RESET_CURSOR;
 
1061
}
 
1062
 
 
1063
char Matrix::numericFormat() const 
 
1064
 
1065
        return d_matrix_private->numericFormat(); 
 
1066
}
 
1067
 
 
1068
int Matrix::displayedDigits() const 
 
1069
 
1070
        return d_matrix_private->displayedDigits(); 
 
1071
}
 
1072
 
 
1073
void Matrix::save(QXmlStreamWriter * writer) const
 
1074
{
 
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();
 
1095
 
 
1096
        for (int col=0; col<cols; col++)
 
1097
                for (int row=0; row<rows; row++)
 
1098
                {
 
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();
 
1104
                }
 
1105
        for (int col=0; col<cols; col++)
 
1106
        {
 
1107
                writer->writeStartElement("column_width");
 
1108
                writer->writeAttribute("column", QString::number(col));
 
1109
                writer->writeCharacters(QString::number(columnWidth(col)));
 
1110
                writer->writeEndElement();
 
1111
        }
 
1112
        for (int row=0; row<rows; row++)
 
1113
        {
 
1114
                writer->writeStartElement("row_height");
 
1115
                writer->writeAttribute("row", QString::number(row));
 
1116
                writer->writeCharacters(QString::number(rowHeight(row)));
 
1117
                writer->writeEndElement();
 
1118
        }
 
1119
        writer->writeEndElement(); // "matrix"
 
1120
}
 
1121
 
 
1122
 
 
1123
bool Matrix::load(XmlStreamReader * reader)
 
1124
{
 
1125
        if(reader->isStartElement() && reader->name() == "matrix") 
 
1126
        {
 
1127
                setDimensions(0, 0);
 
1128
                setComment("");
 
1129
                setFormula("");
 
1130
                setNumericFormat('f');
 
1131
                setDisplayedDigits(6);
 
1132
                setCoordinates(0.0, 1.0, 0.0, 1.0);
 
1133
 
 
1134
                if (!readBasicAttributes(reader)) return false;
 
1135
 
 
1136
                // read dimensions
 
1137
                bool ok1, ok2;
 
1138
                int rows, cols;
 
1139
                rows = reader->readAttributeInt("rows", &ok1);
 
1140
                cols = reader->readAttributeInt("columns", &ok2);
 
1141
                if(!ok1 || !ok2) 
 
1142
                {
 
1143
                        reader->raiseError(tr("invalid row or column count"));
 
1144
                        return false;
 
1145
                }
 
1146
                setDimensions(rows, cols);
 
1147
 
 
1148
                // read child elements
 
1149
                while (!reader->atEnd()) 
 
1150
                {
 
1151
                        reader->readNext();
 
1152
 
 
1153
                        if (reader->isEndElement()) break;
 
1154
 
 
1155
                        if (reader->isStartElement()) 
 
1156
                        {
 
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
 
1173
                                {
 
1174
                                        reader->raiseWarning(tr("unknown element '%1'").arg(reader->name().toString()));
 
1175
                                        if (!reader->skipToEndElement()) return false;
 
1176
                                }
 
1177
                                if(!ret_val) return false;
 
1178
                        } 
 
1179
                }
 
1180
        }
 
1181
        else // no matrix element
 
1182
                reader->raiseError(tr("no matrix element found"));
 
1183
 
 
1184
        return !reader->hasError();
 
1185
}
 
1186
 
 
1187
bool Matrix::readDisplayElement(XmlStreamReader * reader)
 
1188
{
 
1189
        Q_ASSERT(reader->isStartElement() && reader->name() == "display");
 
1190
        QXmlStreamAttributes attribs = reader->attributes();
 
1191
 
 
1192
        QString str = attribs.value(reader->namespaceUri().toString(), "numeric_format").toString();
 
1193
        if(str.isEmpty() || str.length() != 1)
 
1194
        {
 
1195
                reader->raiseError(tr("invalid or missing numeric format"));
 
1196
                return false;
 
1197
        }
 
1198
        setNumericFormat(str.at(0).toAscii());
 
1199
        
 
1200
        bool ok;
 
1201
        int digits = reader->readAttributeInt("displayed_digits", &ok);
 
1202
        if(!ok)
 
1203
        {
 
1204
                reader->raiseError(tr("invalid or missing number of displayed digits"));
 
1205
                return false;
 
1206
        }
 
1207
        setDisplayedDigits(digits);
 
1208
        if (!reader->skipToEndElement()) return false;
 
1209
 
 
1210
        return true;
 
1211
}
 
1212
 
 
1213
bool Matrix::readCoordinatesElement(XmlStreamReader * reader)
 
1214
{
 
1215
        Q_ASSERT(reader->isStartElement() && reader->name() == "coordinates");
 
1216
 
 
1217
        bool ok;
 
1218
        int val;
 
1219
 
 
1220
        val = reader->readAttributeInt("x_start", &ok);
 
1221
        if(!ok)
 
1222
        {
 
1223
                reader->raiseError(tr("invalid x start value"));
 
1224
                return false;
 
1225
        }
 
1226
        setXStart(val);
 
1227
 
 
1228
        val = reader->readAttributeInt("x_end", &ok);
 
1229
        if(!ok)
 
1230
        {
 
1231
                reader->raiseError(tr("invalid x end value"));
 
1232
                return false;
 
1233
        }
 
1234
        setXEnd(val);
 
1235
 
 
1236
        val = reader->readAttributeInt("y_start", &ok);
 
1237
        if(!ok)
 
1238
        {
 
1239
                reader->raiseError(tr("invalid y start value"));
 
1240
                return false;
 
1241
        }
 
1242
        setYStart(val);
 
1243
 
 
1244
        val = reader->readAttributeInt("y_end", &ok);
 
1245
        if(!ok)
 
1246
        {
 
1247
                reader->raiseError(tr("invalid y end value"));
 
1248
                return false;
 
1249
        }
 
1250
        setYEnd(val);
 
1251
        if (!reader->skipToEndElement()) return false;
 
1252
 
 
1253
        return true;
 
1254
}
 
1255
 
 
1256
bool Matrix::readFormulaElement(XmlStreamReader * reader)
 
1257
{
 
1258
        Q_ASSERT(reader->isStartElement() && reader->name() == "formula");
 
1259
        setFormula(reader->readElementText());
 
1260
        return true;
 
1261
}
 
1262
 
 
1263
bool Matrix::readRowHeightElement(XmlStreamReader * reader)
 
1264
{
 
1265
        Q_ASSERT(reader->isStartElement() && reader->name() == "row_height");
 
1266
        bool ok;
 
1267
        int row = reader->readAttributeInt("row", &ok);
 
1268
        if(!ok)
 
1269
        {
 
1270
                reader->raiseError(tr("invalid or missing row index"));
 
1271
                return false;
 
1272
        }
 
1273
        QString str = reader->readElementText();
 
1274
        int value = str.toInt(&ok);
 
1275
        if(!ok)
 
1276
        {
 
1277
                reader->raiseError(tr("invalid row height"));
 
1278
                return false;
 
1279
        }
 
1280
        if (d_view)
 
1281
                d_view->setRowHeight(row, value);
 
1282
        else
 
1283
                setRowHeight(row, value);
 
1284
        return true;
 
1285
}
 
1286
 
 
1287
bool Matrix::readColumnWidthElement(XmlStreamReader * reader)
 
1288
{
 
1289
        Q_ASSERT(reader->isStartElement() && reader->name() == "column_width");
 
1290
        bool ok;
 
1291
        int col = reader->readAttributeInt("column", &ok);
 
1292
        if(!ok)
 
1293
        {
 
1294
                reader->raiseError(tr("invalid or missing column index"));
 
1295
                return false;
 
1296
        }
 
1297
        QString str = reader->readElementText();
 
1298
        int value = str.toInt(&ok);
 
1299
        if(!ok)
 
1300
        {
 
1301
                reader->raiseError(tr("invalid column width"));
 
1302
                return false;
 
1303
        }
 
1304
        if (d_view)
 
1305
                d_view->setColumnWidth(col, value);
 
1306
        else
 
1307
                setColumnWidth(col, value);
 
1308
        return true;
 
1309
}
 
1310
 
 
1311
bool Matrix::readCellElement(XmlStreamReader * reader)
 
1312
{
 
1313
        Q_ASSERT(reader->isStartElement() && reader->name() == "cell");
 
1314
        
 
1315
        QString str;
 
1316
        int row, col;
 
1317
        bool ok;
 
1318
 
 
1319
        QXmlStreamAttributes attribs = reader->attributes();
 
1320
        row = reader->readAttributeInt("row", &ok);
 
1321
        if(!ok)
 
1322
        {
 
1323
                reader->raiseError(tr("invalid or missing row index"));
 
1324
                return false;
 
1325
        }
 
1326
        col = reader->readAttributeInt("column", &ok);
 
1327
        if(!ok)
 
1328
        {
 
1329
                reader->raiseError(tr("invalid or missing column index"));
 
1330
                return false;
 
1331
        }
 
1332
 
 
1333
        str = reader->readElementText();
 
1334
        double value = str.toDouble(&ok);
 
1335
        if(!ok)
 
1336
        {
 
1337
                reader->raiseError(tr("invalid cell value"));
 
1338
                return false;
 
1339
        }
 
1340
        setCell(row, col, value);
 
1341
 
 
1342
        return true;
 
1343
}
 
1344
 
 
1345
void Matrix::setRowHeight(int row, int height) 
 
1346
 
1347
        d_matrix_private->setRowHeight(row, height); 
 
1348
}
 
1349
 
 
1350
void Matrix::setColumnWidth(int col, int width) 
 
1351
 
1352
        d_matrix_private->setColumnWidth(col, width); 
 
1353
}
 
1354
 
 
1355
int Matrix::rowHeight(int row) const 
 
1356
 
1357
        return d_matrix_private->rowHeight(row); 
 
1358
}
 
1359
 
 
1360
int Matrix::columnWidth(int col) const 
 
1361
 
1362
        return d_matrix_private->columnWidth(col); 
 
1363
}
 
1364
 
 
1365
void Matrix::adjustTabBarAction(bool visible)
 
1366
{
 
1367
        if(visible) 
 
1368
                action_toggle_tabbar->setText(tr("Hide Controls"));
 
1369
        else
 
1370
                action_toggle_tabbar->setText(tr("Show Controls"));
 
1371
}
 
1372
 
 
1373
QVector<double> Matrix::columnCells(int col, int first_row, int last_row)
 
1374
{
 
1375
        return d_matrix_private->columnCells(col, first_row, last_row);
 
1376
}
 
1377
 
 
1378
void Matrix::setColumnCells(int col, int first_row, int last_row, const QVector<double> & values)
 
1379
{
 
1380
        WAIT_CURSOR;
 
1381
        exec(new MatrixSetColumnCellsCmd(d_matrix_private, col, first_row, last_row, values));
 
1382
        RESET_CURSOR;
 
1383
}
 
1384
 
 
1385
QVector<double> Matrix::rowCells(int row, int first_column, int last_column)
 
1386
{
 
1387
        return d_matrix_private->rowCells(row, first_column, last_column);
 
1388
}
 
1389
 
 
1390
void Matrix::setRowCells(int row, int first_column, int last_column, const QVector<double> & values)
 
1391
{
 
1392
        WAIT_CURSOR;
 
1393
        exec(new MatrixSetRowCellsCmd(d_matrix_private, row, first_column, last_column, values));
 
1394
        RESET_CURSOR;
 
1395
}
 
1396
 
 
1397
void Matrix::transpose()
 
1398
{
 
1399
        WAIT_CURSOR;
 
1400
        exec(new MatrixTransposeCmd(d_matrix_private));
 
1401
        RESET_CURSOR;
 
1402
}
 
1403
 
 
1404
void Matrix::mirrorHorizontally()
 
1405
{
 
1406
        WAIT_CURSOR;
 
1407
        exec(new MatrixMirrorHorizontallyCmd(d_matrix_private));
 
1408
        RESET_CURSOR;
 
1409
}
 
1410
 
 
1411
void Matrix::mirrorVertically()
 
1412
{
 
1413
        WAIT_CURSOR;
 
1414
        exec(new MatrixMirrorVerticallyCmd(d_matrix_private));
 
1415
        RESET_CURSOR;
 
1416
}
 
1417
 
 
1418
void Matrix::recalculateSelectedCells()
 
1419
{
 
1420
        if (!d_view) return;
 
1421
#ifdef LEGACY_CODE_0_2_x
 
1422
        WAIT_CURSOR;
 
1423
        beginMacro(tr("%1: apply formula to selection").arg(name()));
 
1424
        emit recalculate();
 
1425
        endMacro();
 
1426
        RESET_CURSOR;
 
1427
#endif
 
1428
}
 
1429
 
 
1430
 
 
1431
/* ========================= static methods ======================= */
 
1432
ActionManager * Matrix::action_manager = 0;
 
1433
 
 
1434
ActionManager * Matrix::actionManager()
 
1435
{
 
1436
        if (!action_manager)
 
1437
                initActionManager();
 
1438
        
 
1439
        return action_manager;
 
1440
}
 
1441
 
 
1442
void Matrix::initActionManager()
 
1443
{
 
1444
        if (!action_manager)
 
1445
                action_manager = new ActionManager();
 
1446
 
 
1447
        action_manager->setTitle(tr("Matrix"));
 
1448
        volatile Matrix * action_creator = new Matrix(); // initialize the action texts
 
1449
        delete action_creator;
 
1450
}
 
1451
 
 
1452
Matrix * Matrix::fromImage(const QImage & image)
 
1453
{
 
1454
        int cols = image.width();
 
1455
        int rows = image.height();
 
1456
 
 
1457
        QProgressDialog progress;
 
1458
        progress.setRange(0, cols);
 
1459
        progress.setWindowTitle(tr("SciDAVis") + " - " + tr("Import image..."));
 
1460
        progress.raise();
 
1461
 
 
1462
        Matrix * matrix = new Matrix(0, rows, cols, tr("Matrix %1").arg(1));
 
1463
 
 
1464
        QVector<double> values;
 
1465
        values.resize(rows);
 
1466
 
 
1467
        for (int i=0; i<cols; i++)
 
1468
        {
 
1469
                for (int j=0; j<rows; j++)
 
1470
                        values[j] = qGray(image.pixel(i, rows - 1 - j));
 
1471
                
 
1472
                matrix->setColumnCells(i, 0, rows-1, values);
 
1473
 
 
1474
                if (i%5 == 4)
 
1475
                {
 
1476
                    progress.setValue(i);
 
1477
                    QApplication::processEvents();
 
1478
                }
 
1479
 
 
1480
        if (progress.wasCanceled())
 
1481
            break;
 
1482
        }
 
1483
 
 
1484
        if (progress.wasCanceled())
 
1485
        {
 
1486
                delete matrix;
 
1487
                return NULL;
 
1488
        }
 
1489
        return matrix;
 
1490
}
 
1491
 
 
1492
/* ========================== Matrix::Private ====================== */
 
1493
 
 
1494
Matrix::Private::Private(Matrix *owner) 
 
1495
        : d_owner(owner), d_column_count(0), d_row_count(0) 
 
1496
{
 
1497
        d_block_change_signals = false;
 
1498
        d_numeric_format = 'f';
 
1499
        d_displayed_digits = 6;
 
1500
        d_x_start = 0.0;
 
1501
        d_x_end = 1.0;  
 
1502
        d_y_start = 0.0; 
 
1503
        d_y_end = 1.0;
 
1504
}
 
1505
 
 
1506
void Matrix::Private::insertColumns(int before, int count)
 
1507
{
 
1508
        Q_ASSERT(before >= 0);
 
1509
        Q_ASSERT(before <= d_column_count);
 
1510
 
 
1511
        emit d_owner->columnsAboutToBeInserted(before, count);
 
1512
        for(int i=0; i<count; i++)
 
1513
        {
 
1514
                d_data.insert(before+i, QVector<double>(d_row_count));
 
1515
                d_column_widths.insert(before+i, Matrix::defaultColumnWidth());
 
1516
        }
 
1517
 
 
1518
        d_column_count += count;
 
1519
        emit d_owner->columnsInserted(before, count);
 
1520
}
 
1521
 
 
1522
void Matrix::Private::removeColumns(int first, int count)
 
1523
{
 
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);
 
1532
}
 
1533
 
 
1534
void Matrix::Private::insertRows(int before, int count)
 
1535
{
 
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());
 
1544
 
 
1545
        d_row_count += count;
 
1546
        emit d_owner->rowsInserted(before, count);
 
1547
}
 
1548
 
 
1549
void Matrix::Private::removeRows(int first, int count)
 
1550
{
 
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);
 
1558
 
 
1559
        d_row_count -= count;
 
1560
        emit d_owner->rowsRemoved(first, count);
 
1561
}
 
1562
 
 
1563
double Matrix::Private::cell(int row, int col) const
 
1564
{
 
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);
 
1568
}
 
1569
 
 
1570
void Matrix::Private::setCell(int row, int col, double value)
 
1571
{
 
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);
 
1577
}
 
1578
 
 
1579
QVector<double> Matrix::Private::columnCells(int col, int first_row, int last_row)
 
1580
{
 
1581
        Q_ASSERT(first_row >= 0 && first_row < d_row_count);
 
1582
        Q_ASSERT(last_row >= 0 && last_row < d_row_count);
 
1583
 
 
1584
        if(first_row == 0 && last_row == d_row_count-1)
 
1585
                return d_data.at(col);
 
1586
 
 
1587
        QVector<double> result;
 
1588
        for(int i=first_row; i<=last_row; i++)
 
1589
                result.append(d_data.at(col).at(i));
 
1590
        return result;
 
1591
}
 
1592
 
 
1593
void Matrix::Private::setColumnCells(int col, int first_row, int last_row, const QVector<double> & values)
 
1594
{
 
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);
 
1598
 
 
1599
        if(first_row == 0 && last_row == d_row_count-1)
 
1600
        {
 
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);
 
1605
                return;
 
1606
        }
 
1607
 
 
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);
 
1612
}
 
1613
 
 
1614
QVector<double> Matrix::Private::rowCells(int row, int first_column, int last_column)
 
1615
{
 
1616
        Q_ASSERT(first_column >= 0 && first_column < d_column_count);
 
1617
        Q_ASSERT(last_column >= 0 && last_column < d_column_count);
 
1618
 
 
1619
        QVector<double> result;
 
1620
        for(int i=first_column; i<=last_column; i++)
 
1621
                result.append(d_data.at(i).at(row));
 
1622
        return result;
 
1623
}
 
1624
 
 
1625
void Matrix::Private::setRowCells(int row, int first_column, int last_column, const QVector<double> & values)
 
1626
{
 
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);
 
1630
 
 
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);
 
1635
}
 
1636
 
 
1637
void Matrix::Private::clearColumn(int col)
 
1638
{
 
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);
 
1642
}
 
1643
 
 
1644
double Matrix::Private::xStart() const
 
1645
{
 
1646
        return d_x_start;
 
1647
}
 
1648
 
 
1649
double Matrix::Private::yStart() const
 
1650
{
 
1651
        return d_y_start;
 
1652
}
 
1653
 
 
1654
double Matrix::Private::xEnd() const
 
1655
 
1656
        return d_x_end;
 
1657
}
 
1658
 
 
1659
double Matrix::Private::yEnd() const
 
1660
 
1661
        return d_y_end;
 
1662
}
 
1663
 
 
1664
void Matrix::Private::setXStart(double x)
 
1665
 
1666
        d_x_start = x;
 
1667
        emit d_owner->coordinatesChanged();
 
1668
}
 
1669
 
 
1670
void Matrix::Private::setXEnd(double x)
 
1671
 
1672
        d_x_end = x;
 
1673
        emit d_owner->coordinatesChanged();
 
1674
}
 
1675
 
 
1676
void Matrix::Private::setYStart(double y)
 
1677
 
1678
        d_y_start = y;
 
1679
        emit d_owner->coordinatesChanged();
 
1680
}
 
1681
 
 
1682
void Matrix::Private::setYEnd(double y)
 
1683
 
1684
        d_y_end = y;
 
1685
        emit d_owner->coordinatesChanged();
 
1686
}
 
1687
 
 
1688
QString Matrix::Private::formula() const
 
1689
 
1690
        return d_formula;
 
1691
}
 
1692
 
 
1693
void Matrix::Private::setFormula(const QString & formula)
 
1694
 
1695
        d_formula = formula;
 
1696
        emit d_owner->formulaChanged();
 
1697
}
 
1698
 
 
1699
} // namespace