1
/***************************************************************************
4
Description : Aspect providing a spreadsheet table with column logic
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
#ifndef FUTURE_TABLE_H
32
#define FUTURE_TABLE_H
34
#include "core/AbstractPart.h"
35
#ifndef LEGACY_CODE_0_2_x
36
#include "AbstractScriptingEngine.h"
40
#include <QStringList>
50
class TableStatistics;
55
/*!\brief Aspect providing a spreadsheet table with column logic.
57
This class (incl. Table::Private and its commands) is one aspect in the projet hierarchy
58
that represents a spreadsheet table with column logic. Table provides the public API while
59
Table::Private completely encapsulates the data. The table commands (derived from QUndoCommand)
60
encapsulate all write operations which can be undone and redone, if the table has an undo stack
61
associated with it (usually by the project root aspect).
63
The underlying private data object is not visible to any classes other then those meantioned
64
above with one exeption:
65
Pointers to columns can be passed around an manipulated directly. The owner Table (parent aspect
66
of the Column objects) will be notified by emission of signals and react accordingly.
67
All public methods of Table and Column are undo aware.
69
Table also manages its main view of class TableView. Table and TableView can call each others
70
API in both directions. User interaction ist party handled in TableView and translated into
71
Table API calls (e.g., when a user edits a cell this will be handled by the delegate of
72
TableView and Table will not know whether a script or a user changed the data.). Other parts
73
of the user interaction are handled by actions provides by Table, e.g., via a context menu.
75
Selections are handled by TableView and can be queried by Table. All selection based functions
76
do nothing unless the view exists. The view is created by the first call to view();
78
#ifndef LEGACY_CODE_0_2_x
79
class Table : public AbstractPart, public scripted
81
class Table : public AbstractPart
87
class Private; // This could also be private, but then all commands need to be friend classes
90
#ifndef LEGACY_CODE_0_2_x
91
Table(AbstractScriptingEngine *engine, int rows, int columns, const QString &name);
93
Table(void *engine, int rows, int columns, const QString &name);
94
void setView(TableView * view);
95
friend class ::TableStatistics;
99
//! Return an icon to be used for decorating my views.
100
virtual QIcon icon() const;
101
//! Return a new context menu.
103
* The caller takes ownership of the menu.
105
virtual QMenu *createContextMenu() const;
106
//! Construct a primary view on me.
108
* This method may be called multiple times during the life time of an Aspect, or it might not get
109
* called at all. Aspects must not depend on the existence of a view for their operation.
111
virtual QWidget *view();
115
* Ownership of the columns is transferred to this Table.
117
* If before == columnCount() this will do the same as appendColumns();
119
void insertColumns(int before, QList<Column *> new_cols);
122
* Convenience function, same as:
124
* insertColumns(columnCount(), new_cols);
127
void appendColumns(QList<Column*> new_cols) { insertColumns(columnCount(), new_cols); }
128
void removeColumns(int first, int count);
129
void removeColumn(Column * col);
130
void removeRows(int first, int count);
131
void insertRows(int before, int count);
132
void appendRows(int count) { insertRows(rowCount(), count); }
133
//! Set the number of rows of the table
134
void setRowCount(int new_size);
135
//! Return the total number of columns in the table
136
int columnCount() const;
137
//! Return the total number of rows in the table
138
int rowCount() const;
139
//! Return the number of columns matching the given designation
140
int columnCount(SciDAVis::PlotDesignation pd) const;
141
//! Return column number 'index'
142
Column* column(int index) const;
143
//! Return the column determined by the given name
145
* This method should not be used unless absolutely necessary.
146
* Columns should be addressed by their index.
147
* This method is mainly meant to be used in scripts.
149
Column* column(const QString & name) const;
150
int columnIndex(const Column * col) const;
151
//! Set the number of columns
152
void setColumnCount(int new_size);
153
QVariant headerData(int section, Qt::Orientation orientation,int role) const;
155
//! Create a menu with selection related operations
157
* \param append_to if a pointer to a QMenu is passed
158
* to the function, the actions are appended to
159
* it instead of the creation of a new menu.
161
QMenu * createSelectionMenu(QMenu * append_to = 0);
162
//! Create a menu with column related operations
164
* \param append_to if a pointer to a QMenu is passed
165
* to the function, the actions are appended to
166
* it instead of the creation of a new menu.
168
QMenu * createColumnMenu(QMenu * append_to = 0);
169
//! Create a menu with row related operations
171
* \param append_to if a pointer to a QMenu is passed
172
* to the function, the actions are appended to
173
* it instead of the creation of a new menu.
175
QMenu * createRowMenu(QMenu * append_to = 0);
176
//! Create a menu with table related operations
178
* \param append_to if a pointer to a QMenu is passed
179
* to the function, the actions are appended to
180
* it instead of the creation of a new menu.
182
QMenu * createTableMenu(QMenu * append_to = 0);
183
//! Fill the part specific menu for the main window including setting the title
185
* \return true on success, otherwise false (e.g. part has no actions).
187
virtual bool fillProjectMenu(QMenu * menu);
188
//! Fill the part specific tool bar for the main window including setting the title
190
* \return true on success, otherwise false (e.g. part has no actions to be shown in a toolbar).
192
virtual bool fillProjectToolBar(QToolBar * bar);
194
//! Determine the corresponding X column
196
//! Determine the corresponding Y column
200
* The table takes ownership of the menu.
202
void setPlotMenu(QMenu * menu);
203
//! Open the sort dialog for the given columns
204
void sortDialog(QList<Column*> cols);
205
//! Set default for comment visibility for table views
206
static void setDefaultCommentVisibility(bool visible) { d_default_comment_visibility = visible; }
207
//! Return the default for comment visibility for table views
208
static bool defaultCommentVisibility() { return d_default_comment_visibility; }
209
//! Return the text displayed in the given cell
210
QString text(int row, int col);
211
void setSelectionAs(SciDAVis::PlotDesignation pd);
212
void copy(Table * other);
214
//! \name serialize/deserialize
217
virtual void save(QXmlStreamWriter *) const;
219
virtual bool load(XmlStreamReader *);
220
bool readColumnWidthElement(XmlStreamReader * reader);
224
static ActionManager * actionManager();
225
static void initActionManager();
226
static int defaultColumnWidth() { return default_column_width; }
227
static void setDefaultColumnWidth(int width) { default_column_width = width; }
229
static ActionManager * action_manager;
230
// TODO: the default sizes are to be controlled by the global Table settings
231
static int default_column_width;
232
//! Private ctor for initActionManager() only
236
//! Clear the whole table
238
#ifndef LEGACY_CODE_0_2_x
239
//! Clear all mask in the table
243
//! Append one column
245
//! Append as many columns as are selected
247
//! Append as many rows as are selected
250
void copySelection();
251
void pasteIntoSelection();
252
void clearSelectedCells();
254
#ifndef LEGACY_CODE_0_2_x
255
void maskSelection();
256
void unmaskSelection();
258
void setFormulaForSelection();
259
void recalculateSelectedCells();
260
void fillSelectedCellsWithRowNumbers();
261
void fillSelectedCellsWithRandomNumbers();
262
//! Open the sort dialog for all columns
264
//! Insert columns depending on the selection
265
void insertEmptyColumns();
266
void removeSelectedColumns();
267
void clearSelectedColumns();
268
void clearSelectedRows();
269
void setSelectedColumnsAsX();
270
void setSelectedColumnsAsY();
271
void setSelectedColumnsAsZ();
272
void setSelectedColumnsAsXError();
273
void setSelectedColumnsAsYError();
274
void setSelectedColumnsAsNone();
275
void normalizeColumns(QList< Column* > cols);
276
void normalizeSelectedColumns();
277
void normalizeSelection();
278
void sortSelectedColumns();
279
void statisticsOnSelectedColumns();
280
void statisticsOnSelectedRows();
281
//! Insert rows depending on the selection
282
void insertEmptyRows();
283
void removeSelectedRows();
285
void dimensionsDialog();
286
void editTypeAndFormatOfSelectedColumns();
287
void editDescriptionOfCurrentColumn();
288
void moveColumn(int from, int to);
289
//! Sort the given list of column
291
* If 'leading' is a null pointer, each column is sorted separately.
293
void sortColumns(Column * leading, QList<Column*> cols, bool ascending);
294
//! Show a context menu for the selected cells
296
* \param pos global position of the event
298
void showTableViewContextMenu(const QPoint& pos);
299
//! Show a context menu for the selected columns
301
* \param pos global position of the event
303
void showTableViewColumnContextMenu(const QPoint& pos);
304
//! Show a context menu for the selected rows
306
* \param pos global position of the event
308
void showTableViewRowContextMenu(const QPoint& pos);
311
//! Called after a new child has been inserted or added.
313
* Unlike the aspectAdded() signals, this method does not get called inside undo/redo actions;
314
* allowing subclasses to execute undo commands of their own.
316
virtual void completeAspectInsertion(AbstractAspect * aspect, int index);
317
//! Called before a child is removed.
319
* Unlike the aspectAboutToBeRemoved() signals, this method does not get called inside undo/redo actions;
320
* allowing subclasses to execute undo commands of their own.
322
virtual void prepareAspectRemoval(AbstractAspect * aspect);
325
//! This method should only be called by the view.
326
/** This method does not change the view, it only changes the
327
* values that are saved when the table is saved. The view
328
* has to take care of reading and applying these values */
329
void setColumnWidth(int col, int width);
330
int columnWidth(int col) const;
333
//! Internal function to connect all column signals
334
void connectColumn(const Column* col);
335
//! Internal function to disconnect a column
336
void disconnectColumn(const Column* col);
339
//! \name Column event handlers
341
void handleDescriptionChange(const AbstractAspect * aspect);
342
void handleModeChange(const AbstractColumn * col);
343
void handlePlotDesignationChange(const AbstractColumn * col);
344
void handleDataChange(const AbstractColumn * col);
345
void handleRowsAboutToBeInserted(const AbstractColumn * col, int before, int count);
346
void handleRowsInserted(const AbstractColumn * col, int before, int count);
347
void handleRowsAboutToBeRemoved(const AbstractColumn * col, int first, int count);
348
void handleRowsRemoved(const AbstractColumn * col, int first, int count);
350
void adjustActionNames();
353
void columnsAboutToBeInserted(int before, QList<Column*> new_cols);
354
void columnsInserted(int first, int count);
355
void columnsAboutToBeReplaced(int first, int count);
356
void columnsReplaced(int first, int count);
357
void columnsAboutToBeRemoved(int first, int count);
358
void columnsRemoved(int first, int count);
359
void rowsAboutToBeInserted(int before, int count);
360
void rowsInserted(int first, int count);
361
void rowsAboutToBeRemoved(int first, int count);
362
void rowsRemoved(int first, int count);
363
void dataChanged(int top, int left, int bottom, int right);
364
void headerDataChanged(Qt::Orientation orientation, int first, int last);
365
#ifdef LEGACY_CODE_0_2_x
367
void requestRowStatistics();
368
void requestColumnStatistics();
372
void createActions();
373
void connectActions();
374
void addActionsToView();
376
static bool d_default_comment_visibility;
378
//! \name selection related actions
380
QAction * action_cut_selection;
381
QAction * action_copy_selection;
382
QAction * action_paste_into_selection;
383
#ifndef LEGACY_CODE_0_2_x
384
QAction * action_mask_selection;
385
QAction * action_unmask_selection;
387
QAction * action_set_formula;
388
QAction * action_clear_selection;
389
QAction * action_recalculate;
390
QAction * action_fill_row_numbers;
391
QAction * action_fill_random;
392
QAction * action_normalize_selection;
394
//! \name table related actions
396
QAction * action_toggle_comments;
397
QAction * action_toggle_tabbar;
398
QAction * action_select_all;
399
QAction * action_add_column;
400
QAction * action_clear_table;
401
#ifndef LEGACY_CODE_0_2_x
402
QAction * action_clear_masks;
404
QAction * action_sort_table;
405
QAction * action_go_to_cell;
406
QAction * action_dimensions_dialog;
407
QAction * action_formula_mode;
409
//! \name column related actions
411
QAction * action_insert_columns;
412
QAction * action_remove_columns;
413
QAction * action_clear_columns;
414
QAction * action_add_columns;
415
QAction * action_set_as_x;
416
QAction * action_set_as_y;
417
QAction * action_set_as_z;
418
QAction * action_set_as_xerr;
419
QAction * action_set_as_yerr;
420
QAction * action_set_as_none;
421
QAction * action_normalize_columns;
422
QAction * action_sort_columns;
423
QAction * action_statistics_columns;
424
QAction * action_type_format;
425
QAction * action_edit_description;
427
//! \name row related actions
429
QAction * action_insert_rows;
430
QAction * action_remove_rows;
431
QAction * action_clear_rows;
432
QAction * action_add_rows;
433
QAction * action_statistics_rows;
437
Private *d_table_private;
441
This private class manages column based data (i.e., 1D vector based
442
data such as x-values and y-values for a plot) for a Table. Its
443
API is to be called by Table and table commands only. Table
444
may only call the reading functions to ensure that undo/redo
445
is possible for all data changing operations.
447
Each column is represented by a Column object and can be directly
448
accessed by the pointer returned by column(). Most of the column
449
manipulation is done directly to the columns. The signals of
450
the columns are connected to various handlers in Table which
451
acts according to all changes made to the columns.
453
The Column objects are managed as child aspects by Table.
455
Every column has two filters as children: An input filter that
456
can convert a string (e.g., entered by the user in a cell) to
457
the column's data type and an output filter that delivers
458
the correct string representation to display in a table.
460
The number of columns in the Table will always be equal to
461
d_columns.size(). The number of rows is generally indepenent
462
of the number of rows in the wrapped columns. It is however
463
always adjusted to be large enough to display the longest column.
464
When columns are inserted, resized etc., the table is resized
470
Private(Table *owner) : d_owner(owner), d_column_count(0), d_row_count(0) {}
471
//! Replace columns completely
473
* \param first the first column to be replaced
474
* \param new_cols list of the columns that replace the old ones
475
* This does not delete the replaced columns.
477
void replaceColumns(int first, QList<Column*> new_cols);
478
//! Insert columns before column number 'before'
480
* If 'first' is equal to the number of columns,
481
* the columns will be appended.
482
* \param before index of the column to insert before
483
* \param cols a list of column data objects
485
void insertColumns(int before, QList<Column*> cols);
488
* This does not delete the removed columns because this
489
* must be handled by the undo/redo system.
490
* \param first index of the first column to be removed
491
* \param count number of columns to remove
493
void removeColumns(int first, int count);
494
//! Append columns to the table
496
* \sa insertColumns()
498
void appendColumns(QList<Column*> cols);
499
//! Move a column to another position
500
void moveColumn(int from, int to);
501
//! Return the number of columns in the table
502
int columnCount() const { return d_column_count; }
503
//! Return the number of rows in the table
504
int rowCount() const { return d_row_count; }
505
//! Set the number of rows of the table
506
void setRowCount(int count);
507
//! Return the full column header string
508
QString columnHeader(int col);
509
//! Return the number of columns with a given plot designation
510
int numColsWithPD(SciDAVis::PlotDesignation pd);
511
//! Return column number 'index'
512
Column* column(int index) const;
513
//! Return the index of the given column in the table.
515
* \return the index or -1 if the column is not in the table
517
int columnIndex(const Column * col) const
519
for(int i=0; i<d_columns.size(); i++)
520
if(d_columns.at(i) == col) return i;
523
QString name() const { return d_owner->name(); }
524
QVariant headerData(int section, Qt::Orientation orientation,int role) const;
526
//! Update the vertical header labels
528
* This must be called whenever rows are added
530
* \param start_row first row that needs to be updated
532
void updateVerticalHeader(int start_row);
533
//! Update the horizontal header labels
535
* This must be called whenever columns are added or
536
* removed and when comments, labels, and column types
538
* \param start_col first column that needs to be updated
539
* \param end_col last column that needs to be updated
541
void updateHorizontalHeader(int start_col, int end_col);
542
void setColumnWidth(int col, int width) { d_column_widths[col] = width; }
543
int columnWidth(int col) const { return d_column_widths.at(col); }
548
//! The number of columns
550
//! The maximum number of rows of all columns
552
//! Vertical header data
553
QStringList d_vertical_header_data;
554
//! Horizontal header data
555
QStringList d_horizontal_header_data;
556
//! List of pointers to the column data vectors
557
QList<Column *> d_columns;
558
//! Internal function to put together the column header
560
* Don't use this outside updateHorizontalHeader()
562
void composeColumnHeader(int col, const QString& label);
564
QList<int> d_column_widths;