labplot  2.8.2
About: LabPlot is an application for plotting and analysis of 2D and 3D functions and data. It is a complete rewrite of LabPlot1 and lacks in the first release a lot of features available in the predecessor. On the other hand, the GUI and the usability is more superior.
  Fossies Dox: labplot-2.8.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

MatrixView.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  File : MatrixView.cpp
3  Project : LabPlot
4  Description : View class for Matrix
5  --------------------------------------------------------------------
6  Copyright : (C) 2008-2009 Tilman Benkert (thzs@gmx.net)
7  Copyright : (C) 2015-2019 Alexander Semke (alexander.semke@web.de)
8  Copyright : (C) 2017 Stefan Gerlach (stefan.gerlach@uni.kn)
9 
10  ***************************************************************************/
11 
12 /***************************************************************************
13  * *
14  * This program is free software; you can redistribute it and/or modify *
15  * it under the terms of the GNU General Public License as published by *
16  * the Free Software Foundation; either version 2 of the License, or *
17  * (at your option) any later version. *
18  * *
19  * This program is distributed in the hope that it will be useful, *
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22  * GNU General Public License for more details. *
23  * *
24  * You should have received a copy of the GNU General Public License *
25  * along with this program; if not, write to the Free Software *
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
27  * Boston, MA 02110-1301 USA *
28  * *
29  ***************************************************************************/
30 
31 
33 #include "backend/matrix/Matrix.h"
36 #include "backend/lib/macros.h"
39 
43 
44 #include <KLocalizedString>
45 
46 #include <QAction>
47 #include <QStackedWidget>
48 #include <QTableView>
49 #include <QKeyEvent>
50 #include <QMenu>
51 #include <QPainter>
52 #include <QPrinter>
53 #include <QScrollArea>
54 #include <QInputDialog>
55 #include <QClipboard>
56 #include <QMimeData>
57 #include <QTextStream>
58 #include <QThreadPool>
59 #include <QMutex>
60 #include <QProcess>
61 #include <QHeaderView>
62 #include <QIcon>
63 
64 #include <cfloat>
65 #include <cmath>
66 
67 MatrixView::MatrixView(Matrix* matrix) : QWidget(),
68  m_stackedWidget(new QStackedWidget(this)),
69  m_tableView(new QTableView(this)),
70  m_imageLabel(new QLabel(this)),
71  m_matrix(matrix),
72  m_model(new MatrixModel(matrix)) {
73 
74  init();
75 
76  //resize the view to show a 10x10 region of the matrix.
77  //no need to resize the view when the project is being opened,
78  //all views will be resized to the stored values at the end
79  if (!m_matrix->isLoading()) {
80  int w = m_tableView->horizontalHeader()->sectionSize(0)*10 + m_tableView->verticalHeader()->width();
81  int h = m_tableView->verticalHeader()->sectionSize(0)*10 + m_tableView->horizontalHeader()->height();
82  resize(w+50, h+50);
83  }
84 }
85 
87  delete m_model;
88 }
89 
91  return m_model;
92 }
93 
95  initActions();
97  initMenus();
98 
99  auto* layout = new QHBoxLayout(this);
100  layout->setContentsMargins(0, 0, 0, 0);
101  setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
102  setFocusPolicy(Qt::StrongFocus);
103  setFocus();
104  installEventFilter(this);
105 
106  layout->addWidget(m_stackedWidget);
107 
108  //table data view
109  m_tableView->setModel(m_model);
110  m_stackedWidget->addWidget(m_tableView);
111 
112  //horizontal header
113  QHeaderView* h_header = m_tableView->horizontalHeader();
114  h_header->setSectionsMovable(false);
115  h_header->installEventFilter(this);
116 
117  //vertical header
118  QHeaderView* v_header = m_tableView->verticalHeader();
119  v_header->setSectionsMovable(false);
120  v_header->installEventFilter(this);
121 
122  //set the header sizes to the (potentially user customized) sizes stored in Matrix
123  adjustHeaders();
124 
125  //image view
126  auto* area = new QScrollArea(this);
127  m_stackedWidget->addWidget(area);
128  area->setWidget(m_imageLabel);
129 
130  //SLOTs
133 
134  //keyboard shortcuts
135  sel_all = new QShortcut(QKeySequence(tr("Ctrl+A", "Matrix: select all")), m_tableView);
136  connect(sel_all, &QShortcut::activated, m_tableView, &QTableView::selectAll);
137 
138  //TODO: add shortcuts for copy&paste,
139  //for a single shortcut we need to descriminate between copy&paste for columns, rows or selected cells.
140 }
141 
143  // selection related actions
144  action_cut_selection = new QAction(QIcon::fromTheme("edit-cut"), i18n("Cu&t"), this);
145  action_copy_selection = new QAction(QIcon::fromTheme("edit-copy"), i18n("&Copy"), this);
146  action_paste_into_selection = new QAction(QIcon::fromTheme("edit-paste"), i18n("Past&e"), this);
147  action_clear_selection = new QAction(QIcon::fromTheme("edit-clear"), i18n("Clea&r Selection"), this);
148  action_select_all = new QAction(QIcon::fromTheme("edit-select-all"), i18n("Select All"), this);
149 
150  // matrix related actions
151  auto* viewActionGroup = new QActionGroup(this);
152  viewActionGroup->setExclusive(true);
153  action_data_view = new QAction(QIcon::fromTheme("labplot-matrix"), i18n("Data"), viewActionGroup);
154  action_data_view->setCheckable(true);
155  action_data_view->setChecked(true);
156  action_image_view = new QAction(QIcon::fromTheme("image-x-generic"), i18n("Image"), viewActionGroup);
157  action_image_view->setCheckable(true);
158  connect(viewActionGroup, &QActionGroup::triggered, this, &MatrixView::switchView);
159 
160  action_fill_function = new QAction(QIcon::fromTheme(QString()), i18n("Function Values"), this);
161  action_fill_const = new QAction(QIcon::fromTheme(QString()), i18n("Const Values"), this);
162  action_clear_matrix = new QAction(QIcon::fromTheme("edit-clear"), i18n("Clear Matrix"), this);
163  action_go_to_cell = new QAction(QIcon::fromTheme("go-jump"), i18n("&Go to Cell"), this);
164 
165  action_transpose = new QAction(i18n("&Transpose"), this);
166  action_mirror_horizontally = new QAction(QIcon::fromTheme("object-flip-horizontal"), i18n("Mirror &Horizontally"), this);
167  action_mirror_vertically = new QAction(QIcon::fromTheme("object-flip-vertical"), i18n("Mirror &Vertically"), this);
168 
169  action_add_value = new QAction(i18n("Add Value"), this);
171  action_subtract_value = new QAction(i18n("Subtract Value"), this);
173  action_multiply_value = new QAction(i18n("Multiply Value"), this);
175  action_divide_value = new QAction(i18n("Divide Value"), this);
177 
178 // action_duplicate = new QAction(i18nc("duplicate matrix", "&Duplicate"), this);
179  //TODO
180  //icon
181  auto* headerFormatActionGroup = new QActionGroup(this);
182  headerFormatActionGroup->setExclusive(true);
183  action_header_format_1= new QAction(i18n("Rows and Columns"), headerFormatActionGroup);
184  action_header_format_1->setCheckable(true);
185  action_header_format_2= new QAction(i18n("xy-Values"), headerFormatActionGroup);
186  action_header_format_2->setCheckable(true);
187  action_header_format_3= new QAction(i18n("Rows, Columns and xy-Values"), headerFormatActionGroup);
188  action_header_format_3->setCheckable(true);
189  connect(headerFormatActionGroup, &QActionGroup::triggered, this, &MatrixView::headerFormatChanged);
190 
191  // column related actions
192  action_add_columns = new QAction(QIcon::fromTheme("edit-table-insert-column-right"), i18n("&Add Columns"), this);
193  action_insert_columns = new QAction(QIcon::fromTheme("edit-table-insert-column-left"), i18n("&Insert Empty Columns"), this);
194  action_remove_columns = new QAction(QIcon::fromTheme("edit-table-delete-column"), i18n("Remo&ve Columns"), this);
195  action_clear_columns = new QAction(QIcon::fromTheme("edit-clear"), i18n("Clea&r Columns"), this);
196  action_statistics_columns = new QAction(QIcon::fromTheme("view-statistics"), i18n("Statisti&cs"), this);
197 
198  // row related actions
199  action_add_rows = new QAction(QIcon::fromTheme("edit-table-insert-row-above"), i18n("&Add Rows"), this);
200  action_insert_rows = new QAction(QIcon::fromTheme("edit-table-insert-row-above") ,i18n("&Insert Empty Rows"), this);
201  action_remove_rows = new QAction(QIcon::fromTheme("edit-table-delete-row"), i18n("Remo&ve Rows"), this);
202  action_clear_rows = new QAction(QIcon::fromTheme("edit-clear"), i18n("Clea&r Rows"), this);
203  action_statistics_rows = new QAction(QIcon::fromTheme("view-statistics"), i18n("Statisti&cs"), this);
204 }
205 
207  const QAction* action = dynamic_cast<const QAction*>(QObject::sender());
209  auto* dlg = new AddSubtractValueDialog(m_matrix, op);
210  dlg->setMatrices();
211  dlg->exec();
212 }
213 
215  // selection related actions
216  connect(action_cut_selection, &QAction::triggered, this, &MatrixView::cutSelection);
217  connect(action_copy_selection, &QAction::triggered, this, &MatrixView::copySelection);
218  connect(action_paste_into_selection, &QAction::triggered, this, &MatrixView::pasteIntoSelection);
219  connect(action_clear_selection, &QAction::triggered, this, &MatrixView::clearSelectedCells);
220  connect(action_select_all, &QAction::triggered, m_tableView, &QTableView::selectAll);
221 
222  // matrix related actions
223  connect(action_fill_function, &QAction::triggered, this, &MatrixView::fillWithFunctionValues);
224  connect(action_fill_const, &QAction::triggered, this, &MatrixView::fillWithConstValues);
225 
226  connect(action_go_to_cell, &QAction::triggered, this, QOverload<>::of(&MatrixView::goToCell));
227  //connect(action_duplicate, &QAction::triggered, this, &MatrixView::duplicate);
228  connect(action_clear_matrix, &QAction::triggered, m_matrix, &Matrix::clear);
229  connect(action_transpose, &QAction::triggered, m_matrix, &Matrix::transpose);
230  connect(action_mirror_horizontally, &QAction::triggered, m_matrix, &Matrix::mirrorHorizontally);
231  connect(action_mirror_vertically, &QAction::triggered, m_matrix, &Matrix::mirrorVertically);
232  connect(action_add_value, &QAction::triggered, this, &MatrixView::modifyValues);
233  connect(action_subtract_value, &QAction::triggered, this, &MatrixView::modifyValues);
234  connect(action_multiply_value, &QAction::triggered, this, &MatrixView::modifyValues);
235  connect(action_divide_value, &QAction::triggered, this, &MatrixView::modifyValues);
236 
237  // column related actions
238  connect(action_add_columns, &QAction::triggered, this, &MatrixView::addColumns);
239  connect(action_insert_columns, &QAction::triggered, this, &MatrixView::insertEmptyColumns);
240  connect(action_remove_columns, &QAction::triggered, this, &MatrixView::removeSelectedColumns);
241  connect(action_clear_columns, &QAction::triggered, this, &MatrixView::clearSelectedColumns);
242  connect(action_statistics_columns, &QAction::triggered, this, &MatrixView::showColumnStatistics);
243 
244  // row related actions
245  connect(action_add_rows, &QAction::triggered, this, &MatrixView::addRows);
246  connect(action_insert_rows, &QAction::triggered, this, &MatrixView::insertEmptyRows);
247  connect(action_remove_rows, &QAction::triggered, this, &MatrixView::removeSelectedRows);
248  connect(action_clear_rows, &QAction::triggered, this, &MatrixView::clearSelectedRows);
249  connect(action_statistics_rows, &QAction::triggered, this, &MatrixView::showRowStatistics);
250 }
251 
253  //selection menu
254  m_selectionMenu = new QMenu(i18n("Selection"), this);
255  m_selectionMenu->setIcon(QIcon::fromTheme("selection"));
260 
261  //column menu
262  m_columnMenu = new QMenu(this);
267 
268  //row menu
269  m_rowMenu = new QMenu(this);
270  m_rowMenu->addAction(action_insert_rows);
271  m_rowMenu->addAction(action_remove_rows);
272  m_rowMenu->addAction(action_clear_rows);
273  m_rowMenu->addAction(action_statistics_rows);
274 
275  //matrix menu
276  m_matrixMenu = new QMenu(this);
277 
278  m_matrixMenu->addMenu(m_selectionMenu);
279  m_matrixMenu->addSeparator();
280 
281  QMenu* submenu = new QMenu(i18n("Generate Data"), this);
282  submenu->addAction(action_fill_const);
283  submenu->addAction(action_fill_function);
284  m_matrixMenu->addMenu(submenu);
285  m_matrixMenu->addSeparator();
286 
287  // Data manipulation sub-menu
288  QMenu* dataManipulationMenu = new QMenu(i18n("Manipulate Data"), this);
289  dataManipulationMenu->addAction(action_add_value);
290  dataManipulationMenu->addAction(action_subtract_value);
291  dataManipulationMenu->addAction(action_multiply_value);
292  dataManipulationMenu->addAction(action_divide_value);
293  dataManipulationMenu->addSeparator();
294  dataManipulationMenu->addAction(action_mirror_horizontally);
295  dataManipulationMenu->addAction(action_mirror_vertically);
296  dataManipulationMenu->addSeparator();
297  dataManipulationMenu->addAction(action_transpose);
298 
299  m_matrixMenu->addMenu(dataManipulationMenu);
300  m_matrixMenu->addSeparator();
301 
302  submenu = new QMenu(i18n("View"), this);
303  submenu->setIcon(QIcon::fromTheme("view-choose"));
304  submenu->addAction(action_data_view);
305  submenu->addAction(action_image_view);
306  m_matrixMenu->addMenu(submenu);
307  m_matrixMenu->addSeparator();
308 
309  m_matrixMenu->addAction(action_select_all);
310  m_matrixMenu->addAction(action_clear_matrix);
311  m_matrixMenu->addSeparator();
312 
313  m_headerFormatMenu = new QMenu(i18n("Header Format"), this);
314  m_headerFormatMenu->setIcon(QIcon::fromTheme("format-border-style"));
318 
320  m_matrixMenu->addSeparator();
321  m_matrixMenu->addAction(action_go_to_cell);
322 }
323 
324 /*!
325  * Populates the menu \c menu with the spreadsheet and spreadsheet view relevant actions.
326  * The menu is used
327  * - as the context menu in MatrixView
328  * - as the "matrix menu" in the main menu-bar (called form MainWin)
329  * - as a part of the matrix context menu in project explorer
330  */
331 void MatrixView::createContextMenu(QMenu* menu) const {
332  Q_ASSERT(menu);
333 
334  QAction* firstAction = nullptr;
335  // if we're populating the context menu for the project explorer, then
336  //there're already actions available there. Skip the first title-action
337  //and insert the action at the beginning of the menu.
338  if (menu->actions().size()>1)
339  firstAction = menu->actions().at(1);
340 
341  menu->insertMenu(firstAction, m_selectionMenu);
342  menu->insertSeparator(firstAction);
343 
344  QMenu* submenu = new QMenu(i18n("Generate Data"), const_cast<MatrixView*>(this));
345  submenu->addAction(action_fill_const);
346  submenu->addAction(action_fill_function);
347  menu->insertMenu(firstAction, submenu);
348  menu->insertSeparator(firstAction);
349 
350  // Data manipulation sub-menu
351  submenu = new QMenu(i18n("Manipulate Data"), const_cast<MatrixView*>(this));
352  submenu->addAction(action_transpose);
353  submenu->addAction(action_mirror_horizontally);
354  submenu->addAction(action_mirror_vertically);
355  submenu->addAction(action_add_value);
356  submenu->addAction(action_subtract_value);
357  submenu->addAction(action_multiply_value);
358  submenu->addAction(action_divide_value);
359 
360  menu->insertMenu(firstAction, submenu);
361  menu->insertSeparator(firstAction);
362 
363  submenu = new QMenu(i18n("View"), const_cast<MatrixView*>(this));
364  submenu->addAction(action_data_view);
365  submenu->addAction(action_image_view);
366  menu->insertMenu(firstAction, submenu);
367  menu->insertSeparator(firstAction);
368 
369  menu->insertAction(firstAction, action_select_all);
370  menu->insertAction(firstAction, action_clear_matrix);
371  menu->insertSeparator(firstAction);
372 // menu->insertAction(firstAction, action_duplicate);
373  menu->insertMenu(firstAction, m_headerFormatMenu);
374 
375  menu->insertSeparator(firstAction);
376  menu->insertAction(firstAction, action_go_to_cell);
377  menu->insertSeparator(firstAction);
378 }
379 
380 /*!
381  set the row and column size to the saved sizes.
382  */
384  QHeaderView* h_header = m_tableView->horizontalHeader();
385  QHeaderView* v_header = m_tableView->verticalHeader();
386 
387  disconnect(v_header, &QHeaderView::sectionResized, this, &MatrixView::handleVerticalSectionResized);
388  disconnect(h_header, &QHeaderView::sectionResized, this, &MatrixView::handleHorizontalSectionResized);
389 
390  //resize columns to the saved sizes or to fit the contents if the widht is 0
391  int cols = m_matrix->columnCount();
392  for (int i = 0; i < cols; i++) {
393  if (m_matrix->columnWidth(i) == 0)
394  m_tableView->resizeColumnToContents(i);
395  else
396  m_tableView->setColumnWidth(i, m_matrix->columnWidth(i));
397  }
398 
399  //resize rows to the saved sizes or to fit the contents if the height is 0
400  int rows = m_matrix->rowCount();
401  for (int i = 0; i < rows; i++) {
402  if (m_matrix->rowHeight(i) == 0)
403  m_tableView->resizeRowToContents(i);
404  else
405  m_tableView->setRowHeight(i, m_matrix->rowHeight(i));
406  }
407 
408  connect(v_header, &QHeaderView::sectionResized, this, &MatrixView::handleVerticalSectionResized);
409  connect(h_header, &QHeaderView::sectionResized, this, &MatrixView::handleHorizontalSectionResized);
410 }
411 
412 /*!
413  Resizes the headers/columns to fit the new content. Called on changes of the header format in Matrix.
414 */
416  m_tableView->resizeColumnsToContents();
417  m_tableView->resizeRowsToContents();
418 
419  if (m_matrix->headerFormat() == Matrix::HeaderFormat::HeaderRowsColumns)
420  action_header_format_1->setChecked(true);
421  else if (m_matrix->headerFormat() == Matrix::HeaderFormat::HeaderValues)
422  action_header_format_2->setChecked(true);
423  else
424  action_header_format_3->setChecked(true);
425 }
426 
427 /*!
428  Returns how many columns are selected.
429  If full is true, this function only returns the number of fully selected columns.
430 */
431 int MatrixView::selectedColumnCount(bool full) const {
432  int count = 0;
433  int cols = m_matrix->columnCount();
434  for (int i = 0; i < cols; i++)
435  if (isColumnSelected(i, full)) count++;
436  return count;
437 }
438 
439 /*!
440  Returns true if column 'col' is selected; otherwise false.
441  If full is true, this function only returns true if the whole column is selected.
442 */
443 bool MatrixView::isColumnSelected(int col, bool full) const {
444  if (full)
445  return m_tableView->selectionModel()->isColumnSelected(col, QModelIndex());
446  else
447  return m_tableView->selectionModel()->columnIntersectsSelection(col, QModelIndex());
448 }
449 
450 /*!
451  Return how many rows are (at least partly) selected
452  If full is true, this function only returns the number of fully selected rows.
453 */
454 int MatrixView::selectedRowCount(bool full) const {
455  int count = 0;
456  int rows = m_matrix->rowCount();
457  for (int i = 0; i < rows; i++)
458  if (isRowSelected(i, full)) count++;
459  return count;
460 }
461 
462 /*!
463  Returns true if row \c row is selected; otherwise false
464  If full is true, this function only returns true if the whole row is selected.
465 */
466 bool MatrixView::isRowSelected(int row, bool full) const {
467  if (full)
468  return m_tableView->selectionModel()->isRowSelected(row, QModelIndex());
469  else
470  return m_tableView->selectionModel()->rowIntersectsSelection(row, QModelIndex());
471 }
472 
473 /*!
474  Return the index of the first selected column.
475  If full is true, this function only looks for fully selected columns.
476 */
477 int MatrixView::firstSelectedColumn(bool full) const {
478  int cols = m_matrix->columnCount();
479  for (int i = 0; i < cols; i++) {
480  if (isColumnSelected(i, full))
481  return i;
482  }
483  return -1;
484 }
485 
486 /*!
487  Return the index of the last selected column
488  If full is true, this function only looks for fully selected columns.
489 */
490 int MatrixView::lastSelectedColumn(bool full) const {
491  int cols = m_matrix->columnCount();
492  for (int i = cols-1; i >= 0; i--)
493  if (isColumnSelected(i, full)) return i;
494 
495  return -2;
496 }
497 
498 /*!
499  Return the index of the first selected row.
500  If full is true, this function only looks for fully selected rows.
501 */
502 int MatrixView::firstSelectedRow(bool full) const {
503  int rows = m_matrix->rowCount();
504  for (int i = 0; i < rows; i++) {
505  if (isRowSelected(i, full))
506  return i;
507  }
508  return -1;
509 }
510 
511 /*!
512  Return the index of the last selected row
513  If full is true, this function only looks for fully selected rows.
514 */
515 int MatrixView::lastSelectedRow(bool full) const {
516  int rows = m_matrix->rowCount();
517  for (int i = rows-1; i >= 0; i--)
518  if (isRowSelected(i, full)) return i;
519 
520  return -2;
521 }
522 
523 bool MatrixView::isCellSelected(int row, int col) const {
524  if (row < 0 || col < 0 || row >= m_matrix->rowCount() || col >= m_matrix->columnCount()) return false;
525 
526  return m_tableView->selectionModel()->isSelected(m_model->index(row, col));
527 }
528 
529 void MatrixView::setCellSelected(int row, int col) {
530  m_tableView->selectionModel()->select(m_model->index(row, col), QItemSelectionModel::Select);
531 }
532 
533 void MatrixView::setCellsSelected(int first_row, int first_col, int last_row, int last_col) {
534  QModelIndex top_left = m_model->index(first_row, first_col);
535  QModelIndex bottom_right = m_model->index(last_row, last_col);
536  m_tableView->selectionModel()->select(QItemSelection(top_left, bottom_right), QItemSelectionModel::SelectCurrent);
537 }
538 
539 /*!
540  Determine the current cell (-1 if no cell is designated as the current)
541 */
542 void MatrixView::getCurrentCell(int* row, int* col) const {
543  QModelIndex index = m_tableView->selectionModel()->currentIndex();
544  if (index.isValid()) {
545  *row = index.row();
546  *col = index.column();
547  } else {
548  *row = -1;
549  *col = -1;
550  }
551 }
552 
553 bool MatrixView::eventFilter(QObject * watched, QEvent * event) {
554  if (event->type() == QEvent::ContextMenu) {
555  auto* cm_event = static_cast<QContextMenuEvent*>(event);
556  QPoint global_pos = cm_event->globalPos();
557  if (watched == m_tableView->verticalHeader())
558  m_rowMenu->exec(global_pos);
559  else if (watched == m_tableView->horizontalHeader())
560  m_columnMenu->exec(global_pos);
561  else if (watched == this)
562  m_matrixMenu->exec(global_pos);
563  else
564  return QWidget::eventFilter(watched, event);
565  return true;
566  } else
567  return QWidget::eventFilter(watched, event);
568 }
569 
570 void MatrixView::keyPressEvent(QKeyEvent* event) {
571  if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
572  advanceCell();
573  else if (event->key() == Qt::Key_Backspace || event->matches(QKeySequence::Delete))
575 }
576 
577 //##############################################################################
578 //#################################### SLOTs ################################
579 //##############################################################################
580 /*!
581  Advance current cell after [Return] or [Enter] was pressed
582 */
584  QModelIndex idx = m_tableView->currentIndex();
585  if (idx.row()+1 < m_matrix->rowCount())
586  m_tableView->setCurrentIndex(idx.sibling(idx.row()+1, idx.column()));
587 }
588 
590  bool ok;
591 
592  int col = QInputDialog::getInt(nullptr, i18n("Go to Cell"), i18n("Enter column"), 1, 1, m_matrix->columnCount(), 1, &ok);
593  if (!ok) return;
594 
595  int row = QInputDialog::getInt(nullptr, i18n("Go to Cell"), i18n("Enter row"), 1, 1, m_matrix->rowCount(), 1, &ok);
596  if (!ok) return;
597 
598  goToCell(row-1, col-1);
599 }
600 
601 void MatrixView::goToCell(int row, int col) {
602  QModelIndex index = m_model->index(row, col);
603  m_tableView->scrollTo(index);
604  m_tableView->setCurrentIndex(index);
605 }
606 
607 void MatrixView::handleHorizontalSectionResized(int logicalIndex, int oldSize, int newSize) {
608  Q_UNUSED(oldSize)
609  m_matrix->setColumnWidth(logicalIndex, newSize);
610 }
611 
612 void MatrixView::handleVerticalSectionResized(int logicalIndex, int oldSize, int newSize) {
613  Q_UNUSED(oldSize)
614  m_matrix->setRowHeight(logicalIndex, newSize);
615 }
616 
618  auto* dlg = new MatrixFunctionDialog(m_matrix);
619  dlg->exec();
620 }
621 
623  bool ok = false;
624  double value = QInputDialog::getDouble(this, i18n("Fill the matrix with constant value"),
625  i18n("Value"), 0, -2147483647, 2147483647, 6, &ok);
626  if (ok) {
627  WAIT_CURSOR;
628  auto* newData = static_cast<QVector<QVector<double>>*>(m_matrix->data());
629  for (int col = 0; col < m_matrix->columnCount(); ++col) {
630  for (int row = 0; row < m_matrix->rowCount(); ++row)
631  (newData->operator[](col))[row] = value;
632  }
633  m_matrix->setData(newData);
634  RESET_CURSOR;
635  }
636 }
637 
638 //############################ selection related slots #########################
640  if (firstSelectedRow() < 0) return;
641 
642  WAIT_CURSOR;
643  m_matrix->beginMacro(i18n("%1: cut selected cell(s)", m_matrix->name()));
644  copySelection();
646  m_matrix->endMacro();
647  RESET_CURSOR;
648 }
649 
651  int first_col = firstSelectedColumn(false);
652  if (first_col == -1) return;
653  int last_col = lastSelectedColumn(false);
654  if (last_col == -2) return;
655  int first_row = firstSelectedRow(false);
656  if (first_row == -1) return;
657  int last_row = lastSelectedRow(false);
658  if (last_row == -2) return;
659  int cols = last_col - first_col +1;
660  int rows = last_row - first_row +1;
661 
662  WAIT_CURSOR;
663  QString output_str;
664 
666  for (int r = 0; r < rows; r++) {
667  for (int c = 0; c < cols; c++) {
668  //TODO: mode
669  if (isCellSelected(first_row + r, first_col + c))
670  output_str += numberLocale.toString(m_matrix->cell<double>(first_row + r, first_col + c),
671  m_matrix->numericFormat(), 16); // copy with max. precision
672  if (c < cols-1)
673  output_str += '\t';
674  }
675  if (r < rows-1)
676  output_str += '\n';
677  }
678  QApplication::clipboard()->setText(output_str);
679  RESET_CURSOR;
680 }
681 
683  if (m_matrix->columnCount() < 1 || m_matrix->rowCount() < 1) return;
684 
685  const QMimeData* mime_data = QApplication::clipboard()->mimeData();
686  if (!mime_data->hasFormat("text/plain"))
687  return;
688 
689  WAIT_CURSOR;
690  m_matrix->beginMacro(i18n("%1: paste from clipboard", m_matrix->name()));
691 
692  int first_col = firstSelectedColumn(false);
693  int last_col = lastSelectedColumn(false);
694  int first_row = firstSelectedRow(false);
695  int last_row = lastSelectedRow(false);
696  int input_row_count = 0;
697  int input_col_count = 0;
698  int rows, cols;
699 
700  QString input_str = QString(mime_data->data("text/plain"));
701  QList< QStringList > cell_texts;
702  QStringList input_rows(input_str.split('\n'));
703  input_row_count = input_rows.count();
704  input_col_count = 0;
705  for (int i = 0; i < input_row_count; i++) {
706  cell_texts.append(input_rows.at(i).split('\t'));
707  if (cell_texts.at(i).count() > input_col_count) input_col_count = cell_texts.at(i).count();
708  }
709 
710  // if the is no selection or only one cell selected, the
711  // selection will be expanded to the needed size from the current cell
712  if ( (first_col == -1 || first_row == -1) ||
713  (last_row == first_row && last_col == first_col) ) {
714  int current_row, current_col;
715  getCurrentCell(&current_row, &current_col);
716  if (current_row == -1) current_row = 0;
717  if (current_col == -1) current_col = 0;
718  setCellSelected(current_row, current_col);
719  first_col = current_col;
720  first_row = current_row;
721  last_row = first_row + input_row_count -1;
722  last_col = first_col + input_col_count -1;
723  // resize the matrix if necessary
724  if (last_col >= m_matrix->columnCount())
725  m_matrix->appendColumns(last_col+1-m_matrix->columnCount());
726  if (last_row >= m_matrix->rowCount())
727  m_matrix->appendRows(last_row+1-m_matrix->rowCount());
728  // select the rectangle to be pasted in
729  setCellsSelected(first_row, first_col, last_row, last_col);
730  }
731 
732  rows = last_row - first_row + 1;
733  cols = last_col - first_col + 1;
734  for (int r = 0; r < rows && r < input_row_count; r++) {
735  for (int c = 0; c < cols && c < input_col_count; c++) {
736  if (isCellSelected(first_row + r, first_col + c) && (c < cell_texts.at(r).count()) )
737  m_matrix->setCell(first_row + r, first_col + c, cell_texts.at(r).at(c).toDouble());
738  }
739  }
740 
741  m_matrix->endMacro();
742  RESET_CURSOR;
743 }
744 
746  int first_row = firstSelectedRow();
747  if (first_row<0)
748  return;
749 
750  int first_col = firstSelectedColumn();
751  if (first_col<0)
752  return;
753 
754  int last_row = lastSelectedRow();
755  int last_col = lastSelectedColumn();
756 
757  WAIT_CURSOR;
758  m_matrix->beginMacro(i18n("%1: clear selected cell(s)", m_matrix->name()));
759  for (int i = first_row; i <= last_row; i++) {
760  for (int j = first_col; j <= last_col; j++) {
761  if (isCellSelected(i, j))
762  m_matrix->clearCell(i, j);
763  }
764  }
765  m_matrix->endMacro();
766  RESET_CURSOR;
767 }
768 
769 class UpdateImageTask : public QRunnable {
770 public:
771  UpdateImageTask(int start, int end, QImage& image, const void* data, double scaleFactor, double min) : m_image(image), m_data(data) {
772  m_start = start;
773  m_end = end;
774  m_scaleFactor = scaleFactor;
775  m_min = min;
776  };
777 
778  void run() override {
779  for (int row = m_start; row < m_end; ++row) {
780  m_mutex.lock();
781  QRgb* line = reinterpret_cast<QRgb*>(m_image.scanLine(row));
782  m_mutex.unlock();
783  for (int col = 0; col < m_image.width(); ++col) {
784  const int gray = (static_cast<const QVector<QVector<double>>*>(m_data)->at(col).at(row)-m_min)*m_scaleFactor;
785  line[col] = qRgb(gray, gray, gray);
786  }
787  }
788  }
789 
790 private:
791  QMutex m_mutex;
792  int m_start;
793  int m_end;
794  QImage& m_image;
795  const void* m_data;
797  double m_min;
798 };
799 
801  WAIT_CURSOR;
802  m_image = QImage(m_matrix->columnCount(), m_matrix->rowCount(), QImage::Format_ARGB32);
803 
804  //find min/max value
805  double dmax = -DBL_MAX, dmin = DBL_MAX;
807  const int width = m_matrix->columnCount();
808  const int height = m_matrix->rowCount();
809  for (int col = 0; col < width; ++col) {
810  for (int row = 0; row < height; ++row) {
811  const double value = (data->operator[](col))[row];
812  if (dmax < value) dmax = value;
813  if (dmin > value) dmin = value;
814  }
815  }
816 
817  //update the image
818  const double scaleFactor = 255.0/(dmax-dmin);
819  QThreadPool* pool = QThreadPool::globalInstance();
820  int range = ceil(double(m_image.height())/pool->maxThreadCount());
821  for (int i = 0; i < pool->maxThreadCount(); ++i) {
822  const int start = i*range;
823  int end = (i+1)*range;
824  if (end > m_image.height()) end = m_image.height();
825  auto* task = new UpdateImageTask(start, end, m_image, data, scaleFactor, dmin);
826  pool->start(task);
827  }
828  pool->waitForDone();
829 
830  m_imageLabel->resize(width, height);
831  m_imageLabel->setPixmap(QPixmap::fromImage(m_image));
832  m_imageIsDirty = false;
833  RESET_CURSOR;
834 }
835 
836 //############################# matrix related slots ###########################
838  if (action == action_data_view)
839  m_stackedWidget->setCurrentIndex(0);
840  else {
841  if (m_imageIsDirty)
842  this->updateImage();
843 
844  m_stackedWidget->setCurrentIndex(1);
845  }
846 }
847 
849  m_imageIsDirty = true;
850  if (m_stackedWidget->currentIndex() == 1)
851  this->updateImage();
852 }
853 
857  else if (action == action_header_format_2)
859  else
861 }
862 
863 //############################# column related slots ###########################
864 /*!
865  Append as many columns as are selected.
866 */
869 }
870 
872  int first = firstSelectedColumn();
873  int last = lastSelectedColumn();
874  if (first < 0) return;
875  int current = first;
876 
877  WAIT_CURSOR;
878  m_matrix->beginMacro(i18n("%1: insert empty column(s)", m_matrix->name()));
879  while (current <= last) {
880  current = first+1;
881  while (current <= last && isColumnSelected(current)) current++;
882  const int count = current-first;
883  m_matrix->insertColumns(first, count);
884  current += count;
885  last += count;
886  while (current <= last && isColumnSelected(current)) current++;
887  first = current;
888  }
889  m_matrix->endMacro();
890  RESET_CURSOR;
891 }
892 
894  int first = firstSelectedColumn();
895  int last = lastSelectedColumn();
896  if (first < 0) return;
897 
898  WAIT_CURSOR;
899  m_matrix->beginMacro(i18n("%1: remove selected column(s)", m_matrix->name()));
900  for (int i = last; i >= first; i--)
901  if (isColumnSelected(i, false)) m_matrix->removeColumns(i, 1);
902  m_matrix->endMacro();
903  RESET_CURSOR;
904 }
905 
907  WAIT_CURSOR;
908  m_matrix->beginMacro(i18n("%1: clear selected column(s)", m_matrix->name()));
909  for (int i = 0; i < m_matrix->columnCount(); i++) {
910  if (isColumnSelected(i, false))
911  m_matrix->clearColumn(i);
912  }
913  m_matrix->endMacro();
914  RESET_CURSOR;
915 }
916 
917 //############################## rows related slots ############################
918 /*!
919  Append as many rows as are selected.
920 */
923 }
924 
926  int first = firstSelectedRow();
927  int last = lastSelectedRow();
928  int current = first;
929 
930  if (first < 0) return;
931 
932  WAIT_CURSOR;
933  m_matrix->beginMacro(i18n("%1: insert empty rows(s)", m_matrix->name()));
934  while (current <= last) {
935  current = first+1;
936  while (current <= last && isRowSelected(current)) current++;
937  const int count = current-first;
938  m_matrix->insertRows(first, count);
939  current += count;
940  last += count;
941  while (current <= last && !isRowSelected(current)) current++;
942  first = current;
943  }
944  m_matrix->endMacro();
945  RESET_CURSOR;
946 }
947 
949  int first = firstSelectedRow();
950  int last = lastSelectedRow();
951  if (first < 0) return;
952 
953  WAIT_CURSOR;
954  m_matrix->beginMacro(i18n("%1: remove selected rows(s)", m_matrix->name()));
955  for (int i = last; i >= first; i--)
956  if (isRowSelected(i, false)) m_matrix->removeRows(i, 1);
957  m_matrix->endMacro();
958  RESET_CURSOR;
959 }
960 
962  int first = firstSelectedRow();
963  int last = lastSelectedRow();
964  if (first < 0) return;
965 
966  WAIT_CURSOR;
967  m_matrix->beginMacro(i18n("%1: clear selected rows(s)", m_matrix->name()));
968  for (int i = first; i <= last; i++) {
969  if (isRowSelected(i))
970  m_matrix->clearRow(i);
971  }
972  m_matrix->endMacro();
973  RESET_CURSOR;
974 }
975 
976 /*!
977  prints the complete matrix to \c printer.
978  */
979 
980 void MatrixView::print(QPrinter* printer) const {
981  WAIT_CURSOR;
982  QPainter painter (printer);
983 
984  const int dpiy = printer->logicalDpiY();
985  const int margin = (int) ( (1/2.54)*dpiy ); // 1 cm margins
986 
987  QHeaderView* hHeader = m_tableView->horizontalHeader();
988  QHeaderView* vHeader = m_tableView->verticalHeader();
989  auto* data = static_cast<QVector<QVector<double>>*>(m_matrix->data());
990 
991  const int rows = m_matrix->rowCount();
992  const int cols = m_matrix->columnCount();
993  int height = margin;
994  const int vertHeaderWidth = vHeader->width();
995  int right = margin + vertHeaderWidth;
996 
997  int columnsPerTable = 0;
998  int headerStringWidth = 0;
999  int firstRowStringWidth = vertHeaderWidth;
1000  bool tablesNeeded = false;
1001  QVector<int> firstRowCeilSizes;
1002  firstRowCeilSizes.reserve(data[0].size());
1003  firstRowCeilSizes.resize(data[0].size());
1004  QRect br;
1005 
1006  for (int i = 0; i < data->size(); ++i) {
1007  br = painter.boundingRect(br, Qt::AlignCenter,QString::number(data->at(i)[0]) + '\t');
1008  firstRowCeilSizes[i] = br.width() > m_tableView->columnWidth(i) ?
1009  br.width() : m_tableView->columnWidth(i);
1010  }
1011  for (int col = 0; col < cols; ++col) {
1012  headerStringWidth += m_tableView->columnWidth(col);
1013  br = painter.boundingRect(br, Qt::AlignCenter,QString::number(data->at(col)[0]) + '\t');
1014  firstRowStringWidth += br.width();
1015  if ((headerStringWidth >= printer->pageRect().width() -2*margin) ||
1016  (firstRowStringWidth >= printer->pageRect().width() - 2*margin)) {
1017  tablesNeeded = true;
1018  break;
1019  }
1020  columnsPerTable++;
1021  }
1022 
1023  int tablesCount = (columnsPerTable != 0) ? cols/columnsPerTable : 0;
1024  const int remainingColumns = (columnsPerTable != 0) ? cols % columnsPerTable : cols;
1025 
1026  if (!tablesNeeded) {
1027  tablesCount = 1;
1028  columnsPerTable = cols;
1029  }
1030  if (remainingColumns > 0)
1031  tablesCount++;
1032  for (int table = 0; table < tablesCount; ++table) {
1033  //Paint the horizontal header first
1034  painter.setFont(hHeader->font());
1035  QString headerString = m_tableView->model()->headerData(0, Qt::Horizontal).toString();
1036  QRect br;
1037  br = painter.boundingRect(br, Qt::AlignCenter, headerString);
1038  QRect tr(br);
1039  if (table != 0)
1040  height += tr.height();
1041  painter.drawLine(right, height, right, height+br.height());
1042 
1043  int i = table * columnsPerTable;
1044  int toI = table * columnsPerTable + columnsPerTable;
1045  if ((remainingColumns > 0) && (table == tablesCount-1)) {
1046  i = (tablesCount-1)*columnsPerTable;
1047  toI = (tablesCount-1)* columnsPerTable + remainingColumns;
1048  }
1049 
1050  for (; i<toI; ++i) {
1051  headerString = m_tableView->model()->headerData(i, Qt::Horizontal).toString();
1052  const int w = /*m_tableView->columnWidth(i)*/ firstRowCeilSizes[i];
1053  tr.setTopLeft(QPoint(right,height));
1054  tr.setWidth(w);
1055  tr.setHeight(br.height());
1056 
1057  painter.drawText(tr, Qt::AlignCenter, headerString);
1058  right += w;
1059  painter.drawLine(right, height, right, height+tr.height());
1060 
1061  }
1062  //first horizontal line
1063  painter.drawLine(margin + vertHeaderWidth, height, right-1, height);
1064  height += tr.height();
1065  painter.drawLine(margin, height, right-1, height);
1066 
1067  // print table values
1068  QString cellText;
1069  for (i = 0; i < rows; ++i) {
1070  right = margin;
1071  cellText = m_tableView->model()->headerData(i, Qt::Vertical).toString()+'\t';
1072  tr = painter.boundingRect(tr, Qt::AlignCenter, cellText);
1073  painter.drawLine(right, height, right, height+tr.height());
1074 
1075  br.setTopLeft(QPoint(right,height));
1076  br.setWidth(vertHeaderWidth);
1077  br.setHeight(tr.height());
1078  painter.drawText(br, Qt::AlignCenter, cellText);
1079  right += vertHeaderWidth;
1080  painter.drawLine(right, height, right, height+tr.height());
1081  int j = table * columnsPerTable;
1082  int toJ = table * columnsPerTable + columnsPerTable;
1083  if ((remainingColumns > 0) && (table == tablesCount-1)) {
1084  j = (tablesCount-1)*columnsPerTable;
1085  toJ = (tablesCount-1)* columnsPerTable + remainingColumns;
1086  }
1087  for (; j< toJ; j++) {
1088  int w = /*m_tableView->columnWidth(j)*/ firstRowCeilSizes[j];
1089  cellText = QString::number(data->at(j)[i]) + '\t';
1090  tr = painter.boundingRect(tr,Qt::AlignCenter,cellText);
1091  br.setTopLeft(QPoint(right,height));
1092  br.setWidth(w);
1093  br.setHeight(tr.height());
1094  painter.drawText(br, Qt::AlignCenter, cellText);
1095  right += w;
1096  painter.drawLine(right, height, right, height+tr.height());
1097  }
1098  height += br.height();
1099  painter.drawLine(margin, height, right-1, height);
1100 
1101  if (height >= printer->height()-margin ) {
1102  printer->newPage();
1103  height = margin;
1104  painter.drawLine(margin, height, right, height);
1105  }
1106  }
1107  }
1108  RESET_CURSOR;
1109 }
1110 
1111 void MatrixView::exportToFile(const QString& path, const QString& separator, QLocale::Language language) const {
1112  QFile file(path);
1113  if (!file.open(QFile::WriteOnly | QFile::Truncate))
1114  return;
1115 
1116  QTextStream out(&file);
1117 
1118  QString sep = separator;
1119  sep = sep.replace(QLatin1String("TAB"), QLatin1String("\t"), Qt::CaseInsensitive);
1120  sep = sep.replace(QLatin1String("SPACE"), QLatin1String(" "), Qt::CaseInsensitive);
1121 
1122  //export values
1123  const int cols = m_matrix->columnCount();
1124  const int rows = m_matrix->rowCount();
1125  const QVector<QVector<double> >* data = static_cast<QVector<QVector<double>>*>(m_matrix->data());
1126  //TODO: use general setting for number locale?
1127  QLocale locale(language);
1128  for (int row = 0; row < rows; ++row) {
1129  for (int col = 0; col < cols; ++col) {
1130  out << locale.toString(data->at(col)[row], m_matrix->numericFormat(), m_matrix->precision());
1131 
1132  out << data->at(col)[row];
1133  if (col != cols-1)
1134  out << sep;
1135  }
1136  out << '\n';
1137  }
1138 }
1139 
1140 void MatrixView::exportToLaTeX(const QString& path, const bool verticalHeaders, const bool horizontalHeaders,
1141  const bool latexHeaders, const bool gridLines, const bool entire, const bool captions) const {
1142  QFile file(path);
1143  if (!file.open(QFile::WriteOnly | QFile::Truncate))
1144  return;
1145 
1146  QVector<QVector<QString> > toExport;
1147 
1148  int firstSelectedCol = 0;
1149  int firstSelectedRowi = 0;
1150  int totalRowCount = 0;
1151  int cols = 0;
1152  if (entire) {
1153  cols = m_matrix->columnCount();
1154  totalRowCount = m_matrix->rowCount();
1155  toExport.reserve(totalRowCount);
1156  toExport.resize(totalRowCount);
1157  for (int row = 0; row < totalRowCount; ++row) {
1158  toExport[row].reserve(cols);
1159  toExport[row].resize(cols);
1160  //TODO: mode
1161  for (int col = 0; col < cols; ++col)
1162  toExport[row][col] = m_matrix->text<double>(row,col);
1163  }
1164  firstSelectedCol = 0;
1165  firstSelectedRowi = 0;
1166  } else {
1167  cols = selectedColumnCount();
1168  totalRowCount = selectedRowCount();
1169 
1170  firstSelectedCol = firstSelectedColumn();
1171  if (firstSelectedCol == -1)
1172  return;
1173  firstSelectedRowi = firstSelectedRow();
1174  if (firstSelectedRowi == -1)
1175  return;
1176  const int lastSelectedCol = lastSelectedColumn();
1177  const int lastSelectedRowi = lastSelectedRow();
1178 
1179  toExport.reserve(lastSelectedRowi - firstSelectedRowi+1);
1180  toExport.resize(lastSelectedRowi - firstSelectedRowi+1);
1181  int r = 0;
1182  for (int row = firstSelectedRowi; row <= lastSelectedRowi; ++row, ++r) {
1183  toExport[r].reserve(lastSelectedCol - firstSelectedCol+1);
1184  toExport[r].resize(lastSelectedCol - firstSelectedCol+1);
1185  int c = 0;
1186  //TODO: mode
1187  for (int col = firstSelectedCol; col <= lastSelectedCol; ++col,++c)
1188  toExport[r][c] = m_matrix->text<double>(row, col);
1189  }
1190  }
1191 
1192  int columnsStringSize = 0;
1193  int headerStringSize = 0;
1194  int columnsPerTable = 0;
1195  const int firstHHeaderSectionLength = m_tableView->model()->headerData(0, Qt::Horizontal).toString().length();
1196  const int firstSelectedVHeaderSectionLength = m_tableView->model()->headerData(firstSelectedRow(), Qt::Vertical).toString().length();
1197  if (verticalHeaders) {
1198  if (entire)
1199  headerStringSize += firstHHeaderSectionLength;
1200  else
1201  headerStringSize += firstSelectedVHeaderSectionLength;
1202  }
1203  if (!horizontalHeaders && verticalHeaders) {
1204  if (entire)
1205  columnsStringSize += firstHHeaderSectionLength;
1206  else
1207  columnsStringSize += firstSelectedVHeaderSectionLength;
1208  }
1209 
1210  for (int col = 0; col < cols; ++col) {
1211  int maxSize = -1;
1212  for (auto row : toExport) {
1213  if (row.at(col).size() > maxSize)
1214  maxSize = row.at(col).size();
1215  }
1216  columnsStringSize += maxSize;
1217  if (horizontalHeaders)
1218  headerStringSize += m_tableView->model()->headerData(col, Qt::Horizontal).toString().length();
1219  if ((columnsStringSize > 65) || (headerStringSize > 65))
1220  break;
1221  ++columnsPerTable;
1222  }
1223 
1224  int tablesCount = (columnsPerTable != 0) ? cols/columnsPerTable : 0;
1225  const int remainingColumns = (columnsPerTable != 0) ? cols % columnsPerTable : cols;
1226 
1227  bool columnsSeparating = (cols > columnsPerTable);
1228  QTextStream out(&file);
1229 
1230  QProcess tex;
1231  tex.start("latex", QStringList() << "--version", QProcess::ReadOnly);
1232  tex.waitForFinished(500);
1233  QString texVersionOutput = QString(tex.readAllStandardOutput());
1234  texVersionOutput = texVersionOutput.split('\n')[0];
1235 
1236  int yearidx = -1;
1237  for (int i = texVersionOutput.size() - 1; i >= 0; --i) {
1238  if (texVersionOutput.at(i) == QChar('2')) {
1239  yearidx = i;
1240  break;
1241  }
1242  }
1243 
1244  if (texVersionOutput.at(yearidx+1) == QChar('/'))
1245  yearidx-=3;
1246 
1247  bool ok;
1248  texVersionOutput.midRef(yearidx, 4).toInt(&ok);
1249  int version = -1;
1250  if (ok)
1251  version = texVersionOutput.midRef(yearidx, 4).toInt(&ok);
1252 
1253  if (latexHeaders) {
1254  out << QLatin1String("\\documentclass[11pt,a4paper]{article} \n");
1255  out << QLatin1String("\\usepackage{geometry} \n");
1256  out << QLatin1String("\\usepackage{xcolor,colortbl} \n");
1257  if (version >= 2015)
1258  out << QLatin1String("\\extrafloats{1280} \n");
1259  out << QLatin1String("\\definecolor{HeaderBgColor}{rgb}{0.81,0.81,0.81} \n");
1260  out << QLatin1String("\\geometry{ \n");
1261  out << QLatin1String("a4paper, \n");
1262  out << QLatin1String("total={170mm,257mm}, \n");
1263  out << QLatin1String("left=10mm, \n");
1264  out << QLatin1String("top=10mm } \n");
1265 
1266  out << QLatin1String("\\begin{document} \n");
1267  out << QLatin1String("\\title{LabPlot Matrix Export to \\LaTeX{} } \n");
1268  out << QLatin1String("\\author{LabPlot} \n");
1269  out << QLatin1String("\\date{\\today} \n");
1270  // out << "\\maketitle \n";
1271  }
1272 
1273  const QString endTabularTable ("\\end{tabular} \n \\end{table} \n");
1274  const QString tableCaption ("\\caption{"+ m_matrix->name() + "} \n");
1275  const QString beginTable ("\\begin{table}[ht] \n");
1276  const QString centeredColumn( gridLines ? QLatin1String(" c |") : QLatin1String(" c "));
1277  int rowCount = 0;
1278  const int maxRows = 45;
1279  bool captionRemoved = false;
1280 
1281  if (columnsSeparating) {
1282  for (int table = 0; table < tablesCount; ++table) {
1283  QStringList textable;
1284  captionRemoved = false;
1285 
1286  textable << beginTable;
1287  if (captions)
1288  textable << tableCaption;
1289  textable << QLatin1String("\\centering \n");
1290  textable << QLatin1String("\\begin{tabular}{");
1291  textable << (gridLines ? QStringLiteral("|") : QString());
1292  for (int i = 0; i < columnsPerTable; ++i)
1293  textable << centeredColumn;
1294  if (verticalHeaders)
1295  textable << centeredColumn;
1296  textable << QLatin1String("} \n");
1297  if (gridLines)
1298  textable << QLatin1String("\\hline \n");
1299 
1300  if (horizontalHeaders) {
1301  if (latexHeaders)
1302  textable << QLatin1String("\\rowcolor{HeaderBgColor} \n");
1303  if (verticalHeaders)
1304  textable << QLatin1String(" & ");
1305  for (int col = table*columnsPerTable; col < (table * columnsPerTable) + columnsPerTable; ++col) {
1306  textable << m_tableView->model()->headerData(col + firstSelectedCol, Qt::Horizontal).toString();
1307  if (col != ((table * columnsPerTable)+ columnsPerTable)-1)
1308  textable << QLatin1String(" & ");
1309  }
1310  textable << QLatin1String("\\\\ \n");
1311  if (gridLines)
1312  textable << QLatin1String("\\hline \n");
1313  }
1314  for (const auto& s : textable)
1315  out << s;
1316  for (int row = 0; row < totalRowCount; ++row) {
1317  if (verticalHeaders) {
1318  out << "\\cellcolor{HeaderBgColor} ";
1319  out << m_tableView->model()->headerData(row + firstSelectedRowi, Qt::Vertical).toString();
1320  out << QLatin1String(" & ");
1321  }
1322  for (int col = table*columnsPerTable; col < (table * columnsPerTable) + columnsPerTable; ++col ) {
1323  out << toExport.at(row).at(col);
1324  if (col != ((table * columnsPerTable)+ columnsPerTable)-1)
1325  out << QLatin1String(" & ");
1326  }
1327 
1328  out << QLatin1String("\\\\ \n");
1329  if (gridLines)
1330  out << QLatin1String("\\hline \n");
1331  rowCount++;
1332  if (rowCount == maxRows) {
1333  out << endTabularTable;
1334  out << QLatin1String("\\newpage \n");
1335  if (captions)
1336  if (!captionRemoved)
1337  textable.removeAt(1);
1338  for (const auto& s : textable)
1339  out << s;
1340  rowCount = 0;
1341  if (!captionRemoved)
1342  captionRemoved = true;
1343  }
1344  }
1345  out << endTabularTable;
1346  }
1347  captionRemoved = false;
1348 
1349  QStringList remainingTable;
1350  remainingTable << beginTable;
1351  if (captions)
1352  remainingTable << tableCaption;
1353  remainingTable << QLatin1String("\\centering \n");
1354  remainingTable << QLatin1String("\\begin{tabular}{") << (gridLines ? QStringLiteral("|") : QString());
1355  for (int c = 0; c < remainingColumns; ++c)
1356  remainingTable << centeredColumn;
1357  if (verticalHeaders)
1358  remainingTable << centeredColumn;
1359  remainingTable << QLatin1String("} \n");
1360  if (gridLines)
1361  remainingTable << QLatin1String("\\hline \n");
1362 
1363  if (horizontalHeaders) {
1364  if (latexHeaders)
1365  remainingTable << QLatin1String("\\rowcolor{HeaderBgColor} \n");
1366  if (verticalHeaders)
1367  remainingTable << QLatin1String(" & ");
1368  for (int col = 0; col < remainingColumns; ++col) {
1369  remainingTable << m_tableView->model()->headerData(firstSelectedCol+col + (tablesCount * columnsPerTable), Qt::Horizontal).toString();
1370  if (col != remainingColumns-1)
1371  remainingTable << QLatin1String(" & ");
1372  }
1373  remainingTable << QLatin1String("\\\\ \n");
1374  if (gridLines)
1375  remainingTable << QLatin1String("\\hline \n");
1376  }
1377 
1378  for (const auto& s : remainingTable)
1379  out << s;
1380 
1381  for (int row = 0; row < totalRowCount; ++row) {
1382  if (verticalHeaders) {
1383  out << "\\cellcolor{HeaderBgColor}";
1384  out << m_tableView->model()->headerData(row+ firstSelectedRowi, Qt::Vertical).toString();
1385  out << QLatin1String(" & ");
1386  }
1387  for (int col = 0; col < remainingColumns; ++col ) {
1388  out << toExport.at(row).at(col + (tablesCount * columnsPerTable));
1389  if (col != remainingColumns-1)
1390  out << QLatin1String(" & ");
1391  }
1392 
1393  out << QLatin1String("\\\\ \n");
1394  if (gridLines)
1395  out << QLatin1String("\\hline \n");
1396  rowCount++;
1397  if (rowCount == maxRows) {
1398  out << endTabularTable;
1399  out << QLatin1String("\\pagebreak[4] \n");
1400  if (captions)
1401  if (!captionRemoved)
1402  remainingTable.removeAt(1);
1403  for (const auto& s : remainingTable)
1404  out << s;
1405  rowCount = 0;
1406  if (!captionRemoved)
1407  captionRemoved = true;
1408  }
1409  }
1410  out << endTabularTable;
1411  } else {
1412  QStringList textable;
1413  textable << beginTable;
1414  if (captions)
1415  textable << tableCaption;
1416  textable << QLatin1String("\\centering \n");
1417  textable << QLatin1String("\\begin{tabular}{") << (gridLines ? QStringLiteral("|") : QString());
1418  for (int c = 0; c < cols; ++c)
1419  textable << centeredColumn;
1420  if (verticalHeaders)
1421  textable << centeredColumn;
1422  textable << QLatin1String("} \n");
1423  if (gridLines)
1424  textable << QLatin1String("\\hline \n");
1425 
1426  if (horizontalHeaders) {
1427  if (latexHeaders)
1428  textable << QLatin1String("\\rowcolor{HeaderBgColor} \n");
1429  if (verticalHeaders)
1430  textable << QLatin1String(" & ");
1431  for (int col = 0; col < cols ; ++col) {
1432  textable << m_tableView->model()->headerData(col+firstSelectedCol, Qt::Horizontal).toString();
1433  if (col != cols-1)
1434  textable << QLatin1String(" & ");
1435  }
1436  textable << QLatin1String("\\\\ \n");
1437  if (gridLines)
1438  textable << QLatin1String("\\hline \n");
1439  }
1440 
1441  for (const auto& s : textable)
1442  out << s;
1443  for (int row = 0; row < totalRowCount; ++row) {
1444  if (verticalHeaders) {
1445  out << "\\cellcolor{HeaderBgColor}";
1446  out << m_tableView->model()->headerData(row + firstSelectedRowi, Qt::Vertical).toString();
1447  out << QLatin1String(" & ");
1448  }
1449  for (int col = 0; col < cols; ++col ) {
1450  out << toExport.at(row).at(col);
1451  if (col != cols-1)
1452  out << " & ";
1453  }
1454  out << QLatin1String("\\\\ \n");
1455  if (gridLines)
1456  out << QLatin1String("\\hline \n");
1457  rowCount++;
1458  if (rowCount == maxRows) {
1459  out << endTabularTable;
1460  out << QLatin1String("\\newpage \n");
1461  if (captions)
1462  if (!captionRemoved)
1463  textable.removeAt(1);
1464  for (const auto& s : textable)
1465  out << s;
1466  if (!captionRemoved)
1467  captionRemoved = true;
1468  rowCount = 0;
1469  if (!captionRemoved)
1470  captionRemoved = true;
1471  }
1472  }
1473  out << endTabularTable;
1474  }
1475  if (latexHeaders)
1476  out << QLatin1String("\\end{document} \n");
1477 }
1478 
1480  if (selectedColumnCount() > 0) {
1481  QString dlgTitle (m_matrix->name() + " column statistics");
1482  QVector<Column*> columns;
1483  for (int col = 0; col < m_matrix->columnCount(); ++col) {
1484  if (isColumnSelected(col, false)) {
1485  QString headerString = m_tableView->model()->headerData(col, Qt::Horizontal).toString();
1486  columns << new Column(headerString, static_cast<QVector<QVector<double>>*>(m_matrix->data())->at(col));
1487  }
1488  }
1489  auto* dlg = new StatisticsDialog(dlgTitle, columns);
1490  dlg->showStatistics();
1491  if (dlg->exec() == QDialog::Accepted) {
1492  qDeleteAll(columns);
1493  columns.clear();
1494  }
1495  }
1496 }
1497 
1499  if (selectedRowCount() > 0) {
1500  QString dlgTitle (m_matrix->name() + " row statistics");
1501  QVector<Column*> columns;
1502  for (int row = 0; row < m_matrix->rowCount(); ++row) {
1503  if (isRowSelected(row, false)) {
1504  QString headerString = m_tableView->model()->headerData(row, Qt::Vertical).toString();
1505  //TODO: mode
1506  columns << new Column(headerString, m_matrix->rowCells<double>(row, 0, m_matrix->columnCount()-1));
1507  }
1508  }
1509  auto* dlg = new StatisticsDialog(dlgTitle, columns);
1510  dlg->showStatistics();
1511  if (dlg->exec() == QDialog::Accepted) {
1512  qDeleteAll(columns);
1513  columns.clear();
1514  }
1515  }
1516 }
1517 
1518 void MatrixView::exportToFits(const QString &fileName, const int exportTo) const {
1519  auto* filter = new FITSFilter;
1520  filter->setExportTo(exportTo);
1521  filter->write(fileName, m_matrix);
1522 
1523  delete filter;
1524 }
QString name() const
void beginMacro(const QString &text)
Begin an undo stack macro (series of commands)
bool isLoading() const
void endMacro()
End the current undo stack macro.
Dialog for adding/subtracting a value from column values.
Manages the import/export of data from/to a FITS file.
Definition: FITSFilter.h:41
void setExportTo(const int)
Sets exportTo to exportTo.
Definition: FITSFilter.cpp:245
Dialog for generating matrix values from a mathematical function.
Model for the access to data of a Matrix-object.
Definition: MatrixModel.h:37
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void changed()
void removeSelectedRows()
Definition: MatrixView.cpp:948
void getCurrentCell(int *row, int *col) const
Definition: MatrixView.cpp:542
bool isCellSelected(int row, int col) const
Definition: MatrixView.cpp:523
QAction * action_clear_matrix
Definition: MatrixView.h:109
QAction * action_divide_value
Definition: MatrixView.h:121
QAction * action_transpose
Definition: MatrixView.h:114
QAction * action_statistics_rows
Definition: MatrixView.h:137
MatrixModel * m_model
Definition: MatrixView.h:98
void exportToFits(const QString &fileName, const int exportTo) const
QAction * action_clear_columns
Definition: MatrixView.h:129
QAction * action_header_format_2
Definition: MatrixView.h:124
QAction * action_remove_columns
Definition: MatrixView.h:128
QAction * action_data_view
Definition: MatrixView.h:139
void adjustHeaders()
Definition: MatrixView.cpp:383
void switchView(QAction *)
Definition: MatrixView.cpp:837
void pasteIntoSelection()
Definition: MatrixView.cpp:682
QAction * action_mirror_horizontally
Definition: MatrixView.h:116
QShortcut * sel_all
Definition: MatrixView.h:151
bool isColumnSelected(int col, bool full=false) const
Definition: MatrixView.cpp:443
void cutSelection()
Definition: MatrixView.cpp:639
QAction * action_add_columns
Definition: MatrixView.h:130
int firstSelectedColumn(bool full=false) const
Definition: MatrixView.cpp:477
void insertEmptyRows()
Definition: MatrixView.cpp:925
QAction * action_insert_rows
Definition: MatrixView.h:133
QAction * action_insert_columns
Definition: MatrixView.h:127
void resizeHeaders()
Definition: MatrixView.cpp:415
void clearSelectedCells()
Definition: MatrixView.cpp:745
void headerFormatChanged(QAction *)
Definition: MatrixView.cpp:854
MatrixView(Matrix *)
Definition: MatrixView.cpp:67
void initActions()
Definition: MatrixView.cpp:142
int lastSelectedColumn(bool full=false) const
Definition: MatrixView.cpp:490
void matrixDataChanged()
Definition: MatrixView.cpp:848
void fillWithFunctionValues()
Definition: MatrixView.cpp:617
QAction * action_add_value
Definition: MatrixView.h:118
~MatrixView() override
Definition: MatrixView.cpp:86
void removeSelectedColumns()
Definition: MatrixView.cpp:893
int selectedRowCount(bool full=false) const
Definition: MatrixView.cpp:454
Matrix * m_matrix
Definition: MatrixView.h:97
void init()
Definition: MatrixView.cpp:94
void exportToLaTeX(const QString &, const bool verticalHeaders, const bool horizontalHeaders, const bool latexHeaders, const bool gridLines, const bool entire, const bool captions) const
QAction * action_header_format_1
Definition: MatrixView.h:123
QAction * action_fill_const
Definition: MatrixView.h:142
void goToCell()
Definition: MatrixView.cpp:589
void addRows()
Definition: MatrixView.cpp:921
QMenu * m_matrixMenu
Definition: MatrixView.h:148
int firstSelectedRow(bool full=false) const
Definition: MatrixView.cpp:502
void createContextMenu(QMenu *) const
Definition: MatrixView.cpp:331
void setCellsSelected(int first_row, int first_col, int last_row, int last_col)
Definition: MatrixView.cpp:533
void keyPressEvent(QKeyEvent *) override
Definition: MatrixView.cpp:570
QAction * action_header_format_3
Definition: MatrixView.h:125
QAction * action_clear_rows
Definition: MatrixView.h:135
void setCellSelected(int row, int col)
Definition: MatrixView.cpp:529
void showRowStatistics()
QMenu * m_selectionMenu
Definition: MatrixView.h:145
MatrixModel * model() const
Definition: MatrixView.cpp:90
void copySelection()
Definition: MatrixView.cpp:650
void fillWithConstValues()
Definition: MatrixView.cpp:622
QAction * action_fill_function
Definition: MatrixView.h:141
QAction * action_cut_selection
Definition: MatrixView.h:103
QMenu * m_columnMenu
Definition: MatrixView.h:146
QAction * action_mirror_vertically
Definition: MatrixView.h:115
void handleVerticalSectionResized(int logicalIndex, int oldSize, int newSize)
Definition: MatrixView.cpp:612
QAction * action_select_all
Definition: MatrixView.h:108
QAction * action_multiply_value
Definition: MatrixView.h:120
void handleHorizontalSectionResized(int logicalIndex, int oldSize, int newSize)
Definition: MatrixView.cpp:607
int selectedColumnCount(bool full=false) const
Definition: MatrixView.cpp:431
void updateImage()
Definition: MatrixView.cpp:800
QImage m_image
Definition: MatrixView.h:99
void clearSelectedColumns()
Definition: MatrixView.cpp:906
void connectActions()
Definition: MatrixView.cpp:214
int lastSelectedRow(bool full=false) const
Definition: MatrixView.cpp:515
void initMenus()
Definition: MatrixView.cpp:252
QAction * action_add_rows
Definition: MatrixView.h:136
void addColumns()
Definition: MatrixView.cpp:867
QAction * action_clear_selection
Definition: MatrixView.h:106
QAction * action_image_view
Definition: MatrixView.h:140
bool m_imageIsDirty
Definition: MatrixView.h:100
void advanceCell()
Definition: MatrixView.cpp:583
bool isRowSelected(int row, bool full=false) const
Definition: MatrixView.cpp:466
void insertEmptyColumns()
Definition: MatrixView.cpp:871
QAction * action_paste_into_selection
Definition: MatrixView.h:105
bool eventFilter(QObject *, QEvent *) override
Definition: MatrixView.cpp:553
QAction * action_remove_rows
Definition: MatrixView.h:134
QLabel * m_imageLabel
Definition: MatrixView.h:96
void modifyValues()
Definition: MatrixView.cpp:206
QMenu * m_headerFormatMenu
Definition: MatrixView.h:149
QAction * action_subtract_value
Definition: MatrixView.h:119
void showColumnStatistics()
void exportToFile(const QString &path, const QString &separator, QLocale::Language) const
QAction * action_copy_selection
Definition: MatrixView.h:104
void print(QPrinter *) const
Definition: MatrixView.cpp:980
QTableView * m_tableView
Definition: MatrixView.h:95
QAction * action_statistics_columns
Definition: MatrixView.h:131
QAction * action_go_to_cell
Definition: MatrixView.h:110
QStackedWidget * m_stackedWidget
Definition: MatrixView.h:94
QMenu * m_rowMenu
Definition: MatrixView.h:147
void clearSelectedRows()
Definition: MatrixView.cpp:961
Definition: Matrix.h:41
void setData(void *)
Definition: Matrix.cpp:647
void appendRows(int count)
Definition: Matrix.cpp:358
QVector< T > rowCells(int row, int first_column, int last_column)
Return the values in the given cells as vector (needs explicit instantiation)
Definition: Matrix.cpp:631
void insertRows(int before, int count)
Definition: Matrix.cpp:351
QString text(int row, int col)
Return the text displayed in the given cell (needs explicit instantiation)
Definition: Matrix.cpp:427
T cell(int row, int col) const
Return the value in the given cell (needs explicit instantiation)
Definition: Matrix.cpp:416
void removeColumns(int first, int count)
Definition: Matrix.cpp:301
void mirrorHorizontally()
Definition: Matrix.cpp:733
void mirrorVertically()
Definition: Matrix.cpp:757
void setColumnWidth(int col, int width)
This method should only be called by the view.
Definition: Matrix.cpp:603
void * data() const
Definition: Matrix.cpp:191
int rowHeight(int row) const
Definition: Matrix.cpp:607
void insertColumns(int before, int count)
Definition: Matrix.cpp:290
int columnWidth(int col) const
Definition: Matrix.cpp:611
void clearCell(int row, int col)
Definition: Matrix.cpp:457
void transpose()
Definition: Matrix.cpp:709
void setRowHeight(int row, int height)
This method should only be called by the view.
Definition: Matrix.cpp:595
void setCell(int row, int col, T value)
Set the value of the cell (needs explicit instantiation)
Definition: Matrix.cpp:446
void clearRow(int)
Definition: Matrix.cpp:387
void clear()
Clear the whole matrix (i.e. reset all cells)
Definition: Matrix.cpp:683
void requestProjectContextMenu(QMenu *)
void clearColumn(int)
Definition: Matrix.cpp:326
void appendColumns(int count)
Definition: Matrix.cpp:297
void removeRows(int first, int count)
Definition: Matrix.cpp:362
QImage & m_image
Definition: MatrixView.cpp:794
const void * m_data
Definition: MatrixView.cpp:795
void run() override
Definition: MatrixView.cpp:778
UpdateImageTask(int start, int end, QImage &image, const void *data, double scaleFactor, double min)
Definition: MatrixView.cpp:771
double m_scaleFactor
Definition: MatrixView.cpp:796
#define WAIT_CURSOR
Definition: macros.h:63
#define RESET_CURSOR
Definition: macros.h:64
#define SET_NUMBER_LOCALE
Definition: macros.h:75
#define i18n(m)
Definition: nsl_common.h:38