1 /***************************************************************************
2         File                 : ApplicationWindow.cpp
3         Project              : SciDAVis
4         Description          : SciDAVis's main window
5     --------------------------------------------------------------------
6     Copyright            : (C) 2006-2009 Knut Franke (knut.franke*gmx.de)
7     Copyright            : (C) 2006-2009 Tilman Benkert (thzs*gmx.net)
8     Copyright            : (C) 2004-2007 by Ion Vasilief (ion_vasilief*yahoo.fr)
9                            (replace * with @ in the email address)
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 
32 #define HOMEPAGE_URI "http://scidavis.sourceforge.net"
33 #define MANUAL_URI "http://sourceforge.net/projects/scidavis/files/SciDAVis%20Documentation/0.1/"
34 #define FORUM_URI "http://sourceforge.net/forum/?group_id=199120"
35 #define BUGREPORT_URI "http://sourceforge.net/tracker/?group_id=199120&atid=968214"
36 #define DOWNLOAD_URI "http://sourceforge.net/projects/scidavis/files/SciDAVis/"
37 
38 #include "globals.h"
39 #include "ApplicationWindow.h"
40 #include "CurvesDialog.h"
41 #include "PlotDialog.h"
42 #include "AxesDialog.h"
43 #include "LineDialog.h"
44 #include "TextDialog.h"
45 #include "ExportDialog.h"
46 #include "ErrDialog.h"
47 #include "Legend.h"
48 #include "ArrowMarker.h"
49 #include "ImageMarker.h"
50 #include "Graph.h"
51 #include "Plot.h"
52 #include "Grid.h"
53 #include "PlotWizard.h"
54 #include "PolynomFitDialog.h"
55 #include "ExpDecayDialog.h"
56 #include "FunctionDialog.h"
57 #include "FitDialog.h"
58 #include "SurfaceDialog.h"
59 #include "Graph3D.h"
60 #include "Plot3DDialog.h"
61 #include "ImageDialog.h"
62 #include "MultiLayer.h"
63 #include "LayerDialog.h"
64 #include "DataSetDialog.h"
65 #include "IntDialog.h"
66 #include "ConfigDialog.h"
67 #ifdef ORIGIN_IMPORT
68 #include "importOPJ.h"
69 #endif
70 #include "AssociationsDialog.h"
71 #include "RenameWindowDialog.h"
72 #include "QwtErrorPlotCurve.h"
73 #include "InterpolationDialog.h"
74 #include "ImportASCIIDialog.h"
75 #include "ImageExportDialog.h"
76 #include "SmoothCurveDialog.h"
77 #include "FilterDialog.h"
78 #include "FFTDialog.h"
79 #include "Note.h"
80 #include "Folder.h"
81 #include "FindDialog.h"
82 #include "ScaleDraw.h"
83 #include "ScriptingLangDialog.h"
84 #include "TableStatistics.h"
85 #include "Fit.h"
86 #include "MultiPeakFit.h"
87 #include "PolynomialFit.h"
88 #include "SigmoidalFit.h"
89 #include "FunctionCurve.h"
90 #include "QwtPieCurve.h"
91 #include "Spectrogram.h"
92 #include "Differentiation.h"
93 #include "SmoothFilter.h"
94 #include "FFTFilter.h"
95 #include "Convolution.h"
96 #include "Correlation.h"
97 #include "CurveRangeDialog.h"
98 #include "ColorButton.h"
99 #include "QwtHistogram.h"
100 #include "OpenProjectDialog.h"
101 #include "IconLoader.h"
102 #include "core/Project.h"
103 #include "core/column/Column.h"
104 #include "lib/XmlStreamReader.h"
105 #include "table/future_Table.h"
106 
107 // TODO: move tool-specific code to an extension manager
108 #include "ScreenPickerTool.h"
109 #include "DataPickerTool.h"
110 #include "TranslateCurveTool.h"
111 #include "MultiPeakFitTool.h"
112 #include "LineProfileTool.h"
113 
114 #include <stdio.h>
115 #include <stdlib.h>
116 
117 #include <QFileDialog>
118 #include <QInputDialog>
119 #include <QProgressDialog>
120 #include <QPrintDialog>
121 #include <QPixmapCache>
122 #include <QMenuBar>
123 #include <QClipboard>
124 #include <QMdiArea>
125 #include <QMdiSubWindow>
126 #include <QTranslator>
127 #include <QSplitter>
128 #include <QApplication>
129 #include <QMessageBox>
130 #include <QPrinter>
131 #include <QActionGroup>
132 #include <QAction>
133 #include <QToolBar>
134 #include <QKeySequence>
135 #include <QImageReader>
136 #include <QImageWriter>
137 #include <QDateTime>
138 #include <QShortcut>
139 #include <QDockWidget>
140 #include <QTextStream>
141 #include <QVarLengthArray>
142 #include <QList>
143 #include <QUrl>
144 #include <QDesktopServices>
145 #include <QStatusBar>
146 #include <QToolButton>
147 #include <QSignalMapper>
148 #include <QUndoStack>
149 #include <QtDebug>
150 #include <QDialogButtonBox>
151 #include <QUndoView>
152 #include <QUndoStack>
153 #include <QTemporaryFile>
154 #include <QDebug>
155 #include <QTextCodec>
156 #include <QScrollBar>
157 #include <QMimeData>
158 #include <QElapsedTimer>
159 
160 #include <zlib.h>
161 
162 #include <iostream>
163 #include <memory>
164 using namespace std;
165 
166 #ifdef Q_OS_WIN
167 #include <io.h> // for _commit()
168 #else
169 #include <unistd.h> // for fsync()
170 #endif
171 
172 using namespace Qwt3D;
173 
174 extern "C" {
175 void file_compress(const char *file, const char *mode);
176 }
177 
ApplicationWindow()178 ApplicationWindow::ApplicationWindow()
179     : scripted(ScriptingLangManager::newEnv(this)),
180       //      logWindow(new QDockWidget(this)),
181       //      explorerWindow(new QDockWidget(this)),
182       //      results(new QTextEdit(logWindow)),
183       //#ifdef SCRIPTING_CONSOLE
184       //      consoleWindow(new QDockWidget(this)),
185       //      console(new QTextEdit(consoleWindow)),
186       //#endif
187       //      d_workspace(new QMdiArea(this)),
188       //      lv(new FolderListView()),
189       //      folders(new FolderListView()),
190 
191       //      hiddenWindows(new QList<MyWidget*>()),
192       //      outWindows(new QList<MyWidget*>()),
193       lastModified(0),
194       current_folder(new Folder(tr("UNTITLED"))),
195       show_windows_policy(ActiveFolder),
196       appStyle(qApp->style()->objectName()),
197       appFont(QFont()),
198       projectname("untitled"),
199       logInfo(QString()),
200       savingTimerId(0),
201       copiedLayer(false),
202       renamedTables(QStringList()),
203       copiedMarkerType(Graph::None),
204 #ifdef SEARCH_FOR_UPDATES
205       autoSearchUpdatesRequest(false),
206 #endif
207       lastCopiedLayer(0),
208       explorerSplitter(new QSplitter(Qt::Horizontal, &explorerWindow)),
209       actionNextWindow(new QAction(QIcon(QPixmap(":/next.xpm")), tr("&Next", "next window"), this)),
210       actionPrevWindow(
211               new QAction(QIcon(QPixmap(":/prev.xpm")), tr("&Previous", "previous window"), this))
212 
213 {
214     setAttribute(Qt::WA_DeleteOnClose);
215     QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, false);
216 
217     setWindowTitle(tr("SciDAVis - untitled"));
218 
219     // Icons
220     IconLoader::init();
221     IconLoader::lumen_ = IconLoader::isLight(palette().color(QPalette::Window));
222 
223     initFonts();
224     QPixmapCache::setCacheLimit(20 * QPixmapCache::cacheLimit());
225 
226     d_project = new Project();
227     connect(d_project, SIGNAL(aspectAdded(const AbstractAspect *, int)), this,
228             SLOT(handleAspectAdded(const AbstractAspect *, int)));
229     connect(d_project, SIGNAL(aspectAboutToBeRemoved(const AbstractAspect *, int)), this,
230             SLOT(handleAspectAboutToBeRemoved(const AbstractAspect *, int)));
231 
232     explorerWindow.setWindowTitle(tr("Project Explorer"));
233     explorerWindow.setObjectName(
234             "explorerWindow"); // this is needed for QMainWindow::restoreState()
235     explorerWindow.setMinimumHeight(150);
236     addDockWidget(Qt::BottomDockWidgetArea, &explorerWindow);
237 
238     folders.setObjectName("folders");
239     folders.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
240     folders.setContextMenuPolicy(Qt::CustomContextMenu);
241 
242     folders.setHeaderLabels(QStringList() << tr("Folder") << QString());
243     folders.setRootIsDecorated(true);
244     folders.setColumnWidth(1, 0); // helps autoScroll
245     folders.hideColumn(1); // helps autoScroll
246 #if QT_VERSION >= 0x050000
247     folders.header()->setSectionsClickable(false);
248     folders.header()->setSectionResizeMode(QHeaderView::ResizeToContents);
249 #else
250     folders.header()->setClickable(false);
251     folders.header()->setResizeMode(QHeaderView::ResizeToContents);
252 #endif
253     folders.header()->hide();
254     folders.setSelectionMode(QTreeWidget::SingleSelection);
255 
256     connect(&folders, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this,
257             SLOT(folderItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
258     connect(&folders, SIGNAL(itemRenamed(QTreeWidgetItem *, int, const QString &)), this,
259             SLOT(renameFolder(QTreeWidgetItem *, int, const QString &)));
260     connect(&folders, SIGNAL(customContextMenuRequested(const QPoint &)), this,
261             SLOT(showFolderPopupMenu(const QPoint &)));
262     connect(&folders, SIGNAL(dragItems(QList<QTreeWidgetItem *>)), this,
263             SLOT(dragFolderItems(QList<QTreeWidgetItem *>)));
264     connect(&folders, SIGNAL(dropItems(QTreeWidgetItem *)), this,
265             SLOT(dropFolderItems(QTreeWidgetItem *)));
266     connect(&folders, SIGNAL(renameItem(QTreeWidgetItem *, int)), this,
267             SLOT(startRenameFolder(QTreeWidgetItem *, int)));
268     connect(&folders, SIGNAL(addFolderItem()), this, SLOT(addFolder()));
269     connect(&folders, SIGNAL(deleteSelection()), this, SLOT(deleteSelectedItems()));
270 
271     FolderListItem *fli = new FolderListItem(&folders, current_folder);
272     current_folder->setFolderListItem(fli);
273     folders.setCurrentItem(fli);
274     fli->setExpanded(true);
275 
276     lv.setObjectName("lv");
277     lv.setRootIsDecorated(false);
278     lv.setContextMenuPolicy(Qt::CustomContextMenu);
279     lv.setHeaderLabels(QStringList()
280                        << tr("Name") << tr("Type") << tr("View") << tr("Created") << tr("Label"));
281     lv.header()->setStretchLastSection(true);
282     lv.setMinimumHeight(80);
283     lv.setSelectionMode(QTreeWidget::ExtendedSelection);
284 
285     explorerSplitter->addWidget(&folders);
286     explorerSplitter->addWidget(&lv);
287     explorerWindow.setWidget(explorerSplitter);
288     explorerSplitter->setSizes(QList<int>() << 50 << 50);
289     explorerWindow.hide();
290 
291     logWindow.setObjectName("logWindow"); // this is needed for QMainWindow::restoreState()
292     logWindow.setWindowTitle(tr("Results Log"));
293     addDockWidget(Qt::TopDockWidgetArea, &logWindow);
294 
295     results->setReadOnly(true);
296 
297     logWindow.setWidget(results);
298     logWindow.hide();
299 
300 #ifdef SCRIPTING_CONSOLE
301     consoleWindow.setObjectName("consoleWindow"); // this is needed for QMainWindow::restoreState()
302     consoleWindow.setWindowTitle(tr("Scripting Console"));
303     addDockWidget(Qt::TopDockWidgetArea, &consoleWindow);
304     console.setReadOnly(true);
305     consoleWindow.setWidget(&console);
306     consoleWindow.hide();
307 #endif
308 
309     // Needs to be done after initialization of dock windows,
310     // because we now use QDockWidget::toggleViewAction()
311     createActions();
312     initToolBars();
313     initPlot3DToolBar();
314     initMainMenu();
315 
316     d_workspace.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
317     d_workspace.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
318     d_workspace.setActivationOrder(QMdiArea::ActivationHistoryOrder);
319     setCentralWidget(&d_workspace);
320     setAcceptDrops(true);
321 
322     readSettings();
323     createLanguagesList();
324     insertTranslatedStrings();
325 
326     actionNextWindow->setShortcut(tr("F5", "next window shortcut"));
327     connect(actionNextWindow, SIGNAL(triggered()), &d_workspace, SLOT(activateNextSubWindow()));
328 
329     actionPrevWindow->setShortcut(tr("F6", "previous window shortcut"));
330     connect(actionPrevWindow, SIGNAL(triggered()), &d_workspace, SLOT(activatePreviousSubWindow()));
331 
332     connect(this, SIGNAL(modified()), this, SLOT(modifiedProject()));
333     connect(&d_workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)), this,
334             SLOT(windowActivated(QMdiSubWindow *)));
335     connect(&lv, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this,
336             SLOT(folderItemDoubleClicked(QTreeWidgetItem *, int)));
337     connect(&lv, SIGNAL(customContextMenuRequested(const QPoint &)), this,
338             SLOT(showWindowPopupMenu(const QPoint &)));
339     connect(&lv, SIGNAL(dragItems(QList<QTreeWidgetItem *>)), this,
340             SLOT(dragFolderItems(QList<QTreeWidgetItem *>)));
341     connect(&lv, SIGNAL(dropItems(QTreeWidgetItem *)), this,
342             SLOT(dropFolderItems(QTreeWidgetItem *)));
343     connect(&lv, SIGNAL(renameItem(QTreeWidgetItem *, int)), this,
344             SLOT(startRenameFolder(QTreeWidgetItem *, int)));
345     connect(&lv, SIGNAL(addFolderItem()), this, SLOT(addFolder()));
346     connect(&lv, SIGNAL(deleteSelection()), this, SLOT(deleteSelectedItems()));
347     connect(&lv, SIGNAL(itemRenamed(QTreeWidgetItem *, int, const QString &)), this,
348             SLOT(renameWindow(QTreeWidgetItem *, int, const QString &)));
349     connect(scriptEnv, SIGNAL(error(const QString &, const QString &, int)), this,
350             SLOT(scriptError(const QString &, const QString &, int)));
351     connect(scriptEnv, SIGNAL(print(const QString &)), this, SLOT(scriptPrint(const QString &)));
352 
353 #ifdef SEARCH_FOR_UPDATES
354     connect(&http, SIGNAL(finished(QNetworkReply *)), this,
355             SLOT(receivedVersionFile(QNetworkReply *)));
356 #endif
357 
358     // this has to be done after connecting scriptEnv
359     scriptEnv->initialize();
360 
361     lv.setDragEnabled(true);
362     lv.setAcceptDrops(true);
363     lv.setDefaultDropAction(Qt::MoveAction);
364     folders.setDragEnabled(true);
365     folders.setAcceptDrops(true);
366     folders.setDefaultDropAction(Qt::MoveAction);
367 
368     connect(d_project->undoStack(), SIGNAL(canUndoChanged(bool)), actionUndo,
369             SLOT(setEnabled(bool)));
370     connect(d_project->undoStack(), SIGNAL(canRedoChanged(bool)), actionRedo,
371             SLOT(setEnabled(bool)));
372 }
373 
initFonts()374 void ApplicationWindow::initFonts()
375 {
376     QString family = appFont.family();
377     int pointSize = appFont.pointSize();
378     tableTextFont = appFont;
379     tableHeaderFont = appFont;
380     plotAxesFont = QFont(family, pointSize, QFont::Bold, false);
381     plotNumbersFont = QFont(family, pointSize);
382     plotLegendFont = appFont;
383     plotTitleFont = QFont(family, pointSize + 2, QFont::Bold, false);
384 
385     plot3DAxesFont = QFont(family, pointSize, QFont::Bold, false);
386     plot3DNumbersFont = QFont(family, pointSize);
387     plot3DTitleFont = QFont(family, pointSize + 2, QFont::Bold, false);
388 }
389 
applyUserSettings()390 void ApplicationWindow::applyUserSettings()
391 {
392     updateAppFonts();
393     setScriptingLang(defaultScriptingLang);
394 
395     d_workspace.setBackground(workspaceColor);
396 
397     QPalette cg;
398     cg.setColor(QPalette::Base, QColor(panelsColor));
399     qApp->setPalette(cg);
400 
401     cg.setColor(QPalette::Text, QColor(panelsTextColor));
402     cg.setColor(QPalette::WindowText, QColor(panelsTextColor));
403     cg.setColor(QPalette::HighlightedText, QColor(panelsTextColor));
404     lv.setPalette(cg);
405     results->setPalette(cg);
406 
407     cg.setColor(QPalette::Text, QColor(Qt::green));
408     cg.setColor(QPalette::HighlightedText, QColor(Qt::darkGreen));
409     cg.setColor(QPalette::Base, QColor(Qt::black));
410 }
411 
initToolBars()412 void ApplicationWindow::initToolBars()
413 {
414     setWindowIcon(QIcon(":/appicon"));
415     QPixmap openIcon, saveIcon;
416 
417     file_tools = new QToolBar(tr("File"), this);
418     file_tools->setObjectName("file_tools"); // this is needed for QMainWindow::restoreState()
419     file_tools->setIconSize(QSize(22, 22));
420     addToolBar(Qt::TopToolBarArea, file_tools);
421 
422     file_tools->addAction(actionNewProject);
423 
424     QMenu *menu_new_aspect = new QMenu(this);
425     menu_new_aspect->addAction(actionNewTable);
426     menu_new_aspect->addAction(actionNewMatrix);
427     menu_new_aspect->addAction(actionNewNote);
428     menu_new_aspect->addAction(actionNewGraph);
429     menu_new_aspect->addAction(actionNewFunctionPlot);
430     menu_new_aspect->addAction(actionNewSurfacePlot);
431     QToolButton *btn_new_aspect = new QToolButton(this);
432     btn_new_aspect->setMenu(menu_new_aspect);
433     btn_new_aspect->setPopupMode(QToolButton::InstantPopup);
434     btn_new_aspect->setIcon(QPixmap(":/new_aspect.xpm"));
435     btn_new_aspect->setToolTip(tr("New Aspect"));
436     file_tools->addWidget(btn_new_aspect);
437 
438     file_tools->addAction(actionOpen);
439     file_tools->addAction(actionOpenTemplate);
440     file_tools->addAction(actionLoad);
441     file_tools->addAction(actionSaveProject);
442     file_tools->addAction(actionSaveTemplate);
443 
444     file_tools->addSeparator();
445 
446     file_tools->addAction(actionPrint);
447     file_tools->addAction(actionExportPDF);
448 
449     file_tools->addSeparator();
450 
451     file_tools->addAction(actionShowExplorer);
452     file_tools->addAction(actionShowLog);
453     file_tools->addAction(locktoolbar);
454 
455     edit_tools = new QToolBar(tr("Edit"), this);
456     edit_tools->setObjectName("edit_tools"); // this is needed for QMainWindow::restoreState()
457     edit_tools->setIconSize(QSize(22, 22));
458     addToolBar(edit_tools);
459 
460     edit_tools->addAction(actionUndo);
461     edit_tools->addAction(actionRedo);
462     edit_tools->addAction(actionCutSelection);
463     edit_tools->addAction(actionCopySelection);
464     edit_tools->addAction(actionPasteSelection);
465     edit_tools->addAction(actionClearSelection);
466 
467     graph_tools = new QToolBar(tr("Graph"), this);
468     graph_tools->setObjectName("graph_tools"); // this is needed for QMainWindow::restoreState()
469     graph_tools->setIconSize(QSize(22, 22));
470     addToolBar(graph_tools);
471 
472     dataTools = new QActionGroup(this);
473     dataTools->setExclusive(true);
474 
475     btnPointer = new QAction(tr("Disable &Tools"), this);
476     btnPointer->setActionGroup(dataTools);
477     btnPointer->setCheckable(true);
478     btnPointer->setIcon(QIcon(QPixmap(":/pointer.xpm")));
479     btnPointer->setChecked(true);
480     graph_tools->addAction(btnPointer);
481 
482     graph_tools->addSeparator();
483 
484     QMenu *menu_layers = new QMenu(this);
485     QToolButton *btn_layers = new QToolButton(this);
486     btn_layers->setMenu(menu_layers);
487     btn_layers->setPopupMode(QToolButton::InstantPopup);
488     btn_layers->setIcon(QPixmap(":/arrangeLayers.xpm"));
489     btn_layers->setToolTip(tr("Manage layers"));
490     graph_tools->addWidget(btn_layers);
491 
492     menu_layers->addAction(actionAutomaticLayout);
493     menu_layers->addAction(actionAddLayer);
494     menu_layers->addAction(actionDeleteLayer);
495     menu_layers->addAction(actionShowLayerDialog);
496 
497     QMenu *menu_curves = new QMenu(this);
498     QToolButton *btn_curves = new QToolButton(this);
499     btn_curves->setMenu(menu_curves);
500     btn_curves->setPopupMode(QToolButton::InstantPopup);
501     btn_curves->setIcon(QPixmap(":/curves.xpm"));
502     btn_curves->setToolTip(tr("Add curves / error bars"));
503     graph_tools->addWidget(btn_curves);
504 
505     menu_curves->addAction(actionShowCurvesDialog);
506     menu_curves->addAction(actionAddErrorBars);
507     menu_curves->addAction(actionAddFunctionCurve);
508 
509     QMenu *menu_plot_enrichments = new QMenu(this);
510     QToolButton *btn_plot_enrichments = new QToolButton(this);
511     btn_plot_enrichments->setMenu(menu_plot_enrichments);
512     btn_plot_enrichments->setPopupMode(QToolButton::InstantPopup);
513     btn_plot_enrichments->setIcon(QPixmap(":/text.xpm"));
514     btn_plot_enrichments->setToolTip(tr("Enrichments"));
515     graph_tools->addWidget(btn_plot_enrichments);
516 
517     actionAddText = new QAction(tr("Add &Text"), this);
518     actionAddText->setShortcut(tr("ALT+T"));
519     actionAddText->setIcon(QIcon(QPixmap(":/text.xpm")));
520     actionAddText->setCheckable(true);
521     connect(actionAddText, SIGNAL(triggered()), this, SLOT(addText()));
522     menu_plot_enrichments->addAction(actionAddText);
523 
524     btnArrow = new QAction(tr("Draw &Arrow"), this);
525     btnArrow->setShortcut(tr("CTRL+ALT+A"));
526     btnArrow->setActionGroup(dataTools);
527     btnArrow->setCheckable(true);
528     btnArrow->setIcon(QIcon(QPixmap(":/arrow.xpm")));
529     menu_plot_enrichments->addAction(btnArrow);
530 
531     btnLine = new QAction(tr("Draw &Line"), this);
532     btnLine->setShortcut(tr("CTRL+ALT+L"));
533     btnLine->setActionGroup(dataTools);
534     btnLine->setCheckable(true);
535     btnLine->setIcon(QIcon(QPixmap(":/lPlot.xpm")));
536     menu_plot_enrichments->addAction(btnLine);
537 
538     menu_plot_enrichments->addAction(actionTimeStamp);
539     menu_plot_enrichments->addAction(actionAddImage);
540     menu_plot_enrichments->addAction(actionNewLegend);
541 
542     graph_tools->addSeparator();
543 
544     btnZoomIn = new QAction(tr("&Zoom In"), this);
545     btnZoomIn->setShortcut(tr("Ctrl++"));
546     btnZoomIn->setActionGroup(dataTools);
547     btnZoomIn->setCheckable(true);
548     btnZoomIn->setIcon(QIcon(QPixmap(":/zoom.xpm")));
549     graph_tools->addAction(btnZoomIn);
550 
551     btnZoomOut = new QAction(tr("&Zoom Out"), this);
552     btnZoomOut->setShortcut(tr("Ctrl+-"));
553     btnZoomOut->setActionGroup(dataTools);
554     btnZoomOut->setCheckable(true);
555     btnZoomOut->setIcon(QIcon(QPixmap(":/zoomOut.xpm")));
556     graph_tools->addAction(btnZoomOut);
557 
558     graph_tools->addAction(actionUnzoom);
559 
560     graph_tools->addSeparator();
561 
562     btnPicker = new QAction(tr("S&creen Reader"), this);
563     btnPicker->setActionGroup(dataTools);
564     btnPicker->setCheckable(true);
565     btnPicker->setIcon(QIcon(QPixmap(":/cursor_16.xpm")));
566     graph_tools->addAction(btnPicker);
567 
568     btnCursor = new QAction(tr("&Data Reader"), this);
569     btnCursor->setShortcut(tr("CTRL+D"));
570     btnCursor->setActionGroup(dataTools);
571     btnCursor->setCheckable(true);
572     btnCursor->setIcon(QIcon(QPixmap(":/select.xpm")));
573     graph_tools->addAction(btnCursor);
574 
575     btnSelect = new QAction(tr("&Select Data Range"), this);
576     btnSelect->setShortcut(tr("ALT+S"));
577     btnSelect->setActionGroup(dataTools);
578     btnSelect->setCheckable(true);
579     btnSelect->setIcon(QIcon(QPixmap(":/cursors.xpm")));
580     graph_tools->addAction(btnSelect);
581 
582     btnMovePoints = new QAction(tr("&Move Data Points..."), this);
583     btnMovePoints->setShortcut(tr("Ctrl+ALT+M"));
584     btnMovePoints->setActionGroup(dataTools);
585     btnMovePoints->setCheckable(true);
586     btnMovePoints->setIcon(QIcon(QPixmap(":/hand.xpm")));
587 
588     btnRemovePoints = new QAction(tr("Remove &Bad Data Points..."), this);
589     btnRemovePoints->setShortcut(tr("Alt+B"));
590     btnRemovePoints->setActionGroup(dataTools);
591     btnRemovePoints->setCheckable(true);
592     btnRemovePoints->setIcon(QIcon(QPixmap(":/gomme.xpm")));
593 
594     connect(dataTools, SIGNAL(triggered(QAction *)), this, SLOT(pickDataTool(QAction *)));
595 
596     plot_tools = new QToolBar(tr("Plot"), this);
597     plot_tools->setObjectName("plot_tools"); // this is needed for QMainWindow::restoreState()
598     plot_tools->setIconSize(QSize(22, 22));
599     addToolBar(Qt::TopToolBarArea, plot_tools);
600 
601     QMenu *menu_plot_linespoints = new QMenu(this);
602     QToolButton *btn_plot_linespoints = new QToolButton(this);
603     btn_plot_linespoints->setMenu(menu_plot_linespoints);
604     btn_plot_linespoints->setPopupMode(QToolButton::InstantPopup);
605     btn_plot_linespoints->setIcon(QPixmap(":/lpPlot.xpm"));
606     btn_plot_linespoints->setToolTip(tr("Lines and/or symbols"));
607     plot_tools->addWidget(btn_plot_linespoints);
608     menu_plot_linespoints->addAction(actionPlotL);
609     menu_plot_linespoints->addAction(actionPlotP);
610     menu_plot_linespoints->addAction(actionPlotLP);
611     menu_plot_linespoints->addAction(actionPlotSpline);
612     menu_plot_linespoints->addAction(actionPlotVerticalDropLines);
613     menu_plot_linespoints->addAction(actionPlotHorSteps);
614     menu_plot_linespoints->addAction(actionPlotVertSteps);
615 
616     QMenu *menu_plot_bars = new QMenu(this);
617     QToolButton *btn_plot_bars = new QToolButton(this);
618     btn_plot_bars->setMenu(menu_plot_bars);
619     btn_plot_bars->setPopupMode(QToolButton::InstantPopup);
620     btn_plot_bars->setIcon(QPixmap(":/vertBars.xpm"));
621     plot_tools->addWidget(btn_plot_bars);
622     menu_plot_bars->addAction(actionPlotVerticalBars);
623     menu_plot_bars->addAction(actionPlotHorizontalBars);
624 
625     plot_tools->addAction(actionPlotArea);
626     plot_tools->addAction(actionPlotPie);
627     plot_tools->addAction(actionPlotHistogram);
628     plot_tools->addAction(actionBoxPlot);
629 
630     QMenu *menu_plot_vect = new QMenu(this);
631     QToolButton *btn_plot_vect = new QToolButton(this);
632     btn_plot_vect->setMenu(menu_plot_vect);
633     btn_plot_vect->setPopupMode(QToolButton::InstantPopup);
634     btn_plot_vect->setIcon(QPixmap(":/vectXYXY.xpm"));
635     plot_tools->addWidget(btn_plot_vect);
636     menu_plot_vect->addAction(actionPlotVectXYXY);
637     menu_plot_vect->addAction(actionPlotVectXYAM);
638 
639     plot_tools->addSeparator();
640 
641     plot_tools->addAction(actionPlot3DRibbon);
642     plot_tools->addAction(actionPlot3DBars);
643     plot_tools->addAction(actionPlot3DScatter);
644     plot_tools->addAction(actionPlot3DTrajectory);
645 
646     table_tools = new QToolBar(tr("Table"), this);
647     table_tools->setObjectName("table_tools"); // this is needed for QMainWindow::restoreState()
648     table_tools->setIconSize(QSize(22, 22));
649     addToolBar(Qt::TopToolBarArea, table_tools);
650 
651     graph_tools->setEnabled(false);
652     table_tools->setEnabled(false);
653     plot_tools->setEnabled(false);
654 
655     d_status_info = new QLabel(this);
656     d_status_info->setFrameStyle(QFrame::Sunken | QFrame::StyledPanel);
657     d_status_info->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
658     d_status_info->setContextMenuPolicy(Qt::CustomContextMenu);
659     connect(d_status_info, SIGNAL(customContextMenuRequested(const QPoint &)), this,
660             SLOT(showStatusBarContextMenu(const QPoint &)));
661 
662     statusBar()->addWidget(d_status_info, 1);
663 
664     matrix_plot_tools = new QToolBar(tr("Matrix Plot"), this);
665     matrix_plot_tools->setObjectName("matrix_plot_tools");
666     addToolBar(Qt::BottomToolBarArea, matrix_plot_tools);
667 
668     matrix_plot_tools->addAction(actionPlot3DWireFrame);
669     matrix_plot_tools->addAction(actionPlot3DHiddenLine);
670 
671     matrix_plot_tools->addAction(actionPlot3DPolygons);
672     matrix_plot_tools->addAction(actionPlot3DWireSurface);
673 
674     matrix_plot_tools->addSeparator();
675 
676     matrix_plot_tools->addAction(actionPlot3DBars);
677     matrix_plot_tools->addAction(actionPlot3DScatter);
678 
679     matrix_plot_tools->addSeparator();
680     matrix_plot_tools->addAction(actionColorMap);
681     matrix_plot_tools->addAction(actionContourMap);
682     matrix_plot_tools->addAction(actionGrayMap);
683 
684     matrix_plot_tools->setEnabled(false);
685 }
686 
lockToolbar(const bool status)687 void ApplicationWindow::lockToolbar(const bool status)
688 {
689     if (status) {
690         file_tools->setMovable(false);
691         edit_tools->setMovable(false);
692         graph_tools->setMovable(false);
693         graph_3D_tools->setMovable(false);
694         plot_tools->setMovable(false);
695         table_tools->setMovable(false);
696         matrix_plot_tools->setMovable(false);
697         locktoolbar->setIcon(QIcon(QPixmap(":/lock.xpm")));
698     } else {
699         file_tools->setMovable(true);
700         edit_tools->setMovable(true);
701         graph_tools->setMovable(true);
702         graph_3D_tools->setMovable(true);
703         plot_tools->setMovable(true);
704         table_tools->setMovable(true);
705         matrix_plot_tools->setMovable(true);
706         locktoolbar->setIcon(QIcon(QPixmap(":/unlock.xpm")));
707     }
708 }
709 
insertTranslatedStrings()710 void ApplicationWindow::insertTranslatedStrings()
711 {
712     if (projectname == "untitled")
713         setWindowTitle(tr("SciDAVis - untitled"));
714 
715     lv.headerItem()->setText(0, tr("Name"));
716     lv.headerItem()->setText(1, tr("Type"));
717     lv.headerItem()->setText(2, tr("View"));
718     lv.headerItem()->setText(3, tr("Created"));
719     lv.headerItem()->setText(4, tr("Label"));
720 
721     explorerWindow.setWindowTitle(tr("Project Explorer"));
722     logWindow.setWindowTitle(tr("Results Log"));
723 #ifdef SCRIPTING_CONSOLE
724     consoleWindow.setWindowTitle(tr("Scripting Console"));
725 #endif
726     table_tools->setWindowTitle(tr("Table"));
727     plot_tools->setWindowTitle(tr("Plot"));
728     graph_tools->setWindowTitle(tr("Graph"));
729     file_tools->setWindowTitle(tr("File"));
730     edit_tools->setWindowTitle(tr("Edit"));
731     matrix_plot_tools->setWindowTitle(tr("Matrix Plot"));
732     graph_3D_tools->setWindowTitle(tr("3D Surface"));
733 
734     file->setTitle(tr("&File"));
735     edit->setTitle(tr("&Edit"));
736     view->setTitle(tr("&View"));
737     scriptingMenu->setTitle(tr("Scripting"));
738     graph->setTitle(tr("&Graph"));
739     plot3DMenu->setTitle(tr("3D &Plot"));
740     matrixMenu->setTitle(tr("&Matrix"));
741     tableMenu->setTitle(tr("&Table"));
742     plot2D->setTitle(tr("&Plot"));
743     dataMenu->setTitle(tr("&Analysis"));
744     plotDataMenu->setTitle(tr("&Tools"));
745     calcul->setTitle(tr("&Analysis"));
746     d_quick_fit_menu->setTitle(tr("&Quick Fit"));
747     format->setTitle(tr("For&mat"));
748     windowsMenu->setTitle(tr("&Windows"));
749     help->setTitle(tr("&Help"));
750 
751     type->setTitle(tr("&New"));
752     recent->setTitle(tr("&Recent Projects"));
753     exportPlot->setTitle(tr("&Export Graph"));
754 
755     specialPlot->setTitle(tr("Special Line/Symb&ol"));
756     stat->setTitle(tr("Statistical &Graphs"));
757     panels->setTitle(tr("Pa&nel"));
758     plot3D->setTitle(tr("3&D Plot"));
759 
760     translateMenu->setTitle(tr("&Translate"));
761     smooth->setTitle(tr("&Smooth"));
762     filter->setTitle(tr("&FFT Filter"));
763     decay->setTitle(tr("Fit E&xponential Decay"));
764     multiPeakMenu->setTitle(tr("Fit &Multi-Peak"));
765 
766     translateActionsStrings();
767     for (auto w : windowsList())
768         customMenu(w);
769 }
770 
initMainMenu()771 void ApplicationWindow::initMainMenu()
772 {
773     file = new QMenu(this);
774     file->setTitle(tr("&File"));
775     file->setFont(appFont);
776 
777     type = file->addMenu(tr("&New"));
778     type->setFont(appFont);
779     type->addAction(actionNewProject);
780     type->addAction(actionNewTable);
781     type->addAction(actionNewMatrix);
782     type->addAction(actionNewNote);
783     type->addAction(actionNewGraph);
784     type->addAction(actionNewFunctionPlot);
785     type->addAction(actionNewSurfacePlot);
786 
787     file->addAction(actionOpen);
788 
789     recent = file->addMenu(tr("&Recent Projects"));
790     recent->setFont(appFont);
791 
792     file->addSeparator();
793 
794     file->addAction(actionLoadImage);
795     file->addAction(actionImportImage);
796 
797     file->addSeparator();
798 
799     file->addAction(actionSaveProject);
800     file->addAction(actionSaveProjectAs);
801 
802     file->addSeparator();
803     file->addAction(actionOpenTemplate);
804     file->addAction(actionSaveTemplate);
805     file->addSeparator();
806 
807     exportPlot = file->addMenu(tr("&Export Graph"));
808     exportPlot->addAction(actionExportGraph);
809     exportPlot->addAction(actionExportAllGraphs);
810 
811     file->addAction(actionPrint);
812     file->addAction(actionPrintAllPlots);
813 
814     file->addSeparator();
815 
816     file->addAction(actionShowExportASCIIDialog);
817     file->addAction(actionLoad);
818 
819     file->addSeparator();
820 
821     file->addAction(actionCloseAllWindows);
822 
823     edit = new QMenu(this);
824     edit->setFont(appFont);
825     edit->setTitle(tr("&Edit"));
826     edit->addAction(actionUndo);
827     edit->addAction(actionRedo);
828 
829     edit->addSeparator();
830 
831     edit->addAction(actionCutSelection);
832     edit->addAction(actionCopySelection);
833     edit->addAction(actionPasteSelection);
834     edit->addAction(actionClearSelection);
835 
836     edit->addSeparator();
837 
838     edit->addAction(actionDeleteFitTables);
839     edit->addAction(actionClearLogInfo);
840 
841     edit->addSeparator();
842 
843     edit->addAction(actionShowConfigureDialog);
844 
845     view = new QMenu(this);
846     view->setFont(appFont);
847     view->setTitle(tr("&View"));
848     toolbarsMenu = createToolbarsMenu();
849     if (!toolbarsMenu)
850         toolbarsMenu = new QMenu(this);
851     toolbarsMenu->setTitle(tr("Toolbars"));
852 
853     view->addMenu(toolbarsMenu);
854     view->addAction(locktoolbar);
855     view->addSeparator();
856     view->addAction(actionShowPlotWizard);
857     view->addAction(actionShowExplorer);
858     view->addAction(actionShowLog);
859     view->addAction(actionShowHistory);
860 #ifdef SCRIPTING_CONSOLE
861     view->addAction(actionShowConsole);
862 #endif
863 
864     graph = new QMenu(this);
865     graph->setFont(appFont);
866     graph->setTitle(tr("&Graph"));
867     graph->addAction(actionShowCurvesDialog);
868     graph->addAction(actionAddErrorBars);
869     graph->addAction(actionAddFunctionCurve);
870 
871     graph->addSeparator();
872 
873     graph->addAction(actionAddText);
874     graph->addAction(btnArrow);
875     graph->addAction(btnLine);
876     graph->addAction(actionTimeStamp);
877     graph->addAction(actionAddImage);
878     graph->addAction(actionNewLegend);
879 
880     graph->addSeparator(); // layers section
881     graph->addAction(actionAutomaticLayout);
882     graph->addAction(actionAddLayer);
883     graph->addAction(actionDeleteLayer);
884     graph->addAction(actionShowLayerDialog);
885 
886     plot3DMenu = new QMenu(this);
887     plot3DMenu->setFont(appFont);
888     plot3DMenu->setTitle(tr("3D &Plot"));
889 
890     plot3DMenu->addAction(actionPlot3DWireFrame);
891     plot3DMenu->addAction(actionPlot3DHiddenLine);
892 
893     plot3DMenu->addAction(actionPlot3DPolygons);
894     plot3DMenu->addAction(actionPlot3DWireSurface);
895 
896     plot3DMenu->addSeparator();
897 
898     plot3DMenu->addAction(actionPlot3DBars);
899     plot3DMenu->addAction(actionPlot3DScatter);
900 
901     plot3DMenu->addSeparator();
902     plot3DMenu->addAction(actionColorMap);
903     plot3DMenu->addAction(actionContourMap);
904     plot3DMenu->addAction(actionGrayMap);
905 
906     matrixMenu = new QMenu(this);
907     matrixMenu->setFont(appFont);
908     matrixMenu->setTitle(tr("&Matrix"));
909 
910     tableMenu = new QMenu(this);
911     tableMenu->setFont(appFont);
912     tableMenu->setTitle(tr("&Table"));
913 
914     initPlotMenu();
915     initTableAnalysisMenu();
916     initPlotDataMenu();
917 
918     calcul = new QMenu(this);
919     calcul->setFont(appFont);
920     calcul->setTitle(tr("&Analysis"));
921 
922     translateMenu = calcul->addMenu(tr("&Translate"));
923     translateMenu->setFont(appFont);
924     translateMenu->addAction(actionTranslateVert);
925     translateMenu->addAction(actionTranslateHor);
926     calcul->addSeparator();
927 
928     calcul->addAction(actionDifferentiate);
929     calcul->addAction(actionShowIntDialog);
930 
931     calcul->addSeparator();
932 
933     smooth = calcul->addMenu(tr("&Smooth"));
934     smooth->setFont(appFont);
935     smooth->addAction(actionSmoothSavGol);
936     smooth->addAction(actionSmoothAverage);
937     smooth->addAction(actionSmoothFFT);
938 
939     filter = calcul->addMenu(tr("&FFT Filter"));
940     filter->setFont(appFont);
941     filter->addAction(actionLowPassFilter);
942     filter->addAction(actionHighPassFilter);
943     filter->addAction(actionBandPassFilter);
944     filter->addAction(actionBandBlockFilter);
945 
946     calcul->addSeparator();
947     calcul->addAction(actionInterpolate);
948     calcul->addAction(actionFFT);
949     calcul->addSeparator();
950 
951     d_quick_fit_menu = new QMenu(this);
952     d_quick_fit_menu->setTitle(tr("&Quick Fit"));
953 
954     d_quick_fit_menu->addAction(actionFitLinear);
955     d_quick_fit_menu->addAction(actionShowFitPolynomDialog);
956 
957     d_quick_fit_menu->addSeparator();
958 
959     decay = d_quick_fit_menu->addMenu(tr("Fit E&xponential Decay"));
960     decay->setFont(appFont);
961     decay->addAction(actionShowExpDecayDialog);
962     decay->addAction(actionShowTwoExpDecayDialog);
963     decay->addAction(actionShowExpDecay3Dialog);
964 
965     d_quick_fit_menu->addAction(actionFitExpGrowth);
966     d_quick_fit_menu->addAction(actionFitSigmoidal);
967     d_quick_fit_menu->addAction(actionFitGauss);
968     d_quick_fit_menu->addAction(actionFitLorentz);
969 
970     multiPeakMenu = d_quick_fit_menu->addMenu(tr("Fit &Multi-peak"));
971     multiPeakMenu->setFont(appFont);
972     multiPeakMenu->addAction(actionMultiPeakGauss);
973     multiPeakMenu->addAction(actionMultiPeakLorentz);
974 
975     d_quick_fit_menu->addSeparator();
976 
977     calcul->addMenu(d_quick_fit_menu);
978     calcul->addAction(actionShowFitDialog);
979 
980     format = new QMenu(this);
981     format->setFont(appFont);
982     format->setTitle(tr("For&mat"));
983 
984     scriptingMenu = new QMenu(this);
985     scriptingMenu->setFont(appFont);
986     scriptingMenu->setTitle(tr("Scripting"));
987 
988     windowsMenu = new QMenu(this);
989     windowsMenu->setFont(appFont);
990     windowsMenu->setTitle(tr("&Windows"));
991     connect(windowsMenu, SIGNAL(aboutToShow()), this, SLOT(windowsMenuAboutToShow()));
992 
993     help = new QMenu(this);
994     help->setFont(appFont);
995     help->setTitle(tr("&Help"));
996 
997     help->addAction(actionShowHelp);
998 #ifdef DYNAMIC_MANUAL_PATH
999     help->addAction(actionChooseHelpFolder);
1000 #endif
1001     help->addSeparator();
1002     help->addAction(actionHomePage);
1003 #ifdef SEARCH_FOR_UPDATES
1004     help->addAction(actionCheckUpdates);
1005 #endif
1006 #ifdef DOWNLOAD_LINKS
1007     help->addAction(actionDownloadManual);
1008 #endif
1009     help->addSeparator();
1010     help->addAction(actionHelpForums);
1011     help->addAction(actionHelpBugReports);
1012     help->addSeparator();
1013     help->addAction(actionAbout);
1014 
1015     disableActions();
1016 }
1017 
initPlotDataMenu()1018 void ApplicationWindow::initPlotDataMenu()
1019 {
1020     plotDataMenu = new QMenu(this);
1021     plotDataMenu->setFont(appFont);
1022     plotDataMenu->setTitle(tr("&Tools"));
1023 
1024     plotDataMenu->addAction(btnPointer);
1025     plotDataMenu->addAction(btnZoomIn);
1026     plotDataMenu->addAction(btnZoomOut);
1027     plotDataMenu->addAction(actionUnzoom);
1028     plotDataMenu->addSeparator();
1029 
1030     plotDataMenu->addAction(btnPicker);
1031     plotDataMenu->addAction(btnCursor);
1032     plotDataMenu->addAction(btnSelect);
1033 
1034     plotDataMenu->addSeparator();
1035 
1036     plotDataMenu->addAction(btnMovePoints);
1037     plotDataMenu->addAction(btnRemovePoints);
1038 }
1039 
initPlotMenu()1040 void ApplicationWindow::initPlotMenu()
1041 {
1042     plot2D = new QMenu(this);
1043     plot2D->setFont(appFont);
1044     plot2D->setTitle(tr("&Plot"));
1045 
1046     plot2D->addAction(actionPlotL);
1047     plot2D->addAction(actionPlotP);
1048     plot2D->addAction(actionPlotLP);
1049 
1050     specialPlot = plot2D->addMenu(tr("Special Line/Symb&ol"));
1051     specialPlot->setFont(appFont);
1052     specialPlot->addAction(actionPlotVerticalDropLines);
1053     specialPlot->addAction(actionPlotSpline);
1054     specialPlot->addAction(actionPlotVertSteps);
1055     specialPlot->addAction(actionPlotHorSteps);
1056 
1057     plot2D->addSeparator();
1058 
1059     plot2D->addAction(actionPlotVerticalBars);
1060     plot2D->addAction(actionPlotHorizontalBars);
1061     plot2D->addAction(actionPlotArea);
1062     plot2D->addAction(actionPlotPie);
1063     plot2D->addAction(actionPlotVectXYXY);
1064     plot2D->addAction(actionPlotVectXYAM);
1065 
1066     plot2D->addSeparator();
1067 
1068     stat = plot2D->addMenu(tr("Statistical &Graphs"));
1069     stat->setFont(appFont);
1070     stat->addAction(actionBoxPlot);
1071     stat->addAction(actionPlotHistogram);
1072     stat->addAction(actionPlotStackedHistograms);
1073 
1074     panels = plot2D->addMenu(tr("Pa&nel"));
1075     panels->setFont(appFont);
1076     panels->addAction(actionPlot2VerticalLayers);
1077     panels->addAction(actionPlot2HorizontalLayers);
1078     panels->addAction(actionPlot4Layers);
1079     panels->addAction(actionPlotStackedLayers);
1080 
1081     plot2D->addSeparator();
1082 
1083     plot3D = plot2D->addMenu(tr("3&D Plot"));
1084     plot3D->setFont(appFont);
1085     plot3D->addAction(actionPlot3DRibbon);
1086     plot3D->addAction(actionPlot3DBars);
1087     plot3D->addAction(actionPlot3DScatter);
1088     plot3D->addAction(actionPlot3DTrajectory);
1089 }
1090 
initTableAnalysisMenu()1091 void ApplicationWindow::initTableAnalysisMenu()
1092 {
1093     dataMenu = new QMenu(this);
1094     dataMenu->setFont(appFont);
1095     dataMenu->setTitle(tr("&Analysis"));
1096 
1097     dataMenu->addAction(actionShowColStatistics);
1098     dataMenu->addAction(actionShowRowStatistics);
1099 
1100     dataMenu->addSeparator();
1101     dataMenu->addAction(actionFFT);
1102     dataMenu->addSeparator();
1103     dataMenu->addAction(actionCorrelate);
1104     dataMenu->addAction(actionAutoCorrelate);
1105     dataMenu->addSeparator();
1106     dataMenu->addAction(actionConvolute);
1107     dataMenu->addAction(actionDeconvolute);
1108 
1109     dataMenu->addSeparator();
1110     dataMenu->addAction(actionShowFitDialog);
1111 }
1112 
customMenu(MyWidget * w)1113 void ApplicationWindow::customMenu(MyWidget *w)
1114 {
1115     menuBar()->clear();
1116     menuBar()->addMenu(file);
1117     menuBar()->addMenu(edit);
1118     menuBar()->addMenu(view);
1119     menuBar()->addMenu(scriptingMenu);
1120 
1121     scriptingMenu->clear();
1122 #ifdef SCRIPTING_DIALOG
1123     scriptingMenu->addAction(actionScriptingLang);
1124 #endif
1125     scriptingMenu->addAction(actionRestartScripting);
1126 
1127     // these use the same keyboard shortcut (Ctrl+Return) and should not be enabled at the same time
1128     actionNoteEvaluate->setEnabled(false);
1129 
1130     if (w) {
1131         actionPrintAllPlots->setEnabled(projectHas2DPlots());
1132         actionPrint->setEnabled(true);
1133         actionCutSelection->setEnabled(true);
1134         actionCopySelection->setEnabled(true);
1135         actionPasteSelection->setEnabled(true);
1136         actionClearSelection->setEnabled(true);
1137         actionSaveTemplate->setEnabled(true);
1138 
1139         if (w->inherits("MultiLayer")) {
1140             menuBar()->addMenu(graph);
1141             menuBar()->addMenu(plotDataMenu);
1142             menuBar()->addMenu(calcul);
1143             menuBar()->addMenu(format);
1144 
1145             exportPlot->setEnabled(true);
1146             actionShowExportASCIIDialog->setEnabled(false);
1147             // file->setItemEnabled (closeID,true);
1148 
1149             format->clear();
1150             format->addAction(actionShowPlotDialog);
1151             format->addSeparator();
1152             format->addAction(actionShowScaleDialog);
1153             format->addAction(actionShowAxisDialog);
1154             actionShowAxisDialog->setEnabled(true);
1155             format->addSeparator();
1156             format->addAction(actionShowGridDialog);
1157             format->addAction(actionShowTitleDialog);
1158         } else if (w->inherits("Graph3D")) {
1159             disableActions();
1160 
1161             menuBar()->addMenu(format);
1162 
1163             actionPrint->setEnabled(true);
1164             actionSaveTemplate->setEnabled(true);
1165             exportPlot->setEnabled(true);
1166             // file->setItemEnabled (closeID,true);
1167 
1168             format->clear();
1169             format->addAction(actionShowPlotDialog);
1170             format->addAction(actionShowScaleDialog);
1171             format->addAction(actionShowAxisDialog);
1172             format->addAction(actionShowTitleDialog);
1173             if (((Graph3D *)w)->coordStyle() == Qwt3D::NOCOORD)
1174                 actionShowAxisDialog->setEnabled(false);
1175         } else if (w->inherits("Table")) {
1176             menuBar()->addMenu(plot2D);
1177             menuBar()->addMenu(dataMenu);
1178 
1179             actionShowExportASCIIDialog->setEnabled(true);
1180             exportPlot->setEnabled(false);
1181             // file->setItemEnabled (closeID,true);
1182 
1183             tableMenu->clear();
1184             static_cast<Table *>(w)->d_future_table->fillProjectMenu(tableMenu);
1185             tableMenu->addSeparator();
1186             tableMenu->addAction(actionShowExportASCIIDialog);
1187             tableMenu->addSeparator();
1188             tableMenu->addAction(actionConvertTable);
1189             menuBar()->addMenu(tableMenu);
1190         } else if (w->inherits("Matrix")) {
1191             menuBar()->addMenu(plot3DMenu);
1192 
1193             matrixMenu->clear();
1194             static_cast<Matrix *>(w)->d_future_matrix->fillProjectMenu(matrixMenu);
1195             matrixMenu->addSeparator();
1196             matrixMenu->addAction(actionInvertMatrix);
1197             matrixMenu->addAction(actionMatrixDeterminant);
1198             matrixMenu->addSeparator();
1199             matrixMenu->addAction(actionConvertMatrix);
1200             menuBar()->addMenu(matrixMenu);
1201         } else if (w->inherits("Note")) {
1202             actionSaveTemplate->setEnabled(false);
1203             actionNoteEvaluate->setEnabled(true);
1204             scriptingMenu->addSeparator();
1205             scriptingMenu->addAction(actionNoteExecute);
1206             scriptingMenu->addAction(actionNoteExecuteAll);
1207             scriptingMenu->addAction(actionNoteEvaluate);
1208 
1209             actionNoteExecute->disconnect(SIGNAL(triggered()));
1210             actionNoteExecuteAll->disconnect(SIGNAL(triggered()));
1211             actionNoteEvaluate->disconnect(SIGNAL(triggered()));
1212             connect(actionNoteExecute, SIGNAL(triggered()), w, SLOT(execute()));
1213             connect(actionNoteExecuteAll, SIGNAL(triggered()), w, SLOT(executeAll()));
1214             connect(actionNoteEvaluate, SIGNAL(triggered()), w, SLOT(evaluate()));
1215         } else
1216             disableActions();
1217 
1218         menuBar()->addMenu(windowsMenu);
1219     } else
1220         disableActions();
1221 
1222     menuBar()->addMenu(help);
1223 }
1224 
disableActions()1225 void ApplicationWindow::disableActions()
1226 {
1227     actionSaveTemplate->setEnabled(false);
1228     actionPrintAllPlots->setEnabled(false);
1229     actionPrint->setEnabled(false);
1230     actionShowExportASCIIDialog->setEnabled(false);
1231     exportPlot->setEnabled(false);
1232     // file->setItemEnabled (closeID,false);
1233 
1234     actionUndo->setEnabled(false);
1235     actionRedo->setEnabled(false);
1236 
1237     actionCutSelection->setEnabled(false);
1238     actionCopySelection->setEnabled(false);
1239     actionPasteSelection->setEnabled(false);
1240     actionClearSelection->setEnabled(false);
1241 }
1242 
customToolBars(MyWidget * w)1243 void ApplicationWindow::customToolBars(MyWidget *w)
1244 {
1245     if (w) {
1246         if (!projectHas3DPlots())
1247             graph_3D_tools->setEnabled(false);
1248         if (!projectHas2DPlots())
1249             graph_tools->setEnabled(false);
1250         if (!projectHasMatrices())
1251             matrix_plot_tools->setEnabled(false);
1252         if (tableWindows().count() <= 0) {
1253             table_tools->setEnabled(false);
1254             plot_tools->setEnabled(false);
1255         }
1256 
1257         if (w->inherits("MultiLayer")) {
1258             graph_tools->setEnabled(true);
1259             graph_3D_tools->setEnabled(false);
1260             table_tools->setEnabled(false);
1261             matrix_plot_tools->setEnabled(false);
1262 
1263             Graph *g = static_cast<MultiLayer *>(w)->activeGraph();
1264             if (g) {
1265                 dataTools->blockSignals(true);
1266                 if (g->rangeSelectorsEnabled())
1267                     btnSelect->setChecked(true);
1268                 else if (g->zoomOn())
1269                     btnZoomIn->setChecked(true);
1270                 else if (g->drawArrow())
1271                     btnArrow->setChecked(true);
1272                 else if (g->drawLineActive())
1273                     btnLine->setChecked(true);
1274                 else if (g->activeTool() == 0)
1275                     btnPointer->setChecked(true);
1276                 else
1277                     switch (g->activeTool()->rtti()) {
1278                     case PlotToolInterface::DataPicker:
1279                         switch (static_cast<DataPickerTool *>(g->activeTool())->mode()) {
1280                         case DataPickerTool::Display:
1281                             btnCursor->setChecked(true);
1282                             break;
1283                         case DataPickerTool::Move:
1284                             btnMovePoints->setChecked(true);
1285                             break;
1286                         case DataPickerTool::Remove:
1287                             btnRemovePoints->setChecked(true);
1288                             break;
1289                         }
1290                         break;
1291                     case PlotToolInterface::ScreenPicker:
1292                         btnPicker->setChecked(true);
1293                         break;
1294                     default:
1295                         btnPointer->setChecked(true);
1296                         break;
1297                     }
1298                 dataTools->blockSignals(false);
1299             }
1300             if (g && g->curves() > 0) {
1301                 plot_tools->setEnabled(true);
1302                 QwtPlotCurve *c = g->curve(g->curves() - 1);
1303                 // plot tools managed by d_plot_mapper
1304                 for (int i = 0; i <= (int)Graph::VerticalSteps; i++) {
1305                     QAction *a = static_cast<QAction *>(d_plot_mapper->mapping(i));
1306                     if (a)
1307                         a->setEnabled(Graph::canConvertTo(c, (Graph::CurveType)i));
1308                 }
1309                 // others
1310                 actionPlotPie->setEnabled(Graph::canConvertTo(c, Graph::Pie));
1311                 actionPlotVectXYAM->setEnabled(Graph::canConvertTo(c, Graph::VectXYAM));
1312                 actionPlotVectXYXY->setEnabled(Graph::canConvertTo(c, Graph::VectXYXY));
1313                 actionBoxPlot->setEnabled(Graph::canConvertTo(c, Graph::Box));
1314                 // 3D plots
1315                 actionPlot3DRibbon->setEnabled(false);
1316                 actionPlot3DScatter->setEnabled(false);
1317                 actionPlot3DTrajectory->setEnabled(false);
1318                 actionPlot3DBars->setEnabled(false);
1319             } else
1320                 plot_tools->setEnabled(false);
1321         } else if (w->inherits("Table")) {
1322             table_tools->clear();
1323             static_cast<Table *>(w)->d_future_table->fillProjectToolBar(table_tools);
1324             table_tools->setEnabled(true);
1325 
1326             graph_tools->setEnabled(false);
1327             graph_3D_tools->setEnabled(false);
1328             matrix_plot_tools->setEnabled(false);
1329 
1330             plot_tools->setEnabled(true);
1331             // plot tools managed by d_plot_mapper
1332             for (int i = 0; i <= (int)Graph::VerticalSteps; i++) {
1333                 QAction *a = static_cast<QAction *>(d_plot_mapper->mapping(i));
1334                 if (a)
1335                     a->setEnabled(true);
1336             }
1337             // others
1338             actionPlotPie->setEnabled(true);
1339             actionPlotVectXYAM->setEnabled(true);
1340             actionPlotVectXYXY->setEnabled(true);
1341             actionBoxPlot->setEnabled(true);
1342             // 3D plots
1343             actionPlot3DRibbon->setEnabled(true);
1344             actionPlot3DScatter->setEnabled(true);
1345             actionPlot3DTrajectory->setEnabled(true);
1346             actionPlot3DBars->setEnabled(true);
1347         } else if (w->inherits("Matrix")) {
1348             graph_tools->setEnabled(false);
1349             graph_3D_tools->setEnabled(false);
1350             table_tools->setEnabled(false);
1351             plot_tools->setEnabled(false);
1352             matrix_plot_tools->setEnabled(true);
1353         } else if (w->inherits("Graph3D")) {
1354             graph_tools->setEnabled(false);
1355             table_tools->setEnabled(false);
1356             plot_tools->setEnabled(false);
1357             matrix_plot_tools->setEnabled(false);
1358 
1359             Graph3D *plot = (Graph3D *)w;
1360             if (plot->plotStyle() == Qwt3D::NOPLOT)
1361                 graph_3D_tools->setEnabled(false);
1362             else
1363                 graph_3D_tools->setEnabled(true);
1364 
1365             custom3DActions(w);
1366         } else if (w->inherits("Note")) {
1367             graph_tools->setEnabled(false);
1368             graph_3D_tools->setEnabled(false);
1369             table_tools->setEnabled(false);
1370             plot_tools->setEnabled(false);
1371             matrix_plot_tools->setEnabled(false);
1372         }
1373 
1374     } else {
1375         graph_tools->setEnabled(false);
1376         table_tools->setEnabled(false);
1377         plot_tools->setEnabled(false);
1378         graph_3D_tools->setEnabled(false);
1379         matrix_plot_tools->setEnabled(false);
1380     }
1381 }
1382 
plot3DRibbon()1383 void ApplicationWindow::plot3DRibbon()
1384 {
1385     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Table"))
1386         return;
1387 
1388     Table *table = static_cast<Table *>(d_workspace.activeSubWindow());
1389     if (table->selectedColumns().count() == 1) {
1390         if (!validFor3DPlot(table))
1391             return;
1392         dataPlot3D(table, table->colName(table->firstSelectedColumn()));
1393     } else
1394         QMessageBox::warning(this, tr("Plot error"),
1395                              tr("You must select exactly one column for plotting!"));
1396 }
1397 
plot3DWireframe()1398 void ApplicationWindow::plot3DWireframe()
1399 {
1400     plot3DMatrix(Qwt3D::WIREFRAME);
1401 }
1402 
plot3DHiddenLine()1403 void ApplicationWindow::plot3DHiddenLine()
1404 {
1405     plot3DMatrix(Qwt3D::HIDDENLINE);
1406 }
1407 
plot3DPolygons()1408 void ApplicationWindow::plot3DPolygons()
1409 {
1410     plot3DMatrix(Qwt3D::FILLED);
1411 }
1412 
plot3DWireSurface()1413 void ApplicationWindow::plot3DWireSurface()
1414 {
1415     plot3DMatrix(Qwt3D::FILLEDMESH);
1416 }
1417 
plot3DBars()1418 void ApplicationWindow::plot3DBars()
1419 {
1420     MyWidget *w = (MyWidget *)d_workspace.activeSubWindow();
1421     if (!w)
1422         return;
1423 
1424     if (w->inherits("Table")) {
1425         Table *table = static_cast<Table *>(w);
1426 
1427         if (table->selectedColumns().count() == 1) {
1428             if (!validFor3DPlot(table))
1429                 return;
1430             dataPlotXYZ(table, table->colName(table->firstSelectedColumn()), Graph3D::Bars);
1431         } else
1432             QMessageBox::warning(this, tr("Plot error"),
1433                                  tr("You must select exactly one column for plotting!"));
1434     } else if (w->inherits("Matrix"))
1435         plot3DMatrix(Qwt3D::USER);
1436 }
1437 
plot3DScatter()1438 void ApplicationWindow::plot3DScatter()
1439 {
1440     MyWidget *w = (MyWidget *)d_workspace.activeSubWindow();
1441     if (!w)
1442         return;
1443 
1444     if (w->inherits("Table")) {
1445         Table *table = static_cast<Table *>(w);
1446 
1447         if (table->selectedColumns().count() == 1) {
1448             if (!validFor3DPlot(table))
1449                 return;
1450             dataPlotXYZ(table, table->colName(table->firstSelectedColumn()), Graph3D::Scatter);
1451         } else
1452             QMessageBox::warning(this, tr("Plot error"),
1453                                  tr("You must select exactly one column for plotting!"));
1454     } else if (w->inherits("Matrix"))
1455         plot3DMatrix(Qwt3D::POINTS);
1456 }
1457 
plot3DTrajectory()1458 void ApplicationWindow::plot3DTrajectory()
1459 {
1460     MyWidget *w = (MyWidget *)d_workspace.activeSubWindow();
1461     if (!w)
1462         return;
1463 
1464     if (w->inherits("Table")) {
1465         Table *table = static_cast<Table *>(w);
1466 
1467         if (table->selectedColumns().count() == 1) {
1468             if (!validFor3DPlot(table))
1469                 return;
1470             dataPlotXYZ(table, table->colName(table->firstSelectedColumn()), Graph3D::Trajectory);
1471         } else
1472             QMessageBox::warning(this, tr("Plot error"),
1473                                  tr("You must select exactly one column for plotting!"));
1474     }
1475 }
1476 
plotPie()1477 void ApplicationWindow::plotPie()
1478 {
1479     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Table"))
1480         return;
1481 
1482     Table *table = static_cast<Table *>(d_workspace.activeSubWindow());
1483 
1484     if (table->selectedColumns().count() != 1) {
1485         QMessageBox::warning(this, tr("Plot error"),
1486                              tr("You must select exactly one column for plotting!"));
1487         return;
1488     }
1489     if (table->noXColumn()) {
1490         QMessageBox::critical(0, tr("Error"),
1491                               tr("Please set a default X column for this table, first!"));
1492         return;
1493     }
1494 
1495     QStringList s = table->selectedColumns();
1496     if (s.count() > 0) {
1497         multilayerPlot(table, s, Graph::Pie, table->firstSelectedRow(), table->lastSelectedRow());
1498     } else
1499         QMessageBox::warning(this, tr("Error"), tr("Please select a column to plot!"));
1500 }
1501 
plotVectXYXY()1502 void ApplicationWindow::plotVectXYXY()
1503 {
1504     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Table"))
1505         return;
1506 
1507     Table *table = static_cast<Table *>(d_workspace.activeSubWindow());
1508 
1509     if (!validFor2DPlot(table, Graph::VectXYXY))
1510         return;
1511 
1512     QStringList s = table->selectedColumns();
1513     if (s.count() == 4) {
1514         multilayerPlot(table, s, Graph::VectXYXY, table->firstSelectedRow(),
1515                        table->lastSelectedRow());
1516     } else
1517         QMessageBox::warning(this, tr("Error"),
1518                              tr("Please select four columns for this operation!"));
1519 }
1520 
plotVectXYAM()1521 void ApplicationWindow::plotVectXYAM()
1522 {
1523     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Table"))
1524         return;
1525 
1526     Table *table = static_cast<Table *>(d_workspace.activeSubWindow());
1527 
1528     if (!validFor2DPlot(table, Graph::VectXYAM))
1529         return;
1530 
1531     QStringList s = table->selectedColumns();
1532     if (s.count() == 4) {
1533         multilayerPlot(table, s, Graph::VectXYAM, table->firstSelectedRow(),
1534                        table->lastSelectedRow());
1535     } else
1536         QMessageBox::warning(this, tr("Error"),
1537                              tr("Please select four columns for this operation!"));
1538 }
1539 
renameListViewItem(const QString & oldName,const QString & newName)1540 void ApplicationWindow::renameListViewItem(const QString &oldName, const QString &newName)
1541 {
1542     QTreeWidgetItem *it = lv.findItems(oldName, Qt::MatchExactly | Qt::MatchCaseSensitive).value(0);
1543     if (it)
1544         it->setText(0, newName);
1545 }
1546 
setListViewLabel(const QString & caption,const QString & label)1547 void ApplicationWindow::setListViewLabel(const QString &caption, const QString &label)
1548 {
1549     QTreeWidgetItem *it = lv.findItems(caption, Qt::MatchExactly | Qt::MatchCaseSensitive).value(0);
1550     if (it)
1551         it->setText(4, label);
1552 }
1553 
setListViewDate(const QString & caption,const QString & date)1554 void ApplicationWindow::setListViewDate(const QString &caption, const QString &date)
1555 {
1556     QTreeWidgetItem *it = lv.findItems(caption, Qt::MatchExactly | Qt::MatchCaseSensitive).value(0);
1557     if (it)
1558         it->setText(3, date);
1559 }
1560 
setListView(const QString & caption,const QString & view)1561 void ApplicationWindow::setListView(const QString &caption, const QString &view)
1562 {
1563     QTreeWidgetItem *it = lv.findItems(caption, Qt::MatchExactly | Qt::MatchCaseSensitive).value(0);
1564     if (it)
1565         it->setText(2, view);
1566 }
1567 
updateTableNames(const QString & oldName,const QString & newName)1568 void ApplicationWindow::updateTableNames(const QString &oldName, const QString &newName)
1569 {
1570     QList<MyWidget *> windows = windowsList();
1571     foreach (MyWidget *w, windows) {
1572         if (w->inherits("MultiLayer")) {
1573             QWidgetList gr_lst = ((MultiLayer *)w)->graphPtrs();
1574             foreach (QWidget *widget, gr_lst)
1575                 ((Graph *)widget)->updateCurveNames(oldName, newName);
1576         } else if (w->inherits("Graph3D")) {
1577             QString name = ((Graph3D *)w)->formula();
1578             if (name.contains(oldName, Qt::CaseSensitive)) {
1579                 name.replace(oldName, newName);
1580                 ((Graph3D *)w)->setPlotAssociation(name);
1581             }
1582         }
1583     }
1584 }
1585 
updateColNames(const QString & oldName,const QString & newName)1586 void ApplicationWindow::updateColNames(const QString &oldName, const QString &newName)
1587 {
1588     QList<MyWidget *> windows = windowsList();
1589     foreach (MyWidget *w, windows) {
1590         if (w->inherits("MultiLayer")) {
1591             QWidgetList gr_lst = ((MultiLayer *)w)->graphPtrs();
1592             foreach (QWidget *widget, gr_lst)
1593                 ((Graph *)widget)->updateCurveNames(oldName, newName, false);
1594         } else if (w->inherits("Graph3D")) {
1595             QString name = ((Graph3D *)w)->formula();
1596             if (name.contains(oldName)) {
1597                 name.replace(oldName, newName);
1598                 ((Graph3D *)w)->setPlotAssociation(name);
1599             }
1600         }
1601     }
1602 }
1603 
changeMatrixName(const QString & oldName,const QString & newName)1604 void ApplicationWindow::changeMatrixName(const QString &oldName, const QString &newName)
1605 {
1606     QList<MyWidget *> lst = windowsList();
1607     foreach (MyWidget *w, lst) {
1608         if (w->inherits("Graph3D")) {
1609             QString s = ((Graph3D *)w)->formula();
1610             if (s.contains(oldName)) {
1611                 s.replace(oldName, newName);
1612                 ((Graph3D *)w)->setPlotAssociation(s);
1613             }
1614         } else if (w->inherits("MultiLayer")) {
1615             QWidgetList graphsList = ((MultiLayer *)w)->graphPtrs();
1616             foreach (QWidget *gr_widget, graphsList) {
1617                 Graph *g = (Graph *)gr_widget;
1618                 for (int i = 0; i < g->curves(); i++) {
1619                     QwtPlotItem *sp = (QwtPlotItem *)g->plotItem(i);
1620                     if (sp && sp->rtti() == QwtPlotItem::Rtti_PlotSpectrogram
1621                         && sp->title().text() == oldName)
1622                         sp->setTitle(newName);
1623                 }
1624             }
1625         }
1626     }
1627 }
1628 
remove3DMatrixPlots(Matrix * m)1629 void ApplicationWindow::remove3DMatrixPlots(Matrix *m)
1630 {
1631     if (!m)
1632         return;
1633 
1634     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1635 
1636     QList<MyWidget *> windows = windowsList();
1637     foreach (MyWidget *w, windows) {
1638         if (w->inherits("Graph3D") && ((Graph3D *)w)->matrix() == m)
1639             ((Graph3D *)w)->clearData();
1640         else if (w->inherits("MultiLayer")) {
1641             QWidgetList graphsList = ((MultiLayer *)w)->graphPtrs();
1642             for (int j = 0; j < (int)graphsList.count(); j++) {
1643                 Graph *g = (Graph *)graphsList.at(j);
1644                 for (int i = 0; i < g->curves(); i++) {
1645                     Spectrogram *sp = (Spectrogram *)g->plotItem(i);
1646                     if (sp && sp->rtti() == QwtPlotItem::Rtti_PlotSpectrogram && sp->matrix() == m)
1647                         g->removeCurve(i);
1648                 }
1649             }
1650         }
1651     }
1652     QApplication::restoreOverrideCursor();
1653 }
1654 
updateMatrixPlots(MyWidget * window)1655 void ApplicationWindow::updateMatrixPlots(MyWidget *window)
1656 {
1657     Matrix *m = (Matrix *)window;
1658     if (!m)
1659         return;
1660 
1661     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1662 
1663     QList<MyWidget *> windows = windowsList();
1664     foreach (MyWidget *w, windows) {
1665         if (w->inherits("Graph3D") && ((Graph3D *)w)->matrix() == m)
1666             ((Graph3D *)w)->updateMatrixData(m);
1667         else if (w->inherits("MultiLayer")) {
1668             QWidgetList graphsList = ((MultiLayer *)w)->graphPtrs();
1669             for (int j = 0; j < (int)graphsList.count(); j++) {
1670                 Graph *g = (Graph *)graphsList.at(j);
1671                 for (int i = 0; i < g->curves(); i++) {
1672                     Spectrogram *sp = (Spectrogram *)g->plotItem(i);
1673                     if (sp && sp->rtti() == QwtPlotItem::Rtti_PlotSpectrogram && sp->matrix() == m)
1674                         sp->updateData(m);
1675                 }
1676             }
1677         }
1678     }
1679 
1680     QApplication::restoreOverrideCursor();
1681 }
1682 
add3DData()1683 void ApplicationWindow::add3DData()
1684 {
1685     if (tableWindows().count() <= 0) {
1686         QMessageBox::warning(this, tr("Warning"),
1687                              tr("<h4>There are no tables available in this project.</h4>"
1688                                 "<p><h4>Please create a table and try again!</h4>"));
1689         return;
1690     }
1691 
1692     // TODO: string list -> Column * list
1693     QStringList zColumns = columnsList(SciDAVis::Z);
1694     if ((int)zColumns.count() <= 0) {
1695         QMessageBox::critical(this, tr("Warning"),
1696                               tr("There are no available columns with plot designation set to Z!"));
1697         return;
1698     }
1699 
1700     DataSetDialog *ad = new DataSetDialog(tr("Column") + " : ", this);
1701     ad->setAttribute(Qt::WA_DeleteOnClose);
1702     connect(ad, SIGNAL(options(const QString &)), this, SLOT(insertNew3DData(const QString &)));
1703     ad->setWindowTitle(tr("Choose data set"));
1704     ad->setCurveNames(zColumns);
1705     ad->exec();
1706 }
1707 
change3DData()1708 void ApplicationWindow::change3DData()
1709 {
1710     DataSetDialog *ad = new DataSetDialog(tr("Column") + " : ", this);
1711     ad->setAttribute(Qt::WA_DeleteOnClose);
1712     connect(ad, SIGNAL(options(const QString &)), this, SLOT(change3DData(const QString &)));
1713 
1714     ad->setWindowTitle(tr("Choose data set"));
1715     // TODO: string list -> Column * list
1716     ad->setCurveNames(columnsList(SciDAVis::Z));
1717     ad->exec();
1718 }
1719 
change3DMatrix()1720 void ApplicationWindow::change3DMatrix()
1721 {
1722     DataSetDialog *ad = new DataSetDialog(tr("Matrix") + " : ", this);
1723     ad->setAttribute(Qt::WA_DeleteOnClose);
1724     connect(ad, SIGNAL(options(const QString &)), this, SLOT(change3DMatrix(const QString &)));
1725 
1726     ad->setWindowTitle(tr("Choose matrix to plot"));
1727     ad->setCurveNames(matrixNames());
1728 
1729     Graph3D *g = (Graph3D *)d_workspace.activeSubWindow();
1730     if (g && g->matrix())
1731         ad->setCurentDataSet(g->matrix()->name());
1732     ad->exec();
1733 }
1734 
change3DMatrix(const QString & matrix_name)1735 void ApplicationWindow::change3DMatrix(const QString &matrix_name)
1736 {
1737     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D")) {
1738         Graph3D *g = (Graph3D *)d_workspace.activeSubWindow();
1739         Matrix *m = matrix(matrix_name);
1740         if (m && g)
1741             g->changeMatrix(m);
1742 
1743         emit modified();
1744     }
1745 }
1746 
add3DMatrixPlot()1747 void ApplicationWindow::add3DMatrixPlot()
1748 {
1749     QStringList matrices = matrixNames();
1750     if ((int)matrices.count() <= 0) {
1751         QMessageBox::warning(this, tr("Warning"),
1752                              tr("<h4>There are no matrices available in this project.</h4>"
1753                                 "<p><h4>Please create a matrix and try again!</h4>"));
1754         return;
1755     }
1756 
1757     DataSetDialog *ad = new DataSetDialog(tr("Matrix") + " :", this);
1758     ad->setAttribute(Qt::WA_DeleteOnClose);
1759     connect(ad, SIGNAL(options(const QString &)), this, SLOT(insert3DMatrixPlot(const QString &)));
1760 
1761     ad->setWindowTitle(tr("Choose matrix to plot"));
1762     ad->setCurveNames(matrices);
1763     ad->exec();
1764 }
1765 
insert3DMatrixPlot(const QString & matrix_name)1766 void ApplicationWindow::insert3DMatrixPlot(const QString &matrix_name)
1767 {
1768     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D")) {
1769         ((Graph3D *)d_workspace.activeSubWindow())->addMatrixData(matrix(matrix_name));
1770         emit modified();
1771     }
1772 }
1773 
insertNew3DData(const QString & colName)1774 void ApplicationWindow::insertNew3DData(const QString &colName)
1775 {
1776     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D")) {
1777         ((Graph3D *)d_workspace.activeSubWindow())->insertNewData(table(colName), colName);
1778         emit modified();
1779     }
1780 }
1781 
change3DData(const QString & colName)1782 void ApplicationWindow::change3DData(const QString &colName)
1783 {
1784     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D")) {
1785         ((Graph3D *)d_workspace.activeSubWindow())->changeDataColumn(table(colName), colName);
1786         emit modified();
1787     }
1788 }
1789 
editSurfacePlot()1790 void ApplicationWindow::editSurfacePlot()
1791 {
1792     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D")) {
1793         Graph3D *g = (Graph3D *)d_workspace.activeSubWindow();
1794 
1795         SurfaceDialog *sd = new SurfaceDialog(this);
1796         sd->setAttribute(Qt::WA_DeleteOnClose);
1797         connect(sd,
1798                 SIGNAL(options(const QString &, double, double, double, double, double, double)), g,
1799                 SLOT(insertFunction(const QString &, double, double, double, double, double,
1800                                     double)));
1801         connect(sd, SIGNAL(clearFunctionsList()), this, SLOT(clearSurfaceFunctionsList()));
1802 
1803         sd->insertFunctionsList(surfaceFunc);
1804         if (g->hasData()) {
1805             sd->setFunction(g->formula());
1806             sd->setLimits(g->xStart(), g->xStop(), g->yStart(), g->yStop(), g->zStart(),
1807                           g->zStop());
1808         }
1809         sd->exec();
1810     }
1811 }
1812 
newSurfacePlot()1813 void ApplicationWindow::newSurfacePlot()
1814 {
1815     SurfaceDialog *sd = new SurfaceDialog(this);
1816     sd->setAttribute(Qt::WA_DeleteOnClose);
1817     connect(sd, SIGNAL(options(const QString &, double, double, double, double, double, double)),
1818             this, SLOT(newPlot3D(const QString &, double, double, double, double, double, double)));
1819     connect(sd, SIGNAL(clearFunctionsList()), this, SLOT(clearSurfaceFunctionsList()));
1820 
1821     sd->insertFunctionsList(surfaceFunc);
1822     sd->exec();
1823 }
1824 
newPlot3D(const QString & formula,double xl,double xr,double yl,double yr,double zl,double zr)1825 Graph3D *ApplicationWindow::newPlot3D(const QString &formula, double xl, double xr, double yl,
1826                                       double yr, double zl, double zr)
1827 {
1828     QString label = generateUniqueName(tr("Graph"));
1829 
1830     Graph3D *plot = new Graph3D("", &d_workspace, 0);
1831     plot->setAttribute(Qt::WA_DeleteOnClose);
1832     plot->addFunction(formula, xl, xr, yl, yr, zl, zr);
1833     plot->resize(500, 400);
1834     plot->setWindowTitle(label);
1835     plot->setName(label);
1836     customPlot3D(plot);
1837     plot->update();
1838 
1839     initPlot3D(plot);
1840 
1841     emit modified();
1842     return plot;
1843 }
1844 
updateSurfaceFuncList(const QString & s)1845 void ApplicationWindow::updateSurfaceFuncList(const QString &s)
1846 {
1847     surfaceFunc.removeAll(s);
1848     surfaceFunc.push_front(s);
1849     while ((int)surfaceFunc.size() > 10)
1850         surfaceFunc.pop_back();
1851 }
1852 
newPlot3D(const QString & caption,const QString & formula,double xl,double xr,double yl,double yr,double zl,double zr)1853 Graph3D *ApplicationWindow::newPlot3D(const QString &caption, const QString &formula, double xl,
1854                                       double xr, double yl, double yr, double zl, double zr)
1855 {
1856     Graph3D *plot = new Graph3D("", &d_workspace, 0);
1857     plot->setAttribute(Qt::WA_DeleteOnClose);
1858     plot->addFunction(formula, xl, xr, yl, yr, zl, zr);
1859     plot->update();
1860 
1861     QString label = caption;
1862     while (alreadyUsedName(label))
1863         label = generateUniqueName(tr("Graph"));
1864 
1865     plot->setWindowTitle(label);
1866     plot->setName(label);
1867     initPlot3D(plot);
1868     return plot;
1869 }
1870 
dataPlot3D(Table * table,const QString & colName)1871 Graph3D *ApplicationWindow::dataPlot3D(Table *table, const QString &colName)
1872 {
1873     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1874 
1875     QString label = generateUniqueName(tr("Graph"));
1876     Graph3D *plot = new Graph3D("", &d_workspace, 0);
1877     plot->setAttribute(Qt::WA_DeleteOnClose);
1878     plot->addData(table, colName);
1879     plot->resize(500, 400);
1880     plot->setWindowTitle(label);
1881     plot->setName(label);
1882 
1883     customPlot3D(plot);
1884     plot->update();
1885     initPlot3D(plot);
1886 
1887     emit modified();
1888     QApplication::restoreOverrideCursor();
1889     return plot;
1890 }
1891 
dataPlot3D(const QString & caption,const QString & formula,double xl,double xr,double yl,double yr,double zl,double zr)1892 Graph3D *ApplicationWindow::dataPlot3D(const QString &caption, const QString &formula, double xl,
1893                                        double xr, double yl, double yr, double zl, double zr)
1894 {
1895     int pos = formula.indexOf("_", 0);
1896     QString wCaption = formula.left(pos);
1897 
1898     Table *w = table(wCaption);
1899     if (!w)
1900         return 0;
1901 
1902     int posX = formula.indexOf("(", pos);
1903     QString xCol = formula.mid(pos + 1, posX - pos - 1);
1904 
1905     pos = formula.indexOf(",", posX);
1906     posX = formula.indexOf("(", pos);
1907     QString yCol = formula.mid(pos + 1, posX - pos - 1);
1908 
1909     Graph3D *plot = new Graph3D("", &d_workspace, 0);
1910     plot->setAttribute(Qt::WA_DeleteOnClose);
1911     plot->addData(w, xCol, yCol, xl, xr, yl, yr, zl, zr);
1912     plot->update();
1913 
1914     QString label = caption;
1915     while (alreadyUsedName(label))
1916         label = generateUniqueName(tr("Graph"));
1917 
1918     plot->setWindowTitle(label);
1919     plot->setName(label);
1920     initPlot3D(plot);
1921 
1922     return plot;
1923 }
1924 
newPlot3D()1925 Graph3D *ApplicationWindow::newPlot3D()
1926 {
1927     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1928 
1929     QString label = generateUniqueName(tr("Graph"));
1930 
1931     Graph3D *plot = new Graph3D("", &d_workspace, 0);
1932     plot->setAttribute(Qt::WA_DeleteOnClose);
1933     plot->resize(500, 400);
1934     plot->setWindowTitle(label);
1935     plot->setName(label);
1936 
1937     customPlot3D(plot);
1938     initPlot3D(plot);
1939 
1940     emit modified();
1941     QApplication::restoreOverrideCursor();
1942     return plot;
1943 }
1944 
dataPlotXYZ(Table * table,const QString & zColName,int type)1945 Graph3D *ApplicationWindow::dataPlotXYZ(Table *table, const QString &zColName, int type)
1946 {
1947     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1948 
1949     QString label = generateUniqueName(tr("Graph"));
1950     int zCol = table->colIndex(zColName);
1951     int yCol = table->colY(zCol);
1952     int xCol = table->colX(zCol);
1953 
1954     Graph3D *plot = new Graph3D("", &d_workspace, 0);
1955     plot->setAttribute(Qt::WA_DeleteOnClose);
1956     plot->addData(table, xCol, yCol, zCol, type);
1957     plot->resize(500, 400);
1958     plot->setWindowTitle(label);
1959     plot->setName(label);
1960 
1961     customPlot3D(plot);
1962     plot->update();
1963     initPlot3D(plot);
1964 
1965     emit modified();
1966     QApplication::restoreOverrideCursor();
1967     return plot;
1968 }
1969 
dataPlotXYZ(const QString & caption,const QString & formula,double xl,double xr,double yl,double yr,double zl,double zr)1970 Graph3D *ApplicationWindow::dataPlotXYZ(const QString &caption, const QString &formula, double xl,
1971                                         double xr, double yl, double yr, double zl, double zr)
1972 {
1973     int pos = formula.indexOf("_", 0);
1974     QString wCaption = formula.left(pos);
1975 
1976     Table *w = table(wCaption);
1977     if (!w)
1978         return 0;
1979 
1980     int posX = formula.indexOf("(X)", pos);
1981     QString xColName = formula.mid(pos + 1, posX - pos - 1);
1982 
1983     pos = formula.indexOf(",", posX);
1984 
1985     posX = formula.indexOf("(Y)", pos);
1986     QString yColName = formula.mid(pos + 1, posX - pos - 1);
1987 
1988     pos = formula.indexOf(",", posX);
1989     posX = formula.indexOf("(Z)", pos);
1990     QString zColName = formula.mid(pos + 1, posX - pos - 1);
1991 
1992     int xCol = w->colIndex(xColName);
1993     int yCol = w->colIndex(yColName);
1994     int zCol = w->colIndex(zColName);
1995 
1996     Graph3D *plot = new Graph3D("", &d_workspace, 0);
1997     plot->setAttribute(Qt::WA_DeleteOnClose);
1998     plot->addData(w, xCol, yCol, zCol, xl, xr, yl, yr, zl, zr);
1999     plot->update();
2000 
2001     QString label = caption;
2002     if (alreadyUsedName(label))
2003         label = generateUniqueName(tr("Graph"));
2004 
2005     plot->setWindowTitle(label);
2006     plot->setName(label);
2007     initPlot3D(plot);
2008     return plot;
2009 }
2010 
customPlot3D(Graph3D * plot)2011 void ApplicationWindow::customPlot3D(Graph3D *plot)
2012 {
2013     plot->setDataColors(QColor(COLORVALUE(plot3DColors[4])), QColor(COLORVALUE(plot3DColors[0])));
2014     plot->updateColors(QColor(COLORVALUE(plot3DColors[2])), QColor(COLORVALUE(plot3DColors[6])),
2015                        QColor(COLORVALUE(plot3DColors[5])), QColor(COLORVALUE(plot3DColors[1])),
2016                        QColor(COLORVALUE(plot3DColors[7])), QColor(COLORVALUE(plot3DColors[3])));
2017 
2018     plot->setResolution(plot3DResolution);
2019     plot->showColorLegend(showPlot3DLegend);
2020     plot->setSmoothMesh(smooth3DMesh);
2021     plot->setOrtho(orthogonal3DPlots);
2022     if (showPlot3DProjection)
2023         plot->setFloorData();
2024 
2025     plot->setNumbersFont(plot3DNumbersFont);
2026     plot->setXAxisLabelFont(plot3DAxesFont);
2027     plot->setYAxisLabelFont(plot3DAxesFont);
2028     plot->setZAxisLabelFont(plot3DAxesFont);
2029     plot->setTitleFont(plot3DTitleFont);
2030 }
2031 
initPlot3D(Graph3D * plot)2032 void ApplicationWindow::initPlot3D(Graph3D *plot)
2033 {
2034     d_workspace.addSubWindow(plot);
2035     current_folder->addWindow(plot);
2036     plot->setFolder(current_folder);
2037     connectSurfacePlot(plot);
2038 
2039     plot->setWindowIcon(QPixmap(":/trajectory.xpm"));
2040     plot->show();
2041     plot->setFocus();
2042 
2043     addListViewItem(plot);
2044 
2045     if (!graph_3D_tools->isEnabled())
2046         graph_3D_tools->setEnabled(true);
2047 
2048     customMenu(plot);
2049     customToolBars(plot);
2050 }
2051 
importImage()2052 Matrix *ApplicationWindow::importImage()
2053 {
2054     QList<QByteArray> list = QImageReader::supportedImageFormats();
2055     QString filter = tr("Images") + " (", aux1, aux2;
2056     for (int i = 0; i < (int)list.count(); i++) {
2057         aux1 = " *." + list[i] + " ";
2058         aux2 += " *." + list[i] + ";;";
2059         filter += aux1;
2060     }
2061     filter += ");;" + aux2;
2062 
2063     QString fn =
2064             QFileDialog::getOpenFileName(this, tr("Import image from file"), imagesDirPath, filter);
2065     if (!fn.isEmpty()) {
2066         QFileInfo fi(fn);
2067         imagesDirPath = fi.absolutePath();
2068         return importImage(fn);
2069     } else
2070         return 0;
2071 }
2072 
loadImage()2073 void ApplicationWindow::loadImage()
2074 {
2075     QList<QByteArray> list = QImageReader::supportedImageFormats();
2076     QString filter = tr("Images") + " (", aux1, aux2;
2077     for (int i = 0; i < (int)list.count(); i++) {
2078         aux1 = " *." + list[i] + " ";
2079         aux2 += " *." + list[i] + ";;";
2080         filter += aux1;
2081     }
2082     filter += ");;" + aux2;
2083 
2084     QString fn =
2085             QFileDialog::getOpenFileName(this, tr("Load image from file"), imagesDirPath, filter);
2086     if (!fn.isEmpty()) {
2087         loadImage(fn);
2088         QFileInfo fi(fn);
2089         imagesDirPath = fi.absolutePath();
2090     }
2091 }
2092 
loadImage(const QString & fn)2093 void ApplicationWindow::loadImage(const QString &fn)
2094 {
2095     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2096 
2097     MultiLayer *plot = multilayerPlot(generateUniqueName(tr("Graph")));
2098     plot->setWindowLabel(fn);
2099     plot->setCaptionPolicy(MyWidget::Both);
2100     setListViewLabel(plot->name(), fn);
2101 
2102     plot->showNormal();
2103     Graph *g = plot->addLayer(0, 0, plot->width(), plot->height());
2104 
2105     g->setTitle("");
2106     QVector<bool> axesOn(4);
2107     for (int j = 0; j < 4; j++)
2108         axesOn[j] = false;
2109     g->enableAxes(axesOn);
2110     g->removeLegend();
2111     g->setIgnoreResizeEvents(false);
2112     g->addImage(fn);
2113     QApplication::restoreOverrideCursor();
2114 }
2115 
polishGraph(Graph * g,int style)2116 void ApplicationWindow::polishGraph(Graph *g, int style)
2117 {
2118     if (style == Graph::VerticalBars || style == Graph::HorizontalBars
2119         || style == Graph::Histogram) {
2120         QList<int> ticksList;
2121         int ticksStyle = ScaleDraw::Out;
2122         ticksList << ticksStyle << ticksStyle << ticksStyle << ticksStyle;
2123         g->setMajorTicksType(ticksList);
2124         g->setMinorTicksType(ticksList);
2125     }
2126     if (style == Graph::HorizontalBars) {
2127         g->setAxisTitle(0, tr("Y Axis Title"));
2128         g->setAxisTitle(1, tr("X Axis Title"));
2129     }
2130 }
2131 
multilayerPlot(const QString & caption)2132 MultiLayer *ApplicationWindow::multilayerPlot(const QString &caption)
2133 {
2134     MultiLayer *ml = new MultiLayer("", &d_workspace, 0);
2135     ml->setAttribute(Qt::WA_DeleteOnClose);
2136     QString label = caption;
2137     initMultilayerPlot(ml, label.replace(QRegExp("_"), "-"));
2138     return ml;
2139 }
2140 
newGraph(const QString & caption)2141 MultiLayer *ApplicationWindow::newGraph(const QString &caption)
2142 {
2143     MultiLayer *ml = multilayerPlot(generateUniqueName(caption));
2144     if (ml) {
2145         Graph *g = ml->addLayer();
2146         setPreferences(g);
2147         g->newLegend();
2148         g->setAutoscaleFonts(false);
2149         g->setIgnoreResizeEvents(false);
2150         ml->arrangeLayers(false, false);
2151         g->setAutoscaleFonts(autoScaleFonts); // restore user defined fonts behaviour
2152         g->setIgnoreResizeEvents(!autoResizeLayers);
2153         customMenu(ml);
2154     }
2155     return ml;
2156 }
2157 
multilayerPlot(Table * w,const QStringList & colList,int style,int startRow,int endRow)2158 MultiLayer *ApplicationWindow::multilayerPlot(Table *w, const QStringList &colList, int style,
2159                                               int startRow, int endRow)
2160 { // used when plotting selected columns
2161     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2162 
2163     MultiLayer *g = new MultiLayer("", &d_workspace, 0);
2164     g->setAttribute(Qt::WA_DeleteOnClose);
2165 
2166     initMultilayerPlot(g, generateUniqueName(tr("Graph")));
2167 
2168     Graph *ag = g->addLayer();
2169     if (!ag)
2170         return 0;
2171 
2172     setPreferences(ag);
2173     ag->insertCurvesList(w, colList, style, defaultCurveLineWidth, defaultSymbolSize, startRow,
2174                          endRow);
2175 
2176     polishGraph(ag, style);
2177     ag->newLegend();
2178     g->arrangeLayers(false, false);
2179     customMenu(g);
2180 
2181     emit modified();
2182     QApplication::restoreOverrideCursor();
2183     return g;
2184 }
2185 
multilayerPlot(int c,int r,int style)2186 MultiLayer *ApplicationWindow::multilayerPlot(int c, int r, int style)
2187 { // used when plotting from the panel menu
2188     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Table"))
2189         return 0;
2190 
2191     Table *w = (Table *)d_workspace.activeSubWindow();
2192     if (!validFor2DPlot(w, style))
2193         return 0;
2194 
2195     QStringList list;
2196     switch (style) {
2197     case Graph::Histogram:
2198     case Graph::Pie:
2199     case Graph::Box:
2200         list = w->selectedColumns();
2201         break;
2202     default:
2203         list = w->selectedYColumns();
2204         break;
2205     }
2206 
2207     int curves = (int)list.count();
2208     if (r < 0)
2209         r = curves;
2210 
2211     MultiLayer *g = new MultiLayer("", &d_workspace, 0);
2212     g->setAttribute(Qt::WA_DeleteOnClose);
2213 
2214     initMultilayerPlot(g, generateUniqueName(tr("Graph")));
2215 
2216     int layers = c * r;
2217     if (curves < layers) {
2218         for (int i = 0; i < curves; i++) {
2219             Graph *ag = g->addLayer();
2220             if (ag) {
2221                 setPreferences(ag);
2222                 ag->insertCurvesList(w, QStringList(list[i]), style, defaultCurveLineWidth,
2223                                      defaultSymbolSize);
2224                 ag->newLegend();
2225                 ag->setAutoscaleFonts(false); // in order to avoid to small fonts
2226                 ag->setIgnoreResizeEvents(false);
2227                 polishGraph(ag, style);
2228             }
2229         }
2230     } else {
2231         for (int i = 0; i < layers; i++) {
2232             Graph *ag = g->addLayer();
2233             if (ag) {
2234                 QStringList lst;
2235                 lst << list[i];
2236                 setPreferences(ag);
2237                 ag->insertCurvesList(w, lst, style, defaultCurveLineWidth, defaultSymbolSize);
2238                 ag->newLegend();
2239                 ag->setAutoscaleFonts(false); // in order to avoid to small fonts
2240                 ag->setIgnoreResizeEvents(false);
2241                 polishGraph(ag, style);
2242             }
2243         }
2244     }
2245     g->setRows(r);
2246     g->setCols(c);
2247     g->arrangeLayers(false, false);
2248     QWidgetList lst = g->graphPtrs();
2249     foreach (QWidget *widget, lst) {
2250         Graph *ag = (Graph *)widget;
2251         ag->setAutoscaleFonts(autoScaleFonts); // restore user defined fonts behaviour
2252         ag->setIgnoreResizeEvents(!autoResizeLayers);
2253     }
2254     customMenu(g);
2255     emit modified();
2256     return g;
2257 }
2258 
multilayerPlot(const QStringList & colList)2259 MultiLayer *ApplicationWindow::multilayerPlot(const QStringList &colList)
2260 { // used when plotting from wizard
2261     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2262     MultiLayer *g = new MultiLayer("", &d_workspace, 0);
2263     g->setAttribute(Qt::WA_DeleteOnClose);
2264 
2265     initMultilayerPlot(g, generateUniqueName(tr("Graph")));
2266 
2267     Graph *ag = g->addLayer();
2268     setPreferences(ag);
2269     polishGraph(ag, defaultCurveStyle);
2270     int curves = (int)colList.count();
2271     int errorBars = 0;
2272     for (int i = 0; i < curves; i++) {
2273         if (colList[i].contains("(yErr)") || colList[i].contains("(xErr)"))
2274             errorBars++;
2275     }
2276 
2277     for (int i = 0; i < curves; i++) {
2278         QString s = colList[i];
2279         int pos = s.indexOf(":", 0);
2280         QString caption = s.left(pos) + "_";
2281         Table *w = (Table *)table(caption);
2282 
2283         int posX = s.indexOf("(X)", pos);
2284         QString xColName = caption + s.mid(pos + 2, posX - pos - 2);
2285         int xCol = w->colIndex(xColName);
2286 
2287         posX = s.indexOf(",", posX);
2288         int posY = s.indexOf("(Y)", posX);
2289         QString yColName = caption + s.mid(posX + 2, posY - posX - 2);
2290 
2291         if (s.contains("(yErr)") || s.contains("(xErr)")) {
2292             posY = s.indexOf(",", posY);
2293             int posErr, errType;
2294             if (s.contains("(yErr)")) {
2295                 errType = QwtErrorPlotCurve::Vertical;
2296                 posErr = s.indexOf("(yErr)", posY);
2297             } else {
2298                 errType = QwtErrorPlotCurve::Horizontal;
2299                 posErr = s.indexOf("(xErr)", posY);
2300             }
2301 
2302             QString errColName = caption + s.mid(posY + 2, posErr - posY - 2);
2303             ag->addErrorBars(xColName, yColName, w, errColName, errType);
2304         } else
2305             ag->insertCurve(w, xCol, yColName, defaultCurveStyle);
2306 
2307         CurveLayout cl = ag->initCurveLayout(defaultCurveStyle, curves - errorBars);
2308         cl.lWidth = defaultCurveLineWidth;
2309         cl.sSize = defaultSymbolSize;
2310         ag->updateCurveLayout(i, &cl);
2311     }
2312     ag->newLegend();
2313     ag->updatePlot();
2314     g->arrangeLayers(true, false);
2315     customMenu(g);
2316     emit modified();
2317     QApplication::restoreOverrideCursor();
2318     return g;
2319 }
2320 
initBareMultilayerPlot(MultiLayer * g,const QString & name)2321 void ApplicationWindow::initBareMultilayerPlot(MultiLayer *g, const QString &name)
2322 { // FIXME: workaround, init without unnecessary g->show()
2323     QString label = name;
2324     while (alreadyUsedName(label))
2325         label = generateUniqueName(tr("Graph"));
2326 
2327     connectMultilayerPlot(g);
2328 
2329     g->setWindowTitle(label);
2330     g->setName(label);
2331     g->setWindowIcon(QPixmap(":/graph.xpm"));
2332     g->setScaleLayersOnPrint(d_scale_plots_on_print);
2333     g->printCropmarks(d_print_cropmarks);
2334 
2335     d_workspace.addSubWindow(g);
2336     current_folder->addWindow(g);
2337     g->setFolder(current_folder);
2338     addListViewItem(g);
2339 }
2340 
initMultilayerPlot(MultiLayer * g,const QString & name)2341 void ApplicationWindow::initMultilayerPlot(MultiLayer *g, const QString &name)
2342 {
2343     initBareMultilayerPlot(g, name);
2344     g->show(); // FIXME: bad idea do it here
2345     g->setFocus();
2346 }
2347 
customizeTables(const QColor & bgColor,const QColor & textColor,const QColor & headerColor,const QFont & textFont,const QFont & headerFont,bool showComments)2348 void ApplicationWindow::customizeTables(const QColor &bgColor, const QColor &textColor,
2349                                         const QColor &headerColor, const QFont &textFont,
2350                                         const QFont &headerFont, bool showComments)
2351 {
2352     tableBkgdColor = bgColor;
2353     tableTextColor = textColor;
2354     tableHeaderColor = headerColor;
2355     tableTextFont = textFont;
2356     tableHeaderFont = headerFont;
2357     d_show_table_comments = showComments;
2358 
2359     QList<MyWidget *> windows = windowsList();
2360     foreach (MyWidget *w, windows) {
2361         if (w->inherits("Table"))
2362             customTable((Table *)w);
2363     }
2364 }
2365 
customTable(Table * w)2366 void ApplicationWindow::customTable(Table *w)
2367 {
2368     QPalette cg;
2369     cg.setColor(QPalette::Base, QColor(tableBkgdColor));
2370     cg.setColor(QPalette::Text, QColor(tableTextColor));
2371     w->setPalette(cg);
2372 
2373     w->setHeaderColor(tableHeaderColor);
2374     w->setTextFont(tableTextFont);
2375     w->setHeaderFont(tableHeaderFont);
2376     w->showComments(d_show_table_comments);
2377 }
2378 
setPreferences(Graph * g)2379 void ApplicationWindow::setPreferences(Graph *g)
2380 {
2381     if (!g->isPiePlot()) {
2382         if (allAxesOn) {
2383             QVector<bool> axesOn(QwtPlot::axisCnt);
2384             axesOn.fill(true);
2385             g->enableAxes(axesOn);
2386             g->updateSecondaryAxis(QwtPlot::xTop);
2387             g->updateSecondaryAxis(QwtPlot::yRight);
2388         }
2389 
2390         QList<int> ticksList;
2391         ticksList << majTicksStyle << majTicksStyle << majTicksStyle << majTicksStyle;
2392         g->setMajorTicksType(ticksList);
2393         ticksList.clear();
2394         ticksList << minTicksStyle << minTicksStyle << minTicksStyle << minTicksStyle;
2395         g->setMinorTicksType(ticksList);
2396 
2397         g->setTicksLength(minTicksLength, majTicksLength);
2398         g->setAxesLinewidth(axesLineWidth);
2399         g->drawAxesBackbones(drawBackbones);
2400     }
2401 
2402     g->initFonts(plotAxesFont, plotNumbersFont);
2403     g->setTextMarkerDefaults(legendFrameStyle, plotLegendFont, legendTextColor, legendBackground);
2404     g->setArrowDefaults(defaultArrowLineWidth, defaultArrowColor, defaultArrowLineStyle,
2405                         defaultArrowHeadLength, defaultArrowHeadAngle, defaultArrowHeadFill);
2406     g->initTitle(titleOn, plotTitleFont);
2407     g->drawCanvasFrame(canvasFrameOn, canvasFrameWidth);
2408     g->plotWidget()->setMargin(defaultPlotMargin);
2409     g->enableAutoscaling(autoscale2DPlots);
2410     g->setAutoscaleFonts(autoScaleFonts);
2411     g->setIgnoreResizeEvents(!autoResizeLayers);
2412     g->setAntialiasing(antialiasing2DPlots);
2413 }
2414 
newWrksheetPlot(const QString & name,const QString & label,QList<Column * > columns)2415 void ApplicationWindow::newWrksheetPlot(const QString &name, const QString &label,
2416                                         QList<Column *> columns)
2417 {
2418     Table *w = newTable(name, label, columns);
2419     MultiLayer *plot = multilayerPlot(w, QStringList(QString(w->name()) + "_intensity"), 0);
2420     Graph *g = (Graph *)plot->activeGraph();
2421     if (g) {
2422         g->setTitle("");
2423         g->setXAxisTitle(tr("pixels"));
2424         g->setYAxisTitle(tr("pixel intensity (a.u.)"));
2425     }
2426 }
2427 
2428 /*
2429  *used when importing an ASCII file
2430  */
newTable(const QString & fname,const QString & sep,int lines,bool renameCols,bool stripSpaces,bool simplifySpaces,bool convertToNumeric,QLocale numericLocale)2431 Table *ApplicationWindow::newTable(const QString &fname, const QString &sep, int lines,
2432                                    bool renameCols, bool stripSpaces, bool simplifySpaces,
2433                                    bool convertToNumeric, QLocale numericLocale)
2434 {
2435     Table *w = new Table(scriptEnv, fname, sep, lines, renameCols, stripSpaces, simplifySpaces,
2436                          convertToNumeric, numericLocale, fname, &d_workspace);
2437     if (w) {
2438         w->setName(generateUniqueName(tr("Table")));
2439         d_project->addChild(w->d_future_table);
2440     }
2441     return w;
2442 }
2443 
2444 /*
2445  *creates a new empty table
2446  */
newTable()2447 Table *ApplicationWindow::newTable()
2448 {
2449     Table *w = new Table(scriptEnv, 30, 2, "", &d_workspace, 0);
2450     w->setName(generateUniqueName(tr("Table")));
2451     d_project->addChild(w->d_future_table);
2452     return w;
2453 }
2454 
2455 /*
2456  *used when opening a project file
2457  */
newTable(const QString & caption,int r,int c)2458 Table *ApplicationWindow::newTable(const QString &caption, int r, int c)
2459 {
2460     Table *w = new Table(scriptEnv, r, c, "", &d_workspace, 0);
2461     w->setName(caption);
2462     d_project->addChild(w->d_future_table);
2463     if (w->name() != caption) // the table was renamed
2464     {
2465         renamedTables << caption << w->name();
2466 
2467         QMessageBox::warning(this, tr("Renamed Window"),
2468                              tr("The table '%1' already exists. It has been renamed '%2'.")
2469                                      .arg(caption)
2470                                      .arg(w->name()));
2471     }
2472     return w;
2473 }
2474 
newTable(int r,int c,const QString & name,const QString & legend)2475 Table *ApplicationWindow::newTable(int r, int c, const QString &name, const QString &legend)
2476 {
2477     Table *w = new Table(scriptEnv, r, c, legend, &d_workspace, 0);
2478     w->setName(name);
2479     d_project->addChild(w->d_future_table);
2480     return w;
2481 }
2482 
newTable(const QString & name,const QString & legend,QList<Column * > columns)2483 Table *ApplicationWindow::newTable(const QString &name, const QString &legend,
2484                                    QList<Column *> columns)
2485 {
2486     Table *w = new Table(scriptEnv, 0, 0, legend, &d_workspace, 0);
2487     w->d_future_table->appendColumns(columns);
2488     w->setName(name);
2489     d_project->addChild(w->d_future_table);
2490     return w;
2491 }
2492 
newHiddenTable(const QString & name,const QString & label,QList<Column * > columns)2493 Table *ApplicationWindow::newHiddenTable(const QString &name, const QString &label,
2494                                          QList<Column *> columns)
2495 {
2496     auto w = newTable(name, label, columns);
2497     hideWindow(w);
2498     return w;
2499 }
2500 
initTable(Table * w)2501 void ApplicationWindow::initTable(Table *w)
2502 {
2503     d_workspace.addSubWindow(w);
2504     w->setWindowIcon(QPixmap(":/worksheet.xpm"));
2505     current_folder->addWindow(w);
2506     w->setFolder(current_folder);
2507     addListViewItem(w);
2508     w->showNormal();
2509 
2510     connectTable(w);
2511     customTable(w);
2512 
2513     w->d_future_table->setPlotMenu(plot2D);
2514 
2515     emit modified();
2516 }
2517 
2518 /*
2519  * !creates a new table with type statistics on target columns/rows of table base
2520  */
newTableStatistics(Table * base,int type,QList<int> target,const QString & caption)2521 TableStatistics *ApplicationWindow::newTableStatistics(Table *base, int type, QList<int> target,
2522                                                        const QString &caption)
2523 {
2524     TableStatistics *s =
2525             new TableStatistics(scriptEnv, &d_workspace, base, (TableStatistics::Type)type, target);
2526     if (!caption.isEmpty())
2527         s->setName(caption);
2528 
2529     d_project->addChild(s->d_future_table);
2530     connect(base, SIGNAL(modifiedData(Table *, const QString &)), s,
2531             SLOT(update(Table *, const QString &)));
2532     connect(base, SIGNAL(changedColHeader(const QString &, const QString &)), s,
2533             SLOT(renameCol(const QString &, const QString &)));
2534     connect(base, SIGNAL(removedCol(const QString &)), s, SLOT(removeCol(const QString &)));
2535     connect(base->d_future_table, SIGNAL(aspectAboutToBeRemoved(const AbstractAspect *)), this,
2536             SLOT(removeDependentTableStatistics(const AbstractAspect *)));
2537     return s;
2538 }
2539 
removeDependentTableStatistics(const AbstractAspect * aspect)2540 void ApplicationWindow::removeDependentTableStatistics(const AbstractAspect *aspect)
2541 {
2542     ::future::Table *future_table =
2543             qobject_cast<::future::Table *>(const_cast<AbstractAspect *>(aspect));
2544     if (!future_table)
2545         return;
2546     QList<MyWidget *> windows = windowsList();
2547     foreach (MyWidget *win, windows) {
2548         TableStatistics *table_stat = qobject_cast<TableStatistics *>(win);
2549         if (!table_stat)
2550             continue;
2551         Table *table = qobject_cast<Table *>(future_table->view());
2552         if (!table)
2553             continue;
2554         if (table_stat->base() == table)
2555             d_project->removeChild(table_stat->d_future_table);
2556     }
2557 }
2558 
2559 /*
2560  *creates a new empty note window
2561  */
newNote(const QString & caption)2562 Note *ApplicationWindow::newNote(const QString &caption)
2563 {
2564     Note *m = new Note(scriptEnv, "", &d_workspace);
2565     if (caption.isEmpty())
2566         initNote(m, generateUniqueName(tr("Notes")));
2567     else
2568         initNote(m, caption);
2569     m->showNormal();
2570     return m;
2571 }
2572 
initNote(Note * m,const QString & caption)2573 void ApplicationWindow::initNote(Note *m, const QString &caption)
2574 {
2575     QString name = caption;
2576     while (name.isEmpty() || alreadyUsedName(name))
2577         name = generateUniqueName(tr("Notes"));
2578 
2579     d_workspace.addSubWindow(m);
2580     m->setWindowTitle(name);
2581     m->setName(name);
2582     m->setWindowIcon(QPixmap(":/note.xpm"));
2583     m->askOnCloseEvent(confirmCloseNotes);
2584     m->setFolder(current_folder);
2585 
2586     current_folder->addWindow(m);
2587     addListViewItem(m);
2588 
2589     connect(m, SIGNAL(modifiedWindow(MyWidget *)), this, SLOT(modifiedProject(MyWidget *)));
2590     connect(m, SIGNAL(closedWindow(MyWidget *)), this, SLOT(closeWindow(MyWidget *)));
2591     connect(m, SIGNAL(hiddenWindow(MyWidget *)), this, SLOT(hideWindow(MyWidget *)));
2592     connect(m, SIGNAL(statusChanged(MyWidget *)), this, SLOT(updateWindowStatus(MyWidget *)));
2593     connect(m, SIGNAL(showTitleBarMenu()), this, SLOT(showWindowTitleBarMenu()));
2594 
2595     emit modified();
2596 }
2597 
newMatrix(int rows,int columns)2598 Matrix *ApplicationWindow::newMatrix(int rows, int columns)
2599 {
2600     Matrix *m = new Matrix(scriptEnv, rows, columns, "", 0, 0);
2601     QString caption = generateUniqueName(tr("Matrix"));
2602     while (alreadyUsedName(caption)) {
2603         caption = generateUniqueName(tr("Matrix"));
2604     }
2605     m->setName(caption);
2606     d_project->addChild(m->d_future_matrix);
2607     return m;
2608 }
2609 
newMatrix(const QString & caption,int r,int c)2610 Matrix *ApplicationWindow::newMatrix(const QString &caption, int r, int c)
2611 {
2612     Matrix *w = new Matrix(scriptEnv, r, c, "", 0, 0);
2613     QString name = caption;
2614     while (alreadyUsedName(name)) {
2615         name = generateUniqueName(caption);
2616     }
2617     w->setName(name);
2618     d_project->addChild(w->d_future_matrix);
2619     if (w->name() != caption) // the matrix was renamed
2620         renamedTables << caption << w->name();
2621 
2622     return w;
2623 }
2624 
matrixDeterminant()2625 void ApplicationWindow::matrixDeterminant()
2626 {
2627     Matrix *m = (Matrix *)d_workspace.activeSubWindow();
2628     if (!m)
2629         return;
2630 
2631     QDateTime dt = QDateTime::currentDateTime();
2632     QString info = QLocale().toString(dt);
2633     info += "\n" + tr("Determinant of ") + QString(m->name()) + ":\t";
2634     info += "det = " + QString::number(m->determinant()) + "\n";
2635     info += "-------------------------------------------------------------\n";
2636 
2637     logInfo += info;
2638 
2639     showResults(true);
2640 }
2641 
invertMatrix()2642 void ApplicationWindow::invertMatrix()
2643 {
2644     Matrix *m = (Matrix *)d_workspace.activeSubWindow();
2645     if (!m)
2646         return;
2647 
2648     m->invert();
2649 }
2650 
convertMatrixToTable()2651 Table *ApplicationWindow::convertMatrixToTable()
2652 {
2653     Matrix *m = (Matrix *)d_workspace.activeSubWindow();
2654     if (!m)
2655         return 0;
2656 
2657     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2658 
2659     int rows = m->numRows();
2660     int cols = m->numCols();
2661 
2662     Table *w = new Table(scriptEnv, rows, cols, "", &d_workspace, 0);
2663     for (int i = 0; i < rows; i++) {
2664         for (int j = 0; j < cols; j++)
2665             w->setCell(i, j, m->cell(i, j));
2666     }
2667 
2668     w->setName(generateUniqueName(tr("Table")));
2669     d_project->addChild(w->d_future_table);
2670     w->setWindowLabel(m->windowLabel());
2671     w->setCaptionPolicy(m->captionPolicy());
2672     w->resize(m->size());
2673     w->showNormal();
2674 
2675     QApplication::restoreOverrideCursor();
2676 
2677     return w;
2678 }
2679 
initMatrix(Matrix * m)2680 void ApplicationWindow::initMatrix(Matrix *m)
2681 {
2682     d_workspace.addSubWindow(m);
2683     m->setWindowIcon(QPixmap(":/matrix.xpm"));
2684     m->askOnCloseEvent(confirmCloseMatrix);
2685     m->setNumericFormat(d_default_numeric_format, d_decimal_digits);
2686     m->setFolder(current_folder);
2687 
2688     current_folder->addWindow(m);
2689     m->setFolder(current_folder);
2690     addListViewItem(m);
2691     m->showNormal();
2692 
2693     connect(m, SIGNAL(showTitleBarMenu()), this, SLOT(showWindowTitleBarMenu()));
2694     connect(m, SIGNAL(modifiedWindow(MyWidget *)), this, SLOT(modifiedProject(MyWidget *)));
2695     connect(m, SIGNAL(modifiedWindow(MyWidget *)), this, SLOT(updateMatrixPlots(MyWidget *)));
2696     connect(m, SIGNAL(hiddenWindow(MyWidget *)), this, SLOT(hideWindow(MyWidget *)));
2697     connect(m, SIGNAL(statusChanged(MyWidget *)), this, SLOT(updateWindowStatus(MyWidget *)));
2698     connect(m, SIGNAL(showContextMenu()), this, SLOT(showWindowContextMenu()));
2699     emit modified();
2700 }
2701 
convertTableToMatrix()2702 Matrix *ApplicationWindow::convertTableToMatrix()
2703 {
2704     Table *m = (Table *)d_workspace.activeSubWindow();
2705     if (!m)
2706         return 0;
2707 
2708     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2709 
2710     int rows = m->numRows();
2711     int cols = m->numCols();
2712 
2713     Matrix *w = new Matrix(scriptEnv, rows, cols, "", 0, 0);
2714     for (int i = 0; i < rows; i++) {
2715         for (int j = 0; j < cols; j++)
2716             w->setText(i, j, m->text(i, j));
2717     }
2718 
2719     QString caption = generateUniqueName(m->name());
2720     w->setName(caption);
2721     d_project->addChild(w->d_future_matrix);
2722 
2723     w->setCaptionPolicy(m->captionPolicy());
2724     w->resize(m->size());
2725     w->showNormal();
2726 
2727     QApplication::restoreOverrideCursor();
2728     return w;
2729 }
2730 
window(const QString & name)2731 MyWidget *ApplicationWindow::window(const QString &name)
2732 {
2733     MyWidget *widget = 0;
2734     QList<MyWidget *> windows = windowsList();
2735     for (int i = 0; i < windows.count(); i++) {
2736         widget = windows.at(i);
2737         if (widget && widget->name() == name)
2738             return widget;
2739     }
2740     return widget;
2741 }
2742 
table(const QString & name)2743 Table *ApplicationWindow::table(const QString &name)
2744 {
2745     int pos = name.indexOf("_", 0);
2746     QString caption = name.left(pos);
2747 
2748     QList<MyWidget *> lst = windowsList();
2749     foreach (MyWidget *w, lst) {
2750         if (w->inherits("Table") && static_cast<Table *>(w)->name() == caption) {
2751             return (Table *)w;
2752         }
2753     }
2754     return 0;
2755 }
2756 
matrix(const QString & name)2757 Matrix *ApplicationWindow::matrix(const QString &name)
2758 {
2759     QString caption = name;
2760     if (!renamedTables.isEmpty() && renamedTables.contains(caption)) {
2761         int index = renamedTables.indexOf(caption);
2762         caption = renamedTables[index + 1];
2763     }
2764 
2765     QList<MyWidget *> lst = windowsList();
2766     foreach (MyWidget *w, lst) {
2767         if (w->inherits("Matrix") && static_cast<Matrix *>(w)->name() == caption) {
2768             return (Matrix *)w;
2769         }
2770     }
2771     return 0;
2772 }
2773 
windowActivated(QMdiSubWindow * w)2774 void ApplicationWindow::windowActivated(QMdiSubWindow *w)
2775 {
2776     if (!w || !w->inherits("MyWidget"))
2777         return;
2778 
2779     customToolBars((MyWidget *)w);
2780     customMenu((MyWidget *)w);
2781 
2782     Folder *f = ((MyWidget *)w)->folder();
2783     if (f)
2784         f->setActiveWindow((MyWidget *)w);
2785 }
2786 
addErrorBars()2787 void ApplicationWindow::addErrorBars()
2788 {
2789     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
2790         return;
2791 
2792     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
2793     if (plot->isEmpty()) {
2794         QMessageBox::warning(this, tr("Warning"),
2795                              tr("<h4>There are no plot layers available in this window.</h4>"
2796                                 "<p><h4>Please add a layer and try again!</h4>"));
2797         return;
2798     }
2799 
2800     Graph *g = (Graph *)plot->activeGraph();
2801     if (!g)
2802         return;
2803 
2804     if (!g->curves()) {
2805         QMessageBox::warning(this, tr("Warning"),
2806                              tr("There are no curves available on this plot!"));
2807         return;
2808     }
2809 
2810     if (g->isPiePlot()) {
2811         QMessageBox::warning(this, tr("Warning"),
2812                              tr("This functionality is not available for pie plots!"));
2813         return;
2814     }
2815 
2816     ErrDialog *ed = new ErrDialog(this);
2817     ed->setAttribute(Qt::WA_DeleteOnClose);
2818     connect(ed, SIGNAL(options(const QString &, int, const QString &, int)), this,
2819             SLOT(defineErrorBars(const QString &, int, const QString &, int)));
2820     connect(ed, SIGNAL(options(const QString &, const QString &, int)), this,
2821             SLOT(defineErrorBars(const QString &, const QString &, int)));
2822 
2823     ed->setCurveNames(g->analysableCurvesList());
2824     ed->setSrcTables(tableList());
2825     ed->exec();
2826 }
2827 
defineErrorBars(const QString & name,int type,const QString & percent,int direction)2828 void ApplicationWindow::defineErrorBars(const QString &name, int type, const QString &percent,
2829                                         int direction)
2830 {
2831     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
2832         return;
2833 
2834     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
2835     if (!g)
2836         return;
2837 
2838     Table *w = table(name);
2839     if (!w) { // user defined function
2840         QMessageBox::critical(
2841                 this, tr("Error bars error"),
2842                 tr("This feature is not available for user defined function curves!"));
2843         return;
2844     }
2845 
2846     DataCurve *master_curve = (DataCurve *)g->curve(name);
2847     QString xColName = master_curve->xColumnName();
2848     if (xColName.isEmpty())
2849         return;
2850 
2851     Column *errors = new Column("1", SciDAVis::ColumnMode::Numeric);
2852     Column *data;
2853     if (direction == QwtErrorPlotCurve::Horizontal) {
2854         errors->setPlotDesignation(SciDAVis::xErr);
2855         data = w->d_future_table->column(xColName);
2856     } else {
2857         errors->setPlotDesignation(SciDAVis::yErr);
2858         data = w->d_future_table->column(name);
2859     }
2860     if (!data)
2861         return;
2862 
2863     int rows = data->rowCount();
2864     if (type == 0) {
2865         double fraction = percent.toDouble() / 100.0;
2866         for (int i = 0; i < rows; i++)
2867             errors->setValueAt(i, data->valueAt(i) * fraction);
2868     } else if (type == 1) {
2869         double average = 0.0;
2870         double dev = 0.0;
2871         for (int i = 0; i < rows; i++)
2872             average += data->valueAt(i);
2873         average /= rows;
2874         for (int i = 0; i < rows; i++)
2875             dev += pow(data->valueAt(i) - average, 2);
2876         dev = sqrt(dev / rows);
2877         for (int i = 0; i < rows; i++)
2878             errors->setValueAt(i, dev);
2879     }
2880     w->d_future_table->addChild(errors);
2881     g->addErrorBars(xColName, name, w, errors->name(), direction);
2882 }
2883 
defineErrorBars(const QString & curveName,const QString & errColumnName,int direction)2884 void ApplicationWindow::defineErrorBars(const QString &curveName, const QString &errColumnName,
2885                                         int direction)
2886 {
2887     Table *w = table(curveName);
2888     if (!w) { // user defined function --> no worksheet available
2889         QMessageBox::critical(
2890                 this, tr("Error"),
2891                 tr("This feature is not available for user defined function curves!"));
2892         return;
2893     }
2894 
2895     Table *errTable = table(errColumnName);
2896     if (w->numRows() != errTable->numRows()) {
2897         QMessageBox::critical(this, tr("Error"),
2898                               tr("The selected columns have different numbers of rows!"));
2899 
2900         addErrorBars();
2901         return;
2902     }
2903 
2904     int errCol = errTable->colIndex(errColumnName);
2905     if (errTable->d_future_table->column(errCol)->dataType() != SciDAVis::TypeDouble) {
2906         QMessageBox::critical(this, tr("Error"),
2907                               tr("You can only define error bars for numeric columns."));
2908         addErrorBars();
2909         return;
2910     }
2911 
2912     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
2913         return;
2914 
2915     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
2916     if (!g)
2917         return;
2918 
2919     g->addErrorBars(curveName, errTable, errColumnName, direction);
2920     emit modified();
2921 }
2922 
removeCurves(const QString & name)2923 void ApplicationWindow::removeCurves(const QString &name)
2924 {
2925     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2926 
2927     QList<MyWidget *> windows = windowsList();
2928     foreach (MyWidget *w, windows) {
2929         if (w->inherits("MultiLayer")) {
2930             QWidgetList lst = ((MultiLayer *)w)->graphPtrs();
2931             foreach (QWidget *widget, lst)
2932                 ((Graph *)widget)->removeCurves(name);
2933         } else if (w->inherits("Graph3D")) {
2934             if ((((Graph3D *)w)->formula()).contains(name))
2935                 ((Graph3D *)w)->clearData();
2936         }
2937     }
2938     QApplication::restoreOverrideCursor();
2939 }
2940 
updateCurves(Table * t,const QString & name)2941 void ApplicationWindow::updateCurves(Table *t, const QString &name)
2942 {
2943     QList<MyWidget *> windows = windowsList();
2944     foreach (MyWidget *w, windows) {
2945         if (w->inherits("MultiLayer")) {
2946             QWidgetList graphsList = ((MultiLayer *)w)->graphPtrs();
2947             for (int k = 0; k < (int)graphsList.count(); k++) {
2948                 Graph *g = (Graph *)graphsList.at(k);
2949                 if (g)
2950                     g->updateCurvesData(t, name);
2951             }
2952         } else if (w->inherits("Graph3D")) {
2953             Graph3D *g = (Graph3D *)w;
2954             if ((g->formula()).contains(name))
2955                 g->updateData(t);
2956         }
2957     }
2958 }
2959 
showPreferencesDialog()2960 void ApplicationWindow::showPreferencesDialog()
2961 {
2962     ConfigDialog *cd = new ConfigDialog(this);
2963     cd->setAttribute(Qt::WA_DeleteOnClose);
2964     cd->setColumnSeparator(columnSeparator);
2965     cd->exec();
2966 }
2967 
setSaveSettings(bool autoSaving,int min)2968 void ApplicationWindow::setSaveSettings(bool autoSaving, int min)
2969 {
2970     if (autoSave == autoSaving && autoSaveTime == min)
2971         return;
2972 
2973     autoSave = autoSaving;
2974     autoSaveTime = min;
2975 
2976     killTimer(savingTimerId);
2977 
2978     if (autoSave)
2979         savingTimerId = startTimer(autoSaveTime * 60000);
2980     else
2981         savingTimerId = 0;
2982 }
2983 
changeAppStyle(const QString & s)2984 void ApplicationWindow::changeAppStyle(const QString &s)
2985 {
2986     // style keys are case insensitive
2987     if (appStyle.toLower() == s.toLower())
2988         return;
2989 
2990     qApp->setStyle(s);
2991     appStyle = qApp->style()->objectName();
2992 
2993     QPalette pal = qApp->palette();
2994     pal.setColor(QPalette::Active, QPalette::Base, QColor(panelsColor));
2995     qApp->setPalette(pal);
2996 }
2997 
changeAppFont(const QFont & f)2998 void ApplicationWindow::changeAppFont(const QFont &f)
2999 {
3000     if (appFont == f)
3001         return;
3002 
3003     appFont = f;
3004     updateAppFonts();
3005 }
3006 
updateAppFonts()3007 void ApplicationWindow::updateAppFonts()
3008 {
3009     qApp->setFont(appFont);
3010     this->setFont(appFont);
3011     scriptingMenu->setFont(appFont);
3012     windowsMenu->setFont(appFont);
3013     view->setFont(appFont);
3014     graph->setFont(appFont);
3015     file->setFont(appFont);
3016     format->setFont(appFont);
3017     calcul->setFont(appFont);
3018     edit->setFont(appFont);
3019     dataMenu->setFont(appFont);
3020     recent->setFont(appFont);
3021     help->setFont(appFont);
3022     type->setFont(appFont);
3023     plot2D->setFont(appFont);
3024     plot3D->setFont(appFont);
3025     plot3DMenu->setFont(appFont);
3026     matrixMenu->setFont(appFont);
3027     specialPlot->setFont(appFont);
3028     panels->setFont(appFont);
3029     stat->setFont(appFont);
3030     smooth->setFont(appFont);
3031     filter->setFont(appFont);
3032     decay->setFont(appFont);
3033     plotDataMenu->setFont(appFont);
3034     tableMenu->setFont(appFont);
3035     exportPlot->setFont(appFont);
3036     translateMenu->setFont(appFont);
3037     multiPeakMenu->setFont(appFont);
3038 }
3039 
updateConfirmOptions(bool askTables,bool askMatrices,bool askPlots2D,bool askPlots3D,bool askNotes)3040 void ApplicationWindow::updateConfirmOptions(bool askTables, bool askMatrices, bool askPlots2D,
3041                                              bool askPlots3D, bool askNotes)
3042 {
3043     QList<MyWidget *> windows = windowsList();
3044     if (confirmCloseTable != askTables) {
3045         confirmCloseTable = askTables;
3046         for (int i = 0; i < int(windows.count()); i++) {
3047             if (windows.at(i)->inherits("Table"))
3048                 ((MyWidget *)windows.at(i))->askOnCloseEvent(confirmCloseTable);
3049         }
3050     }
3051 
3052     if (confirmCloseMatrix != askMatrices) {
3053         confirmCloseMatrix = askMatrices;
3054         for (int i = 0; i < int(windows.count()); i++) {
3055             if (windows.at(i)->inherits("Matrix"))
3056                 ((MyWidget *)windows.at(i))->askOnCloseEvent(confirmCloseMatrix);
3057         }
3058     }
3059 
3060     if (confirmClosePlot2D != askPlots2D) {
3061         confirmClosePlot2D = askPlots2D;
3062         for (int i = 0; i < int(windows.count()); i++) {
3063             if (windows.at(i)->inherits("MultiLayer"))
3064                 ((MyWidget *)windows.at(i))->askOnCloseEvent(confirmClosePlot2D);
3065         }
3066     }
3067 
3068     if (confirmClosePlot3D != askPlots3D) {
3069         confirmClosePlot3D = askPlots3D;
3070         for (int i = 0; i < int(windows.count()); i++) {
3071             if (windows.at(i)->inherits("Graph3D"))
3072                 ((MyWidget *)windows.at(i))->askOnCloseEvent(confirmClosePlot3D);
3073         }
3074     }
3075 
3076     if (confirmCloseNotes != askNotes) {
3077         confirmCloseNotes = askNotes;
3078         for (int i = 0; i < int(windows.count()); i++) {
3079             if (windows.at(i)->inherits("Note"))
3080                 ((MyWidget *)windows.at(i))->askOnCloseEvent(confirmCloseNotes);
3081         }
3082     }
3083 }
3084 
setGraphDefaultSettings(bool autoscale,bool scaleFonts,bool resizeLayers,bool antialiasing)3085 void ApplicationWindow::setGraphDefaultSettings(bool autoscale, bool scaleFonts, bool resizeLayers,
3086                                                 bool antialiasing)
3087 {
3088     if (autoscale2DPlots == autoscale && autoScaleFonts == scaleFonts
3089         && autoResizeLayers != resizeLayers && antialiasing2DPlots == antialiasing)
3090         return;
3091 
3092     autoscale2DPlots = autoscale;
3093     autoScaleFonts = scaleFonts;
3094     autoResizeLayers = !resizeLayers;
3095     antialiasing2DPlots = antialiasing;
3096 
3097     QList<MyWidget *> windows = windowsList();
3098     foreach (MyWidget *w, windows) {
3099         if (w->inherits("MultiLayer")) {
3100             QWidgetList lst = ((MultiLayer *)w)->graphPtrs();
3101             Graph *g;
3102             foreach (QWidget *widget, lst) {
3103                 g = (Graph *)widget;
3104                 g->enableAutoscaling(autoscale2DPlots);
3105                 g->updateScale();
3106                 g->setIgnoreResizeEvents(!autoResizeLayers);
3107                 g->setAutoscaleFonts(autoScaleFonts);
3108                 g->setAntialiasing(antialiasing2DPlots);
3109             }
3110         }
3111     }
3112 }
3113 
setLegendDefaultSettings(int frame,const QFont & font,const QColor & textCol,const QColor & backgroundCol)3114 void ApplicationWindow::setLegendDefaultSettings(int frame, const QFont &font,
3115                                                  const QColor &textCol, const QColor &backgroundCol)
3116 {
3117     if (legendFrameStyle == frame && legendTextColor == textCol && legendBackground == backgroundCol
3118         && plotLegendFont == font)
3119         return;
3120 
3121     legendFrameStyle = frame;
3122     legendTextColor = textCol;
3123     legendBackground = backgroundCol;
3124     plotLegendFont = font;
3125 
3126     QList<MyWidget *> windows = windowsList();
3127     foreach (MyWidget *w, windows) {
3128         if (w->inherits("MultiLayer")) {
3129             QWidgetList graphsList = ((MultiLayer *)w)->graphPtrs();
3130             foreach (QWidget *widget, graphsList)
3131                 ((Graph *)widget)->setTextMarkerDefaults(frame, font, textCol, backgroundCol);
3132         }
3133     }
3134     saveSettings();
3135 }
3136 
setArrowDefaultSettings(const QPen & pen,int headLength,int headAngle,bool fillHead)3137 void ApplicationWindow::setArrowDefaultSettings(const QPen &pen, int headLength, int headAngle,
3138                                                 bool fillHead)
3139 {
3140     if (defaultArrowLineWidth == pen.width() && defaultArrowColor == pen.color()
3141         && defaultArrowLineStyle == pen.style() && defaultArrowHeadLength == headLength
3142         && defaultArrowHeadAngle == headAngle && defaultArrowHeadFill == fillHead)
3143         return;
3144 
3145     defaultArrowLineWidth = pen.width();
3146     defaultArrowColor = pen.color();
3147     defaultArrowLineStyle = pen.style();
3148     defaultArrowHeadLength = headLength;
3149     defaultArrowHeadAngle = headAngle;
3150     defaultArrowHeadFill = fillHead;
3151 
3152     QList<MyWidget *> windows = windowsList();
3153     foreach (MyWidget *w, windows) {
3154         if (w->inherits("MultiLayer")) {
3155             QWidgetList graphsList = ((MultiLayer *)w)->graphPtrs();
3156             foreach (QWidget *widget, graphsList)
3157                 ((Graph *)widget)
3158                         ->setArrowDefaults(defaultArrowLineWidth, defaultArrowColor,
3159 
3160                                            defaultArrowLineStyle, defaultArrowHeadLength,
3161                                            defaultArrowHeadAngle, defaultArrowHeadFill);
3162         }
3163     }
3164     saveSettings();
3165 }
3166 
plotFile(const QString & fn)3167 ApplicationWindow *ApplicationWindow::plotFile(const QString &fn)
3168 {
3169     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
3170     ApplicationWindow *app = new ApplicationWindow();
3171     app->applyUserSettings();
3172     app->showMaximized();
3173 
3174     Table *t = app->newTable(fn, app->columnSeparator, 0, true, app->strip_spaces,
3175                              app->simplify_spaces, app->d_convert_to_numeric,
3176                              app->d_ASCII_import_locale);
3177     t->setCaptionPolicy(MyWidget::Both);
3178     app->multilayerPlot(t, t->YColumns(), Graph::LineSymbols);
3179     QApplication::restoreOverrideCursor();
3180     return 0;
3181 }
3182 
importASCII()3183 void ApplicationWindow::importASCII()
3184 {
3185     ImportASCIIDialog *import_dialog = new ImportASCIIDialog(
3186             d_workspace.currentSubWindow() && d_workspace.currentSubWindow()->inherits("Table"),
3187             this, d_extended_import_ASCII_dialog);
3188     import_dialog->setDirectory(asciiDirPath);
3189     import_dialog->selectNameFilter(d_ASCII_file_filter);
3190     if (import_dialog->exec() != QDialog::Accepted)
3191         return;
3192 
3193     asciiDirPath = import_dialog->directory().path();
3194     if (import_dialog->rememberOptions()) {
3195         columnSeparator = import_dialog->columnSeparator();
3196         ignoredLines = import_dialog->ignoredLines();
3197         renameColumns = import_dialog->renameColumns();
3198         strip_spaces = import_dialog->stripSpaces();
3199         simplify_spaces = import_dialog->simplifySpaces();
3200         d_ASCII_import_locale = import_dialog->decimalSeparators();
3201         d_convert_to_numeric = import_dialog->convertToNumeric();
3202         saveSettings();
3203     }
3204 
3205     QLocale save_locale = QLocale();
3206     QLocale::setDefault(import_dialog->decimalSeparators());
3207     importASCII(import_dialog->selectedFiles(), import_dialog->importMode(),
3208                 import_dialog->columnSeparator(), import_dialog->ignoredLines(),
3209                 import_dialog->renameColumns(), import_dialog->stripSpaces(),
3210                 import_dialog->simplifySpaces(), import_dialog->convertToNumeric(),
3211                 import_dialog->decimalSeparators());
3212     QLocale::setDefault(save_locale);
3213 }
3214 
importASCII(const QStringList & files,int import_mode,const QString & local_column_separator,int local_ignored_lines,bool local_rename_columns,bool local_strip_spaces,bool local_simplify_spaces,bool local_convert_to_numeric,QLocale local_numeric_locale)3215 void ApplicationWindow::importASCII(const QStringList &files, int import_mode,
3216                                     const QString &local_column_separator, int local_ignored_lines,
3217                                     bool local_rename_columns, bool local_strip_spaces,
3218                                     bool local_simplify_spaces, bool local_convert_to_numeric,
3219                                     QLocale local_numeric_locale)
3220 {
3221     if (files.isEmpty())
3222         return;
3223 
3224     // this is very much a special case, and thus is handled completely in its own block
3225     if (import_mode == ImportASCIIDialog::NewTables) {
3226         int dx = 0, dy = 0;
3227         QStringList sorted_files = files;
3228         sorted_files.sort();
3229         for (int i = 0; i < sorted_files.size(); i++) {
3230             Table *w = newTable(sorted_files[i], local_column_separator, local_ignored_lines,
3231                                 local_rename_columns, local_strip_spaces, local_simplify_spaces,
3232                                 local_convert_to_numeric, local_numeric_locale);
3233             if (!w)
3234                 continue;
3235             w->setCaptionPolicy(MyWidget::Both);
3236             setListViewLabel(w->name(), sorted_files[i]);
3237             if (i == 0) {
3238                 dx = w->verticalHeaderWidth();
3239                 dy = w->frameGeometry().height() - w->height();
3240                 w->move(QPoint(0, 0));
3241             } else
3242                 w->move(QPoint(i * dx, i * dy));
3243         }
3244         modifiedProject();
3245         return;
3246     }
3247 
3248     Table *table = qobject_cast<Table *>(d_workspace.currentSubWindow());
3249     if (!table)
3250         return;
3251 
3252     foreach (QString file, files) {
3253         Table *temp = new Table(scriptEnv, file, local_column_separator, local_ignored_lines,
3254                                 local_rename_columns, local_strip_spaces, local_simplify_spaces,
3255                                 local_convert_to_numeric, local_numeric_locale, "temp");
3256         if (!temp)
3257             continue;
3258 
3259         // need to check data types of columns for append/overwrite
3260         if (import_mode == ImportASCIIDialog::NewRows
3261             || import_mode == ImportASCIIDialog::Overwrite) {
3262             if (local_convert_to_numeric) {
3263                 for (int col = 0; col < qMin(temp->columnCount(), table->columnCount()); col++)
3264                     if (table->column(col)->columnMode() != SciDAVis::ColumnMode::Numeric) {
3265                         QMessageBox::critical(this, tr("ASCII Import Failed"),
3266                                               tr("Numeric data cannot be imported into non-numeric "
3267                                                  "column \"%1\".")
3268                                                       .arg(table->column(col)->name()));
3269                         delete temp;
3270                         return;
3271                     }
3272             } else {
3273                 for (int col = 0; col < qMin(temp->columnCount(), table->columnCount()); col++)
3274                     if (table->column(col)->columnMode() != SciDAVis::ColumnMode::Text) {
3275                         QMessageBox::critical(this, tr("ASCII Import Failed"),
3276                                               tr("Non-numeric data cannot be imported into "
3277                                                  "non-text column \"%1\".")
3278                                                       .arg(table->column(col)->name()));
3279                         delete temp;
3280                         return;
3281                     }
3282             }
3283         }
3284 
3285         // copy or move data from temp to table
3286         switch (import_mode) {
3287         case ImportASCIIDialog::NewColumns:
3288             while (temp->d_future_table->childCount() > 0)
3289                 temp->d_future_table->reparentChild(table->d_future_table,
3290                                                     temp->d_future_table->child(0));
3291             break;
3292         case ImportASCIIDialog::NewRows: {
3293             int missing_columns = temp->columnCount() - table->columnCount();
3294             for (int col = 0; col < missing_columns; col++) {
3295                 Column *new_col =
3296                         new Column(tr("new_by_import") + QString::number(col + 1),
3297                                    local_convert_to_numeric ? SciDAVis::ColumnMode::Numeric : SciDAVis::ColumnMode::Text);
3298                 new_col->setPlotDesignation(SciDAVis::Y);
3299                 table->d_future_table->addChild(new_col);
3300             }
3301             Q_ASSERT(table->columnCount() >= temp->columnCount());
3302             int start_row = table->rowCount();
3303             table->d_future_table->setRowCount(table->rowCount() + temp->rowCount());
3304             for (int col = 0; col < temp->columnCount(); col++) {
3305                 Column *src_col = temp->column(col);
3306                 Column *dst_col = table->column(col);
3307                 Q_ASSERT(src_col->dataType() == dst_col->dataType());
3308                 dst_col->copy(src_col, 0, start_row, src_col->rowCount());
3309                 if (local_rename_columns)
3310                     dst_col->setName(src_col->name());
3311             }
3312             break;
3313         }
3314         case ImportASCIIDialog::Overwrite: {
3315             if (table->rowCount() < temp->rowCount())
3316                 table->d_future_table->setRowCount(temp->rowCount());
3317             for (int col = 0; col < table->columnCount() && col < temp->columnCount(); col++) {
3318                 Column *src_col = temp->column(col);
3319                 Column *dst_col = table->column(col);
3320                 Q_ASSERT(src_col->dataType() == dst_col->dataType());
3321                 dst_col->copy(src_col, 0, 0, temp->rowCount());
3322                 if (local_rename_columns)
3323                     dst_col->setName(src_col->name());
3324             }
3325             if (temp->columnCount() > table->columnCount()) {
3326                 temp->d_future_table->removeColumns(0, table->columnCount());
3327                 while (temp->d_future_table->childCount() > 0)
3328                     temp->d_future_table->reparentChild(table->d_future_table,
3329                                                         temp->d_future_table->child(0));
3330             }
3331             break;
3332         }
3333         }
3334         delete temp;
3335     }
3336 
3337     table->setWindowLabel(files.join("; "));
3338     table->notifyChanges();
3339     modifiedProject(table);
3340     modifiedProject();
3341 }
3342 
open()3343 void ApplicationWindow::open()
3344 {
3345     OpenProjectDialog *open_dialog = new OpenProjectDialog(this, d_extended_open_dialog);
3346     open_dialog->setDirectory(workingDir);
3347     auto &settings = getSettings();
3348     open_dialog->setCodec(settings.value("/General/Dialogs/LastUsedOriginLocale", "").toString());
3349     if (open_dialog->exec() != QDialog::Accepted || open_dialog->selectedFiles().isEmpty())
3350         return;
3351     workingDir = open_dialog->directory().path();
3352     settings.setValue("/General/Dialogs/LastUsedOriginLocale", open_dialog->codec());
3353 
3354     switch (open_dialog->openMode()) {
3355     case OpenProjectDialog::NewProject: {
3356         QString fn = open_dialog->selectedFiles()[0];
3357         QFileInfo fi(fn);
3358 
3359         if (projectname != "untitled") {
3360             QFileInfo fi(projectname);
3361             QString pn = fi.absolutePath();
3362             if (fn == pn) {
3363                 QMessageBox::warning(this, tr("File opening error"),
3364                                      tr("The file: <b>%1</b> is the current file!").arg(fn));
3365                 return;
3366             }
3367         }
3368 
3369         if (fn.endsWith(".sciprj", Qt::CaseInsensitive)
3370             || fn.endsWith(".sciprj~", Qt::CaseInsensitive)
3371             || fn.endsWith(".qti", Qt::CaseInsensitive) || fn.endsWith(".qti~", Qt::CaseInsensitive)
3372             || fn.endsWith(".sciprj.gz", Qt::CaseInsensitive)
3373             || fn.endsWith(".qti.gz", Qt::CaseInsensitive)
3374             || fn.endsWith(".opj", Qt::CaseInsensitive) || fn.endsWith(".ogm", Qt::CaseInsensitive)
3375             || fn.endsWith(".ogw", Qt::CaseInsensitive) || fn.endsWith(".ogg", Qt::CaseInsensitive)
3376             || fn.endsWith(".org", Qt::CaseInsensitive)) {
3377             if (!fi.exists()) {
3378                 QMessageBox::critical(this, tr("File opening error"),
3379                                       tr("The file: <b>%1</b> doesn't exist!").arg(fn));
3380                 return;
3381             }
3382 
3383             saveSettings(); // the recent projects must be saved
3384 
3385             ApplicationWindow *a = open(fn);
3386             if (a) {
3387                 a->workingDir = workingDir;
3388                 if (fn.endsWith(".sciprj", Qt::CaseInsensitive)
3389                     || fn.endsWith(".sciprj~", Qt::CaseInsensitive)
3390                     || fn.endsWith(".sciprj.gz", Qt::CaseInsensitive)
3391                     || fn.endsWith(".qti.gz", Qt::CaseInsensitive)
3392                     || fn.endsWith(".qti", Qt::CaseInsensitive)
3393                     || fn.endsWith(".qti~", Qt::CaseInsensitive)
3394                     || fn.endsWith(".opj", Qt::CaseInsensitive)
3395                     || fn.endsWith(".ogg", Qt::CaseInsensitive)
3396                     || fn.endsWith(".org", Qt::CaseInsensitive))
3397                     this->close();
3398             }
3399         } else {
3400             QMessageBox::critical(this, tr("File opening error"),
3401                                   tr("The file <b>%1</b> is not a valid project file.").arg(fn));
3402             return;
3403         }
3404         break;
3405     }
3406     case OpenProjectDialog::NewFolder:
3407         appendProject(open_dialog->selectedFiles()[0]);
3408         break;
3409     }
3410 }
3411 
open(const QString & fn,const QStringList & scriptArgs)3412 ApplicationWindow *ApplicationWindow::open(const QString &fn, const QStringList &scriptArgs)
3413 {
3414     if (fn.endsWith(".opj", Qt::CaseInsensitive) || fn.endsWith(".ogm", Qt::CaseInsensitive)
3415         || fn.endsWith(".ogw", Qt::CaseInsensitive) || fn.endsWith(".ogg", Qt::CaseInsensitive)
3416         || fn.endsWith(".org", Qt::CaseInsensitive))
3417 #ifdef ORIGIN_IMPORT
3418         return importOPJ(fn);
3419 #else
3420     {
3421         QMessageBox::critical(
3422                 this, tr("File opening error"),
3423                 tr("SciDAVis currently does not support Origin import. If you are interested in "
3424                    "reviving and maintaining an Origin import filter, contact the developers.")
3425                         .arg(fn));
3426         return 0;
3427     }
3428 #endif
3429     else if (fn.endsWith(".py", Qt::CaseInsensitive))
3430         return loadScript(fn, scriptArgs);
3431     else if (fn.endsWith(".sciprj", Qt::CaseInsensitive)
3432              || fn.endsWith(".sciprj.gz", Qt::CaseInsensitive)
3433              || fn.endsWith(".qti", Qt::CaseInsensitive)
3434              || fn.endsWith(".qti.gz", Qt::CaseInsensitive)
3435              || fn.endsWith(".sciprj~", Qt::CaseInsensitive)
3436              || fn.endsWith(".sciprj.gz~", Qt::CaseInsensitive)
3437              || fn.endsWith(".qti~", Qt::CaseInsensitive)
3438              || fn.endsWith(".qti.gz~", Qt::CaseInsensitive))
3439         return openProject(fn);
3440     else
3441         return plotFile(fn);
3442 }
3443 
openRecentProject()3444 void ApplicationWindow::openRecentProject()
3445 {
3446     QAction *trigger = qobject_cast<QAction *>(sender());
3447     if (!trigger)
3448         return;
3449     QString fn = trigger->text();
3450     int pos = fn.indexOf(" ", 0);
3451     fn = fn.right(fn.length() - pos - 1);
3452 
3453     QFile f(fn);
3454     if (!f.exists()) {
3455         QMessageBox::critical(this, tr("File Open Error"),
3456                               tr("The file: <b> %1 </b> <p>does not exist anymore!"
3457                                  "<p>It will be removed from the list.")
3458                                       .arg(fn));
3459 
3460         recentProjects.removeAll(fn);
3461         updateRecentProjectsList();
3462         return;
3463     }
3464 
3465     if (projectname != "untitled") {
3466         QFileInfo fi(projectname);
3467         QString pn = fi.absolutePath();
3468         if (fn == pn) {
3469             QMessageBox::warning(this, tr("File opening error"),
3470                                  tr("The file: <p><b> %1 </b><p> is the current file!").arg(fn));
3471             return;
3472         }
3473     }
3474 
3475     if (!fn.isEmpty()) {
3476         saveSettings(); // the recent projects must be saved
3477         ApplicationWindow *a = open(fn);
3478         if (a
3479             && (fn.endsWith(".sciprj", Qt::CaseInsensitive)
3480                 || fn.endsWith(".sciprj~", Qt::CaseInsensitive)
3481                 || fn.endsWith(".sciprj.gz", Qt::CaseInsensitive)
3482                 || fn.endsWith(".qti.gz", Qt::CaseInsensitive)
3483                 || fn.endsWith(".qti", Qt::CaseInsensitive)
3484                 || fn.endsWith(".qti~", Qt::CaseInsensitive)
3485                 || fn.endsWith(".opj", Qt::CaseInsensitive)
3486                 || fn.endsWith(".ogg", Qt::CaseInsensitive)
3487                 || fn.endsWith(".org", Qt::CaseInsensitive)))
3488             this->close();
3489     }
3490 }
3491 
openCompressedFile(const QString & fn)3492 QFile *ApplicationWindow::openCompressedFile(const QString &fn)
3493 {
3494     QTemporaryFile *file;
3495     char buf[16384];
3496     int len, err;
3497 
3498     gzFile in = gzopen(QFile::encodeName(fn).constData(), "rb");
3499     if (!in) {
3500         QMessageBox::critical(this, tr("File opening error"), tr("zlib can't open %1.").arg(fn));
3501         return 0;
3502     }
3503     file = new QTemporaryFile();
3504     if (!file || !file->open()) {
3505         gzclose(in);
3506         QMessageBox::critical(
3507                 this, tr("File opening error"),
3508                 tr("Can't create temporary file for writing uncompressed copy of %1.").arg(fn));
3509         return 0;
3510     }
3511 
3512     forever {
3513         len = gzread(in, buf, sizeof(buf));
3514         if (len == 0)
3515             break;
3516         if (len < 0) {
3517             QMessageBox::critical(this, tr("File opening error"), gzerror(in, &err));
3518             gzclose(in);
3519             file->close();
3520             delete file;
3521             return 0;
3522         }
3523         if (file->write(buf, len) != len) {
3524             QMessageBox::critical(
3525                     this, tr("File opening error"),
3526                     tr("Error writing to temporary file: %1").arg(file->errorString()));
3527             gzclose(in);
3528             file->close();
3529             delete file;
3530             return 0;
3531         }
3532     }
3533 
3534     gzclose(in);
3535     file->reset();
3536     return file;
3537 }
3538 
loadProject(const QString & fn)3539 bool ApplicationWindow::loadProject(const QString &fn)
3540 {
3541     unique_ptr<QFile> file;
3542 
3543     if (fn.endsWith(".gz", Qt::CaseInsensitive) || fn.endsWith(".gz~", Qt::CaseInsensitive)) {
3544         file.reset(openCompressedFile(fn));
3545         if (!file)
3546             return false;
3547     } else {
3548         file.reset(new QFile(fn));
3549         if (!file->open(QIODevice::ReadOnly)) {
3550             QMessageBox::critical(this, tr("File opening error"), file->errorString());
3551             return false;
3552         }
3553     }
3554 
3555     QTextStream t(file.get());
3556     t.setCodec(QTextCodec::codecForName("UTF-8"));
3557     QString s;
3558     QStringList list;
3559 
3560     s = t.readLine();
3561 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
3562     list = s.split(QRegExp("\\s"), Qt::SkipEmptyParts);
3563 #else
3564     list = s.split(QRegExp("\\s"), QString::SkipEmptyParts);
3565 #endif
3566     if (list.count() < 2 || (list[0] != "SciDAVis" && list[0] != "QtiPlot")) {
3567         if (QFile::exists(fn + "~")) {
3568             int choice = QMessageBox::question(
3569                     this, tr("File opening error"),
3570                     tr("The file <b>%1</b> is corrupted, but there exists a backup copy.<br>Do you "
3571                        "want to open the backup instead?")
3572                             .arg(fn),
3573                     QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape);
3574             if (choice == QMessageBox::Yes) {
3575                 QMessageBox::information(
3576                         this, tr("Opening backup copy"),
3577                         tr("The original (corrupt) file is being left untouched, in case you want "
3578                            "to "
3579                            "try rescuing data manually. If you want to continue working with the "
3580                            "automatically restored backup copy, you have to explicitly overwrite "
3581                            "the "
3582                            "original file."));
3583                 return loadProject(fn + "~");
3584             }
3585         }
3586         QMessageBox::critical(this, tr("File opening error"),
3587                               tr("The file <b>%1</b> is not a valid project file.").arg(fn));
3588         return false;
3589     }
3590 
3591 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
3592     QStringList vl = list[1].split(".", Qt::SkipEmptyParts);
3593 #else
3594     QStringList vl = list[1].split(".", QString::SkipEmptyParts);
3595 #endif
3596     if (fn.endsWith(".qti", Qt::CaseInsensitive) || fn.endsWith(".qti.gz", Qt::CaseInsensitive)
3597         || fn.endsWith(".qti~", Qt::CaseInsensitive)
3598         || fn.endsWith(".qti.gz~", Qt::CaseInsensitive)) {
3599         d_file_version = 100 * (vl[0]).toInt() + 10 * (vl[1]).toInt() + (vl[2]).toInt();
3600         if (d_file_version > 90) {
3601             QMessageBox::critical(this, tr("File opening error"),
3602                                   tr("SciDAVis does not support QtiPlot project files from "
3603                                      "versions later than 0.9.0.")
3604                                           .arg(fn));
3605             return false;
3606         }
3607     } else
3608         d_file_version = ((vl[0]).toInt() << 16) + ((vl[1]).toInt() << 8) + (vl[2]).toInt();
3609 
3610     projectname = fn;
3611     setWindowTitle(tr("SciDAVis") + " - " + fn);
3612 
3613     QFileInfo fi(fn);
3614     QString baseName = fi.fileName();
3615 
3616     if (d_file_version < 73)
3617         t.readLine();
3618 
3619     s = t.readLine();
3620 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
3621     list = s.split("\t", Qt::SkipEmptyParts);
3622 #else
3623     list = s.split("\t", QString::SkipEmptyParts);
3624 #endif
3625     if (list[0] == "<scripting-lang>") {
3626         if (!setScriptingLang(list[1], true))
3627             QMessageBox::warning(
3628                     this, tr("File opening error"),
3629                     tr("The file \"%1\" was created using \"%2\" as scripting language.\n\n"
3630                        "Initializing support for this language FAILED; I'm using \"%3\" instead.\n"
3631                        "Various parts of this file may not be displayed as expected.")
3632                             .arg(fn)
3633                             .arg(list[1])
3634                             .arg(scriptEnv->objectName()));
3635 
3636         s = t.readLine();
3637 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
3638         list = s.split("\t", Qt::SkipEmptyParts);
3639 #else
3640         list = s.split("\t", QString::SkipEmptyParts);
3641 #endif
3642     }
3643     int aux = 0, widgets = list[1].toInt();
3644 
3645     QString titleBase = tr("Window") + ": ";
3646     QString title = titleBase + "1/" + QString::number(widgets) + "  ";
3647 
3648     QProgressDialog progress; /*(this);*/
3649     progress.setWindowModality(Qt::WindowModal);
3650     progress.setRange(0, widgets);
3651     progress.setMinimumWidth(width() / 2);
3652     progress.setWindowTitle(tr("Opening file") + ": " + baseName);
3653     progress.setLabelText(title);
3654     progress.activateWindow();
3655 
3656     Folder *cf = projectFolder();
3657     folders.blockSignals(true);
3658     blockSignals(true);
3659     // rename project folder item
3660     FolderListItem *item = (FolderListItem *)folders.topLevelItem(0);
3661     item->setText(0, fi.baseName());
3662     item->folder()->setName(fi.baseName());
3663 
3664     // process tables and matrix information
3665     while (!t.atEnd() && !progress.wasCanceled()) {
3666         s = t.readLine(4096); // workaround for safely reading very big lines
3667         list.clear();
3668         if (s.left(8) == "<folder>") {
3669             list = s.split("\t");
3670             Folder &f = current_folder->addChild<Folder>(list[1]);
3671             f.setBirthDate(list[2]);
3672             f.setModificationDate(list[3]);
3673             if (list.count() > 4)
3674                 if (list[4] == "current")
3675                     cf = &f;
3676 
3677             FolderListItem *fli = new FolderListItem(current_folder->folderListItem(), &f);
3678             fli->setText(0, list[1]);
3679             f.setFolderListItem(fli);
3680 
3681             current_folder = &f;
3682         } else if (s == "<table>") {
3683             title = titleBase + QString::number(++aux) + "/" + QString::number(widgets);
3684             progress.setLabelText(title);
3685 
3686             openTable(this, t);
3687             progress.setValue(aux);
3688         } else if (s.left(17) == "<TableStatistics>") {
3689             QStringList lst;
3690             while (s != "</TableStatistics>") {
3691                 s = t.readLine();
3692                 lst << s;
3693             }
3694             lst.pop_back();
3695             openTableStatistics(lst);
3696         } else if (s == "<matrix>") {
3697             title = titleBase + QString::number(++aux) + "/" + QString::number(widgets);
3698             progress.setLabelText(title);
3699             QStringList lst;
3700             while (s != "</matrix>") {
3701                 s = t.readLine();
3702                 lst << s;
3703             }
3704             lst.pop_back();
3705             openMatrix(this, lst);
3706             progress.setValue(aux);
3707         } else if (s == "<note>") {
3708             title = titleBase + QString::number(++aux) + "/" + QString::number(widgets);
3709             progress.setLabelText(title);
3710             for (int i = 0; i < 3; i++) {
3711                 s = t.readLine();
3712                 list << s;
3713             }
3714             Note *m = openNote(this, list);
3715             QStringList cont;
3716             while (s != "</note>") {
3717                 s = t.readLine();
3718                 cont << s;
3719             }
3720             cont.pop_back();
3721             m->restore(cont);
3722             progress.setValue(aux);
3723         } else if (s == "</folder>") {
3724             Folder *parent = (Folder *)current_folder->parent();
3725             if (!parent)
3726                 current_folder = projectFolder();
3727             else
3728                 current_folder = parent;
3729         }
3730     }
3731 
3732     if (progress.wasCanceled()) {
3733         saved = true;
3734         close();
3735         return false;
3736     }
3737 
3738     // process the rest
3739     t.seek(0);
3740 
3741     MultiLayer *plot = 0;
3742     while (!t.atEnd() && !progress.wasCanceled()) {
3743         s = t.readLine(4096); // workaround for safely reading very big lines
3744         if (s.left(8) == "<folder>") {
3745             list = s.split("\t");
3746             current_folder = current_folder->findSubfolder(list[1]);
3747         } else if (s == "<multiLayer>") { // process multilayers information
3748             title = titleBase + QString::number(++aux) + "/" + QString::number(widgets);
3749             progress.setLabelText(title);
3750 
3751             s = t.readLine();
3752             QStringList graph = s.split("\t");
3753             QString caption = graph[0];
3754             plot = multilayerPlot(caption);
3755             plot->setCols(graph[1].toInt());
3756             plot->setRows(graph[2].toInt());
3757 
3758             setListViewDate(caption, graph[3]);
3759             plot->setBirthDate(graph[3]);
3760 
3761             restoreWindowGeometry(this, plot, t.readLine());
3762             plot->blockSignals(true);
3763 
3764             if (d_file_version > 71) {
3765                 QStringList lst = t.readLine().split("\t");
3766                 plot->setWindowLabel(lst[1]);
3767                 setListViewLabel(plot->name(), lst[1]);
3768                 if (lst.length() > 2) {
3769                     plot->setCaptionPolicy((MyWidget::CaptionPolicy)lst[2].toInt());
3770                 } else {
3771                     QMessageBox::warning(this, tr("File opening error"),
3772                                          tr("Invalid WindowLabel line:\n'%1'\nin file %2.")
3773                                                  .arg(lst.join(" "))
3774                                                  .arg(fn));
3775                     plot->setCaptionPolicy(MyWidget::CaptionPolicy::Name);
3776                     // Partial fix for sf #403
3777                     t.readLine();
3778                 }
3779             }
3780             if (d_file_version > 83) {
3781 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
3782                 QStringList lst = t.readLine().split("\t", Qt::SkipEmptyParts);
3783                 plot->setMargins(lst[1].toInt(), lst[2].toInt(), lst[3].toInt(), lst[4].toInt());
3784                 lst = t.readLine().split("\t", Qt::SkipEmptyParts);
3785                 plot->setSpacing(lst[1].toInt(), lst[2].toInt());
3786                 lst = t.readLine().split("\t", Qt::SkipEmptyParts);
3787                 plot->setLayerCanvasSize(lst[1].toInt(), lst[2].toInt());
3788                 lst = t.readLine().split("\t", Qt::SkipEmptyParts);
3789                 plot->setAlignement(lst[1].toInt(), lst[2].toInt());
3790 #else
3791                 QStringList lst = t.readLine().split("\t", QString::SkipEmptyParts);
3792                 plot->setMargins(lst[1].toInt(), lst[2].toInt(), lst[3].toInt(), lst[4].toInt());
3793                 lst = t.readLine().split("\t", QString::SkipEmptyParts);
3794                 plot->setSpacing(lst[1].toInt(), lst[2].toInt());
3795                 lst = t.readLine().split("\t", QString::SkipEmptyParts);
3796                 plot->setLayerCanvasSize(lst[1].toInt(), lst[2].toInt());
3797                 lst = t.readLine().split("\t", QString::SkipEmptyParts);
3798                 plot->setAlignement(lst[1].toInt(), lst[2].toInt());
3799 #endif
3800             }
3801 
3802             while (s != "</multiLayer>") { // open layers
3803                 s = t.readLine();
3804                 if (s.left(7) == "<graph>") {
3805                     list.clear();
3806                     while (s != "</graph>") {
3807                         s = t.readLine();
3808                         list << s;
3809                     }
3810                     openGraph(this, plot, list);
3811                 }
3812             }
3813             plot->blockSignals(false);
3814             activateSubWindow(plot);
3815             progress.setValue(aux);
3816         } else if (s == "<SurfacePlot>") { // process 3D plots information
3817             list.clear();
3818             title = titleBase + QString::number(++aux) + "/" + QString::number(widgets);
3819             progress.setLabelText(title);
3820             while (s != "</SurfacePlot>") {
3821                 s = t.readLine();
3822                 list << s;
3823             }
3824             openSurfacePlot(this, list);
3825             progress.setValue(aux);
3826         } else if (s == "</folder>") {
3827             Folder *parent = (Folder *)current_folder->parent();
3828             if (!parent)
3829                 current_folder = projectFolder();
3830             else
3831                 current_folder = parent;
3832         } else if (s.left(5) == "<log>") { // process analysis information
3833             s = t.readLine();
3834             while (s != "</log>") {
3835                 logInfo += s + "\n";
3836                 s = t.readLine();
3837             }
3838             results->setText(logInfo);
3839         }
3840     }
3841 
3842     if (progress.wasCanceled()) {
3843         saved = true;
3844         close();
3845         return false;
3846     }
3847 
3848     logInfo = logInfo.remove("</log>\n", Qt::CaseInsensitive);
3849 
3850     folders.setCurrentItem(cf->folderListItem());
3851     folders.blockSignals(false);
3852     // change folder to user defined current folder
3853     changeFolder(cf, true);
3854 
3855     blockSignals(false);
3856     renamedTables.clear();
3857 
3858     show();
3859     executeNotes();
3860     savedProject();
3861 
3862     recentProjects.removeAll(fn);
3863     recentProjects.push_front(fn);
3864     updateRecentProjectsList();
3865 
3866     return true;
3867 }
3868 
openProject(const QString & fn)3869 ApplicationWindow *ApplicationWindow::openProject(const QString &fn)
3870 {
3871     unique_ptr<ApplicationWindow> app(new ApplicationWindow);
3872     app->applyUserSettings();
3873     return app->loadProject(fn) ? app.release() : nullptr;
3874 }
3875 
executeNotes()3876 void ApplicationWindow::executeNotes()
3877 {
3878     QList<MyWidget *> lst = projectFolder()->windowsList();
3879     foreach (MyWidget *widget, lst)
3880         if (widget->inherits("Note") && ((Note *)widget)->autoexec())
3881             ((Note *)widget)->executeAll();
3882 }
3883 
scriptError(const QString & message,const QString & scriptName,int lineNumber)3884 void ApplicationWindow::scriptError(const QString &message, const QString &scriptName,
3885                                     int lineNumber)
3886 {
3887     Q_UNUSED(scriptName)
3888     Q_UNUSED(lineNumber)
3889     QMessageBox::critical(this, tr("SciDAVis") + " - " + tr("Script Error"), message);
3890 }
3891 
scriptPrint(const QString & text)3892 void ApplicationWindow::scriptPrint(const QString &text)
3893 {
3894 #ifdef SCRIPTING_CONSOLE
3895     if (!text.isEmpty())
3896         console.insertPlainText(text);
3897 #else
3898     printf(text.toUtf8().constData());
3899 #endif
3900 }
3901 
setScriptingLang(const QString & lang,bool force,bool batch)3902 bool ApplicationWindow::setScriptingLang(const QString &lang, bool force, bool batch)
3903 {
3904     if (!force && lang == scriptEnv->objectName())
3905         return true;
3906     if (lang.isEmpty())
3907         return false;
3908 
3909     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
3910 
3911     ScriptingEnv *newEnv = ScriptingLangManager::newEnv(lang.toStdString(), this, batch);
3912     if (!newEnv) {
3913         QApplication::restoreOverrideCursor();
3914         return false;
3915     }
3916 
3917     connect(newEnv, SIGNAL(error(const QString &, const QString &, int)), this,
3918             SLOT(scriptError(const QString &, const QString &, int)));
3919     connect(newEnv, SIGNAL(print(const QString &)), this, SLOT(scriptPrint(const QString &)));
3920     if (!newEnv->initialize()) {
3921         QApplication::restoreOverrideCursor();
3922         return false;
3923     }
3924 
3925     // notify everyone who might be interested
3926     ScriptingChangeEvent sce(newEnv);
3927     QApplication::sendEvent(this, &sce);
3928 
3929     foreach (QObject *i, findChildren<QWidget *>())
3930         QApplication::postEvent(i, new ScriptingChangeEvent(newEnv));
3931 
3932     QApplication::restoreOverrideCursor();
3933 
3934     return true;
3935 }
3936 
showScriptingLangDialog()3937 void ApplicationWindow::showScriptingLangDialog()
3938 {
3939     ScriptingLangDialog *d = new ScriptingLangDialog(scriptEnv, this);
3940     d->showNormal();
3941     d->activateWindow();
3942 }
3943 
restartScriptingEnv()3944 void ApplicationWindow::restartScriptingEnv()
3945 {
3946     if (setScriptingLang(scriptEnv->objectName(), true))
3947         executeNotes();
3948     else
3949         QMessageBox::critical(
3950                 this, tr("Scripting Error"),
3951                 tr("Scripting language \"%1\" failed to initialize.").arg(scriptEnv->objectName()));
3952 }
3953 
3954 // TODO: rewrite the template system
openTemplate()3955 void ApplicationWindow::openTemplate()
3956 {
3957     QString filter = "SciDAVis/QtiPlot 2D Graph Template (*.qpt);;";
3958     filter += "SciDAVis/QtiPlot 3D Surface Template (*.qst);;";
3959     filter += "SciDAVis/QtiPlot Table Template (*.qtt);;";
3960     filter += "SciDAVis/QtiPlot Matrix Template (*.qmt)";
3961 
3962     QString fn = QFileDialog::getOpenFileName(this, tr("Open Template File"), templatesDir, filter);
3963     if (!fn.isEmpty()) {
3964         QFileInfo fi(fn);
3965         templatesDir = fi.absolutePath();
3966         if (fn.contains(".qmt", Qt::CaseSensitive) || fn.contains(".qpt", Qt::CaseSensitive)
3967             || fn.contains(".qtt", Qt::CaseSensitive) || fn.contains(".qst", Qt::CaseSensitive)) {
3968             if (!fi.exists()) {
3969                 QMessageBox::critical(this, tr("File opening error"),
3970                                       tr("The file: <b>%1</b> doesn't exist!").arg(fn));
3971                 return;
3972             }
3973             QFile f(fn);
3974             QTextStream t(&f);
3975             t.setCodec(QTextCodec::codecForName("UTF-8"));
3976             f.open(QIODevice::ReadOnly);
3977 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
3978             QStringList l = t.readLine().split(QRegExp("\\s"), Qt::SkipEmptyParts);
3979 #else
3980             QStringList l = t.readLine().split(QRegExp("\\s"), QString::SkipEmptyParts);
3981 #endif
3982             QString fileType = l[0];
3983             if ((fileType != "SciDAVis") && (fileType != "QtiPlot")) {
3984                 QMessageBox::critical(
3985                         this, tr("File opening error"),
3986                         tr("The file: <b> %1 </b> was not created using SciDAVis!").arg(fn));
3987                 return;
3988             }
3989 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
3990             QStringList vl = l[1].split(".", Qt::SkipEmptyParts);
3991 #else
3992             QStringList vl = l[1].split(".", QString::SkipEmptyParts);
3993 #endif
3994             if (fileType == "QtiPlot") {
3995                 d_file_version = 100 * (vl[0]).toInt() + 10 * (vl[1]).toInt() + (vl[2]).toInt();
3996                 if (d_file_version > 90) {
3997                     QMessageBox::critical(this, tr("File opening error"),
3998                                           tr("SciDAVis does not support QtiPlot template files "
3999                                              "from versions later than 0.9.0.")
4000                                                   .arg(fn));
4001                     return;
4002                 }
4003             } else
4004                 d_file_version = ((vl[0]).toInt() << 16) + ((vl[1]).toInt() << 8) + (vl[2]).toInt();
4005 
4006             QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
4007 
4008             MyWidget *w = 0;
4009             QString templateType;
4010             t >> templateType;
4011 
4012             if (templateType == "<SurfacePlot>") {
4013                 t.skipWhiteSpace();
4014                 QStringList lst;
4015                 while (!t.atEnd())
4016                     lst << t.readLine();
4017                 w = openSurfacePlot(this, lst);
4018                 if (w)
4019                     ((Graph3D *)w)->clearData();
4020             } else {
4021                 int rows, cols;
4022                 t >> rows;
4023                 t >> cols;
4024                 t.skipWhiteSpace();
4025                 QString geometry = t.readLine();
4026 
4027                 if (templateType == "<multiLayer>") { // FIXME: workarounds for template
4028                     w = new MultiLayer("", &d_workspace, 0);
4029                     w->setAttribute(Qt::WA_DeleteOnClose);
4030                     QString label = generateUniqueName(tr("Graph"));
4031                     initBareMultilayerPlot((MultiLayer *)w, label.replace(QRegExp("_"), "-"));
4032                     if (w) {
4033                         ((MultiLayer *)w)->setCols(cols);
4034                         ((MultiLayer *)w)->setRows(rows);
4035                         restoreWindowGeometry(this, w, geometry);
4036                         if (d_file_version > 83) {
4037 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
4038                             QStringList lst = t.readLine().split("\t", Qt::SkipEmptyParts);
4039                             ((MultiLayer *)w)
4040                                     ->setMargins(lst[1].toInt(), lst[2].toInt(), lst[3].toInt(),
4041                                                  lst[4].toInt());
4042                             lst = t.readLine().split("\t", Qt::SkipEmptyParts);
4043                             ((MultiLayer *)w)->setSpacing(lst[1].toInt(), lst[2].toInt());
4044                             lst = t.readLine().split("\t", Qt::SkipEmptyParts);
4045                             ((MultiLayer *)w)->setLayerCanvasSize(lst[1].toInt(), lst[2].toInt());
4046                             lst = t.readLine().split("\t", Qt::SkipEmptyParts);
4047                             ((MultiLayer *)w)->setAlignement(lst[1].toInt(), lst[2].toInt());
4048 #else
4049                             QStringList lst = t.readLine().split("\t", QString::SkipEmptyParts);
4050                             ((MultiLayer *)w)
4051                                     ->setMargins(lst[1].toInt(), lst[2].toInt(), lst[3].toInt(),
4052                                                  lst[4].toInt());
4053                             lst = t.readLine().split("\t", QString::SkipEmptyParts);
4054                             ((MultiLayer *)w)->setSpacing(lst[1].toInt(), lst[2].toInt());
4055                             lst = t.readLine().split("\t", QString::SkipEmptyParts);
4056                             ((MultiLayer *)w)->setLayerCanvasSize(lst[1].toInt(), lst[2].toInt());
4057                             lst = t.readLine().split("\t", QString::SkipEmptyParts);
4058                             ((MultiLayer *)w)->setAlignement(lst[1].toInt(), lst[2].toInt());
4059 #endif
4060                         }
4061                         while (!t.atEnd()) { // open layers
4062                             QString s = t.readLine();
4063                             if (s.left(7) == "<graph>") {
4064                                 QStringList lst;
4065                                 while (s != "</graph>") {
4066                                     s = t.readLine();
4067                                     lst << s;
4068                                 }
4069                                 openGraph(this, (MultiLayer *)w, lst);
4070                             }
4071                         }
4072                     }
4073                 } else {
4074                     if (templateType == "<table>")
4075                         w = newTable(tr("Table1"), rows, cols);
4076                     else if (templateType == "<matrix>")
4077                         w = newMatrix(rows, cols);
4078                     if (w) {
4079                         QStringList lst;
4080                         while (!t.atEnd())
4081                             lst << t.readLine();
4082                         w->restore(lst);
4083                         restoreWindowGeometry(this, w, geometry);
4084                     }
4085                 }
4086             }
4087 
4088             f.close();
4089             if (w) {
4090                 switch (w->status()) {
4091                 case MyWidget::Maximized:
4092                     w->setMaximized();
4093                     break;
4094                 case MyWidget::Minimized:
4095                     w->setMinimized();
4096                     break;
4097                 case MyWidget::Hidden:
4098                     w->setHidden();
4099                     break;
4100                 case MyWidget::Normal:
4101                     w->setNormal();
4102                     break;
4103                 }
4104                 customMenu((MyWidget *)w);
4105                 customToolBars((MyWidget *)w);
4106             }
4107             QApplication::restoreOverrideCursor();
4108         } else {
4109             QMessageBox::critical(
4110                     this, tr("File opening error"),
4111                     tr("The file: <b>%1</b> is not a SciDAVis template file!").arg(fn));
4112             return;
4113         }
4114     }
4115 }
4116 
readSettings()4117 void ApplicationWindow::readSettings()
4118 {
4119     auto &settings = getSettings();
4120     /* ---------------- group General --------------- */
4121     settings.beginGroup("/General");
4122 #ifdef SEARCH_FOR_UPDATES
4123     autoSearchUpdates = settings.value("/AutoSearchUpdates", false).toBool();
4124 #endif
4125     appLanguage =
4126             settings.value("/Language", QLocale::system().name().section('_', 0, 0)).toString();
4127     show_windows_policy =
4128             (ShowWindowsPolicy)settings.value("/ShowWindowsPolicy", ApplicationWindow::ActiveFolder)
4129                     .toInt();
4130 
4131     recentProjects = settings.value("/RecentProjects").toStringList();
4132     // Follows an ugly hack added by Ion in order to fix Qt4 porting issues
4133     //(only needed on Windows due to a Qt bug?)
4134 #ifdef Q_OS_WIN
4135     if (!recentProjects.isEmpty() && recentProjects[0].contains("^e"))
4136 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
4137         recentProjects = recentProjects[0].split("^e", Qt::SkipEmptyParts);
4138 #else
4139         recentProjects = recentProjects[0].split("^e", QString::SkipEmptyParts);
4140 #endif
4141     else if (recentProjects.count() == 1) {
4142         QString s = recentProjects[0];
4143         if (s.remove(QRegExp("\\s")).isEmpty())
4144             recentProjects = QStringList();
4145     }
4146 #endif
4147 
4148     updateRecentProjectsList();
4149 
4150     changeAppStyle(settings.value("/Style", appStyle).toString());
4151     undoLimit = settings.value("/UndoLimit", 10).toInt();
4152     d_project->undoStack()->setUndoLimit(undoLimit);
4153     autoSave = settings.value("/AutoSave", true).toBool();
4154     autoSaveTime = settings.value("/AutoSaveTime", 15).toInt();
4155     defaultScriptingLang = settings.value("/ScriptingLang", "muParser").toString();
4156 
4157     QLocale temp_locale = QLocale(settings.value("/Locale", QLocale::system().name()).toString());
4158     bool usegl = settings.value("/LocaleUseGroupSeparator", true).toBool();
4159     if (usegl)
4160         temp_locale.setNumberOptions(temp_locale.numberOptions() & ~QLocale::OmitGroupSeparator);
4161     else
4162         temp_locale.setNumberOptions(temp_locale.numberOptions() | QLocale::OmitGroupSeparator);
4163     QLocale::setDefault(temp_locale);
4164 
4165     d_decimal_digits = settings.value("/DecimalDigits", 6).toInt();
4166     d_default_numeric_format = settings.value("/DefaultNumericFormat", 'g').toChar().toLatin1();
4167 
4168     // restore geometry of main window
4169     restoreGeometry(settings.value("/ProjectWindow/Geometry").toByteArray());
4170 
4171     // restore dock windows and tool bars
4172     restoreState(settings.value("/DockWindows").toByteArray());
4173     explorerSplitter->restoreState(settings.value("/ExplorerSplitter").toByteArray());
4174 
4175     QStringList applicationFont = settings.value("/Font").toStringList();
4176     if (applicationFont.size() == 4)
4177         appFont = QFont(applicationFont[0], applicationFont[1].toInt(), applicationFont[2].toInt(),
4178                         applicationFont[3].toInt());
4179 
4180     settings.beginGroup("/Dialogs");
4181     d_extended_open_dialog = settings.value("/ExtendedOpenDialog", true).toBool();
4182     d_extended_export_dialog = settings.value("/ExtendedExportDialog", true).toBool();
4183     d_extended_import_ASCII_dialog = settings.value("/ExtendedImportAsciiDialog", true).toBool();
4184     d_extended_plot_dialog =
4185             settings.value("/ExtendedPlotDialog", true).toBool(); // used by PlotDialog
4186 
4187     settings.beginGroup("/AddRemoveCurves");
4188     d_add_curves_dialog_size =
4189             QSize(settings.value("/Width", 700).toInt(), settings.value("/Height", 400).toInt());
4190     d_show_current_folder = settings.value("/ShowCurrentFolder", false).toBool();
4191     settings.endGroup(); // AddRemoveCurves Dialog
4192     settings.endGroup(); // Dialogs
4193 
4194     settings.beginGroup("/Colors");
4195     workspaceColor = QColor(COLORVALUE(settings.value("/Workspace", "darkGray").toString()));
4196     // see http://doc.trolltech.com/4.2/qvariant.html for instructions on qcolor <-> qvariant
4197     // conversion
4198     panelsColor = QColor(COLORVALUE(settings.value("/Panels", "#ffffffff").toString()));
4199     panelsTextColor = QColor(COLORVALUE(settings.value("/PanelsText", "#ff000000").toString()));
4200     settings.endGroup(); // Colors
4201 
4202     settings.beginGroup("/Paths");
4203     workingDir = settings.value("/WorkingDir", QDir::homePath()).toString();
4204     helpFilePath = settings.value("/HelpFile", "").toString();
4205 #ifdef PLUGIN_PATH
4206     QString defaultFitPluginsPath = PLUGIN_PATH;
4207 #else // defined PLUGIN_PATH
4208 #ifdef Q_OS_WIN
4209     QString defaultFitPluginsPath = "fitPlugins";
4210 #else
4211     QString defaultFitPluginsPath = "/usr/lib/scidavis/plugins";
4212 #endif
4213 #endif // defined PLUGIN_PATH
4214 #ifdef DYNAMIC_PLUGIN_PATH
4215     fitPluginsPath = settings.value("/FitPlugins", defaultFitPluginsPath).toString();
4216 #else // defined PLUGIN_PATH
4217     fitPluginsPath = defaultFitPluginsPath;
4218 #endif
4219 
4220 #ifdef Q_OS_WIN
4221     templatesDir = settings.value("/TemplatesDir", qApp->applicationDirPath()).toString();
4222     asciiDirPath = settings.value("/ASCII", qApp->applicationDirPath()).toString();
4223     imagesDirPath = settings.value("/Images", qApp->applicationDirPath()).toString();
4224 #else
4225     templatesDir = settings.value("/TemplatesDir", QDir::homePath()).toString();
4226     asciiDirPath = settings.value("/ASCII", QDir::homePath()).toString();
4227     imagesDirPath = settings.value("/Images", QDir::homePath()).toString();
4228 #endif
4229     locktoolbar->setChecked(settings.value("LockToolbars", false).toBool());
4230     settings.endGroup(); // Paths
4231     settings.endGroup();
4232     /* ------------- end group General ------------------- */
4233 
4234     settings.beginGroup("/UserFunctions");
4235     fitFunctions = settings.value("/FitFunctions").toStringList();
4236     surfaceFunc = settings.value("/SurfaceFunctions").toStringList();
4237     xFunctions = settings.value("/xFunctions").toStringList();
4238     yFunctions = settings.value("/yFunctions").toStringList();
4239     rFunctions = settings.value("/rFunctions").toStringList();
4240     thetaFunctions = settings.value("/thetaFunctions").toStringList();
4241     settings.endGroup(); // UserFunctions
4242 
4243     settings.beginGroup("/Confirmations");
4244     confirmCloseFolder = settings.value("/Folder", true).toBool();
4245     confirmCloseTable = settings.value("/Table", true).toBool();
4246     confirmCloseMatrix = settings.value("/Matrix", true).toBool();
4247     confirmClosePlot2D = settings.value("/Plot2D", true).toBool();
4248     confirmClosePlot3D = settings.value("/Plot3D", true).toBool();
4249     confirmCloseNotes = settings.value("/Note", true).toBool();
4250     settings.endGroup(); // Confirmations
4251 
4252     /* ---------------- group Tables --------------- */
4253     settings.beginGroup("/Tables");
4254     d_show_table_comments = settings.value("/DisplayComments", false).toBool();
4255     QStringList tableFonts = settings.value("/Fonts").toStringList();
4256     if (tableFonts.size() == 8) {
4257         tableTextFont = QFont(tableFonts[0], tableFonts[1].toInt(), tableFonts[2].toInt(),
4258                               tableFonts[3].toInt());
4259         tableHeaderFont = QFont(tableFonts[4], tableFonts[5].toInt(), tableFonts[6].toInt(),
4260                                 tableFonts[7].toInt());
4261     }
4262 
4263     settings.beginGroup("/Colors");
4264     tableBkgdColor = QColor(COLORVALUE(settings.value("/Background", "#ffffffff").toString()));
4265     tableTextColor = QColor(COLORVALUE(settings.value("/Text", "#ff000000").toString()));
4266     tableHeaderColor = QColor(COLORVALUE(settings.value("/Header", "#ff000000").toString()));
4267     settings.endGroup(); // Colors
4268     settings.endGroup();
4269     /* --------------- end group Tables ------------------------ */
4270 
4271     /* --------------- group 2D Plots ----------------------------- */
4272     settings.beginGroup("/2DPlots");
4273     settings.beginGroup("/General");
4274     titleOn = settings.value("/Title", true).toBool();
4275     allAxesOn = settings.value("/AllAxes", false).toBool();
4276     canvasFrameOn = settings.value("/CanvasFrame", false).toBool();
4277     canvasFrameWidth = settings.value("/CanvasFrameWidth", 0).toInt();
4278     defaultPlotMargin = settings.value("/Margin", 0).toInt();
4279     drawBackbones = settings.value("/AxesBackbones", true).toBool();
4280     axesLineWidth = settings.value("/AxesLineWidth", 1).toInt();
4281     autoscale2DPlots = settings.value("/Autoscale", true).toBool();
4282     autoScaleFonts = settings.value("/AutoScaleFonts", true).toBool();
4283     autoResizeLayers = settings.value("/AutoResizeLayers", true).toBool();
4284     antialiasing2DPlots = settings.value("/Antialiasing", true).toBool();
4285     d_scale_plots_on_print = settings.value("/ScaleLayersOnPrint", false).toBool();
4286     d_print_cropmarks = settings.value("/PrintCropmarks", false).toBool();
4287 
4288     QStringList graphFonts = settings.value("/Fonts").toStringList();
4289     if (graphFonts.size() == 16) {
4290         plotAxesFont = QFont(graphFonts[0], graphFonts[1].toInt(), graphFonts[2].toInt(),
4291                              graphFonts[3].toInt());
4292         plotNumbersFont = QFont(graphFonts[4], graphFonts[5].toInt(), graphFonts[6].toInt(),
4293                                 graphFonts[7].toInt());
4294         plotLegendFont = QFont(graphFonts[8], graphFonts[9].toInt(), graphFonts[10].toInt(),
4295                                graphFonts[11].toInt());
4296         plotTitleFont = QFont(graphFonts[12], graphFonts[13].toInt(), graphFonts[14].toInt(),
4297                               graphFonts[15].toInt());
4298     }
4299     settings.endGroup(); // General
4300 
4301     settings.beginGroup("/Curves");
4302     defaultCurveStyle = settings.value("/Style", Graph::LineSymbols).toInt();
4303     defaultCurveLineWidth = settings.value("/LineWidth", 1).toInt();
4304     defaultSymbolSize = settings.value("/SymbolSize", 7).toInt();
4305     settings.endGroup(); // Curves
4306 
4307     settings.beginGroup("/Ticks");
4308     majTicksStyle = settings.value("/MajTicksStyle", ScaleDraw::Out).toInt();
4309     minTicksStyle = settings.value("/MinTicksStyle", ScaleDraw::Out).toInt();
4310     minTicksLength = settings.value("/MinTicksLength", 5).toInt();
4311     majTicksLength = settings.value("/MajTicksLength", 9).toInt();
4312     settings.endGroup(); // Ticks
4313 
4314     settings.beginGroup("/Legend");
4315     legendFrameStyle = settings.value("/FrameStyle", Legend::Line).toInt();
4316     legendTextColor = QColor(COLORVALUE(
4317             settings.value("/TextColor", "#ff000000").toString())); // default color Qt::black
4318     legendBackground = QColor(COLORVALUE(
4319             settings.value("/BackgroundColor", "#ffffffff").toString())); // default color Qt::white
4320     legendBackground.setAlpha(
4321             settings.value("/Transparency", 0).toInt()); // transparent by default;
4322     settings.endGroup(); // Legend
4323 
4324     settings.beginGroup("/Arrows");
4325     defaultArrowLineWidth = settings.value("/Width", 1).toInt();
4326     defaultArrowColor = QColor(COLORVALUE(
4327             settings.value("/Color", "#ff000000").toString())); // default color Qt::black
4328     defaultArrowHeadLength = settings.value("/HeadLength", 4).toInt();
4329     defaultArrowHeadAngle = settings.value("/HeadAngle", 45).toInt();
4330     defaultArrowHeadFill = settings.value("/HeadFill", true).toBool();
4331     defaultArrowLineStyle =
4332             Graph::getPenStyle(settings.value("/LineStyle", "SolidLine").toString());
4333     settings.endGroup(); // Arrows
4334     settings.endGroup();
4335     /* ----------------- end group 2D Plots --------------------------- */
4336 
4337     /* ----------------- group 3D Plots --------------------------- */
4338     settings.beginGroup("/3DPlots");
4339     showPlot3DLegend = settings.value("/Legend", true).toBool();
4340     showPlot3DProjection = settings.value("/Projection", false).toBool();
4341     smooth3DMesh = settings.value("/Antialiasing", true).toBool();
4342     plot3DResolution = settings.value("/Resolution", 1).toInt();
4343     orthogonal3DPlots = settings.value("/Orthogonal", false).toBool();
4344     autoscale3DPlots = settings.value("/Autoscale", true).toBool();
4345 
4346     QStringList plot3DFonts = settings.value("/Fonts").toStringList();
4347     if (plot3DFonts.size() == 12) {
4348         plot3DTitleFont = QFont(plot3DFonts[0], plot3DFonts[1].toInt(), plot3DFonts[2].toInt(),
4349                                 plot3DFonts[3].toInt());
4350         plot3DNumbersFont = QFont(plot3DFonts[4], plot3DFonts[5].toInt(), plot3DFonts[6].toInt(),
4351                                   plot3DFonts[7].toInt());
4352         plot3DAxesFont = QFont(plot3DFonts[8], plot3DFonts[9].toInt(), plot3DFonts[10].toInt(),
4353                                plot3DFonts[11].toInt());
4354     }
4355 
4356     settings.beginGroup("/Colors");
4357     plot3DColors << settings.value("/MaxData", "blue").toString();
4358     plot3DColors << settings.value("/Labels", "#000000").toString();
4359     plot3DColors << settings.value("/Mesh", "#000000").toString();
4360     plot3DColors << settings.value("/Grid", "#000000").toString();
4361     plot3DColors << settings.value("/MinData", "red").toString();
4362     plot3DColors << settings.value("/Numbers", "#000000").toString();
4363     plot3DColors << settings.value("/Axes", "#000000").toString();
4364     plot3DColors << settings.value("/Background", "#ffffff").toString();
4365     settings.endGroup(); // Colors
4366     settings.endGroup();
4367     /* ----------------- end group 3D Plots --------------------------- */
4368 
4369     settings.beginGroup("/Fitting");
4370     fit_output_precision = settings.value("/OutputPrecision", 15).toInt();
4371     pasteFitResultsToPlot = settings.value("/PasteResultsToPlot", false).toBool();
4372     writeFitResultsToLog = settings.value("/WriteResultsToLog", true).toBool();
4373     generateUniformFitPoints = settings.value("/GenerateFunction", true).toBool();
4374     fitPoints = settings.value("/Points", 100).toInt();
4375     generatePeakCurves = settings.value("/GeneratePeakCurves", true).toBool();
4376     peakCurvesColor = QColor(
4377             COLORVALUE(settings.value("/PeaksColor", "#ff00ff00").toString())); // green color
4378     fit_scale_errors = settings.value("/ScaleErrors", false).toBool();
4379     d_2_linear_fit_points = settings.value("/TwoPointsLinearFit", true).toBool();
4380     settings.endGroup(); // Fitting
4381 
4382     settings.beginGroup("/ImportASCII");
4383     columnSeparator = settings.value("/ColumnSeparator", "\\t").toString();
4384     columnSeparator.replace("\\t", "\t").replace("\\s", " ");
4385     ignoredLines = settings.value("/IgnoreLines", 0).toInt();
4386     renameColumns = settings.value("/RenameColumns", true).toBool();
4387     strip_spaces = settings.value("/StripSpaces", false).toBool();
4388     simplify_spaces = settings.value("/SimplifySpaces", false).toBool();
4389     d_ASCII_file_filter = settings.value("/AsciiFileTypeFilter", "*").toString();
4390     d_ASCII_import_locale = settings.value("/AsciiImportLocale", "C").toString();
4391     d_convert_to_numeric = settings.value("/ConvertToNumeric", true).toBool();
4392     settings.endGroup(); // Import ASCII
4393 
4394     settings.beginGroup("/ExportImage");
4395     d_image_export_filter = settings.value("/ImageFileTypeFilter", ".png").toString();
4396     d_export_transparency = settings.value("/ExportTransparency", false).toBool();
4397     d_export_quality = settings.value("/ImageQuality", 100).toInt();
4398     d_export_resolution = settings.value("/Resolution", 72).toInt();
4399     d_export_color = settings.value("/ExportColor", true).toBool();
4400     d_export_vector_size = settings.value("/ExportPageSize", QPrinter::Custom).toInt();
4401     d_keep_plot_aspect = settings.value("/KeepAspect", true).toBool();
4402     d_export_orientation = settings.value("/Orientation", QPrinter::Landscape).toInt();
4403     settings.endGroup(); // ExportImage
4404 }
4405 
saveSettings()4406 void ApplicationWindow::saveSettings()
4407 {
4408     auto &settings = getSettings();
4409     /* ---------------- group General --------------- */
4410     settings.beginGroup("/General");
4411 #ifdef SEARCH_FOR_UPDATES
4412     settings.setValue("/AutoSearchUpdates", autoSearchUpdates);
4413 #endif
4414     settings.setValue("/Language", appLanguage);
4415     settings.setValue("/ShowWindowsPolicy", show_windows_policy);
4416     settings.setValue("/RecentProjects", recentProjects);
4417     settings.setValue("/Style", appStyle);
4418     settings.setValue("/AutoSave", autoSave);
4419     settings.setValue("/AutoSaveTime", autoSaveTime);
4420     settings.setValue("/UndoLimit", undoLimit);
4421     settings.setValue("/ScriptingLang", defaultScriptingLang);
4422     settings.setValue("/Locale", QLocale().name());
4423     settings.setValue("/LocaleUseGroupSeparator",
4424                       bool(!(QLocale().numberOptions() & QLocale::OmitGroupSeparator)));
4425     settings.setValue("/DecimalDigits", d_decimal_digits);
4426     settings.setValue("/DefaultNumericFormat", QChar(d_default_numeric_format));
4427 
4428     settings.setValue("/ProjectWindow/Geometry", saveGeometry());
4429     settings.setValue("/DockWindows", saveState());
4430     settings.setValue("/ExplorerSplitter", explorerSplitter->saveState());
4431 
4432     QStringList applicationFont;
4433     applicationFont << appFont.family();
4434     applicationFont << QString::number(appFont.pointSize());
4435     applicationFont << QString::number(appFont.weight());
4436     applicationFont << QString::number(appFont.italic());
4437     settings.setValue("/Font", applicationFont);
4438 
4439     settings.beginGroup("/Dialogs");
4440     settings.setValue("/ExtendedOpenDialog", d_extended_open_dialog);
4441     settings.setValue("/ExtendedExportDialog", d_extended_export_dialog);
4442     settings.setValue("/ExtendedImportAsciiDialog", d_extended_import_ASCII_dialog);
4443     settings.setValue("/ExtendedPlotDialog", d_extended_plot_dialog);
4444     settings.beginGroup("/AddRemoveCurves");
4445     settings.setValue("/Width", d_add_curves_dialog_size.width());
4446     settings.setValue("/Height", d_add_curves_dialog_size.height());
4447     settings.setValue("/ShowCurrentFolder", d_show_current_folder);
4448     settings.endGroup(); // AddRemoveCurves Dialog
4449     settings.endGroup(); // Dialogs
4450 
4451     settings.beginGroup("/Colors");
4452     settings.setValue("/Workspace", COLORNAME(workspaceColor));
4453     settings.setValue("/Panels", COLORNAME(panelsColor));
4454     settings.setValue("/PanelsText", COLORNAME(panelsTextColor));
4455     settings.endGroup(); // Colors
4456 
4457     settings.beginGroup("/Paths");
4458     settings.setValue("/WorkingDir", workingDir);
4459     settings.setValue("/TemplatesDir", templatesDir);
4460     settings.setValue("/HelpFile", helpFilePath);
4461     settings.setValue("/FitPlugins", fitPluginsPath);
4462     settings.setValue("/ASCII", asciiDirPath);
4463     settings.setValue("/Images", imagesDirPath);
4464 
4465     settings.setValue("LockToolbars", locktoolbar->isChecked());
4466 
4467     settings.endGroup(); // Paths
4468     settings.endGroup();
4469     /* ---------------- end group General --------------- */
4470 
4471     settings.beginGroup("/UserFunctions");
4472     settings.setValue("/FitFunctions", fitFunctions);
4473     settings.setValue("/SurfaceFunctions", surfaceFunc);
4474     settings.setValue("/xFunctions", xFunctions);
4475     settings.setValue("/yFunctions", yFunctions);
4476     settings.setValue("/rFunctions", rFunctions);
4477     settings.setValue("/thetaFunctions", thetaFunctions);
4478     settings.endGroup(); // UserFunctions
4479 
4480     settings.beginGroup("/Confirmations");
4481     settings.setValue("/Folder", confirmCloseFolder);
4482     settings.setValue("/Table", confirmCloseTable);
4483     settings.setValue("/Matrix", confirmCloseMatrix);
4484     settings.setValue("/Plot2D", confirmClosePlot2D);
4485     settings.setValue("/Plot3D", confirmClosePlot3D);
4486     settings.setValue("/Note", confirmCloseNotes);
4487     settings.endGroup(); // Confirmations
4488 
4489     /* ----------------- group Tables -------------- */
4490     settings.beginGroup("/Tables");
4491     settings.setValue("/DisplayComments", d_show_table_comments);
4492     QStringList tableFonts;
4493     tableFonts << tableTextFont.family();
4494     tableFonts << QString::number(tableTextFont.pointSize());
4495     tableFonts << QString::number(tableTextFont.weight());
4496     tableFonts << QString::number(tableTextFont.italic());
4497     tableFonts << tableHeaderFont.family();
4498     tableFonts << QString::number(tableHeaderFont.pointSize());
4499     tableFonts << QString::number(tableHeaderFont.weight());
4500     tableFonts << QString::number(tableHeaderFont.italic());
4501     settings.setValue("/Fonts", tableFonts);
4502 
4503     settings.beginGroup("/Colors");
4504     settings.setValue("/Background", COLORNAME(tableBkgdColor));
4505     settings.setValue("/Text", COLORNAME(tableTextColor));
4506     settings.setValue("/Header", COLORNAME(tableHeaderColor));
4507     settings.endGroup(); // Colors
4508     settings.endGroup();
4509     /* ----------------- end group Tables ---------- */
4510 
4511     /* ----------------- group 2D Plots ------------ */
4512     settings.beginGroup("/2DPlots");
4513     settings.beginGroup("/General");
4514     settings.setValue("/Title", titleOn);
4515     settings.setValue("/AllAxes", allAxesOn);
4516     settings.setValue("/CanvasFrame", canvasFrameOn);
4517     settings.setValue("/CanvasFrameWidth", canvasFrameWidth);
4518     settings.setValue("/Margin", defaultPlotMargin);
4519     settings.setValue("/AxesBackbones", drawBackbones);
4520     settings.setValue("/AxesLineWidth", axesLineWidth);
4521     settings.setValue("/Autoscale", autoscale2DPlots);
4522     settings.setValue("/AutoScaleFonts", autoScaleFonts);
4523     settings.setValue("/AutoResizeLayers", autoResizeLayers);
4524     settings.setValue("/Antialiasing", antialiasing2DPlots);
4525     settings.setValue("/ScaleLayersOnPrint", d_scale_plots_on_print);
4526     settings.setValue("/PrintCropmarks", d_print_cropmarks);
4527 
4528     QStringList graphFonts;
4529     graphFonts << plotAxesFont.family();
4530     graphFonts << QString::number(plotAxesFont.pointSize());
4531     graphFonts << QString::number(plotAxesFont.weight());
4532     graphFonts << QString::number(plotAxesFont.italic());
4533     graphFonts << plotNumbersFont.family();
4534     graphFonts << QString::number(plotNumbersFont.pointSize());
4535     graphFonts << QString::number(plotNumbersFont.weight());
4536     graphFonts << QString::number(plotNumbersFont.italic());
4537     graphFonts << plotLegendFont.family();
4538     graphFonts << QString::number(plotLegendFont.pointSize());
4539     graphFonts << QString::number(plotLegendFont.weight());
4540     graphFonts << QString::number(plotLegendFont.italic());
4541     graphFonts << plotTitleFont.family();
4542     graphFonts << QString::number(plotTitleFont.pointSize());
4543     graphFonts << QString::number(plotTitleFont.weight());
4544     graphFonts << QString::number(plotTitleFont.italic());
4545     settings.setValue("/Fonts", graphFonts);
4546     settings.endGroup(); // General
4547 
4548     settings.beginGroup("/Curves");
4549     settings.setValue("/Style", defaultCurveStyle);
4550     settings.setValue("/LineWidth", defaultCurveLineWidth);
4551     settings.setValue("/SymbolSize", defaultSymbolSize);
4552     settings.endGroup(); // Curves
4553 
4554     settings.beginGroup("/Ticks");
4555     settings.setValue("/MajTicksStyle", majTicksStyle);
4556     settings.setValue("/MinTicksStyle", minTicksStyle);
4557     settings.setValue("/MinTicksLength", minTicksLength);
4558     settings.setValue("/MajTicksLength", majTicksLength);
4559     settings.endGroup(); // Ticks
4560 
4561     settings.beginGroup("/Legend");
4562     settings.setValue("/FrameStyle", legendFrameStyle);
4563     settings.setValue("/TextColor", COLORNAME(legendTextColor));
4564     settings.setValue("/BackgroundColor", COLORNAME(legendBackground));
4565     settings.setValue("/Transparency", legendBackground.alpha());
4566     settings.endGroup(); // Legend
4567 
4568     settings.beginGroup("/Arrows");
4569     settings.setValue("/Width", defaultArrowLineWidth);
4570     settings.setValue("/Color", COLORNAME(defaultArrowColor));
4571     settings.setValue("/HeadLength", defaultArrowHeadLength);
4572     settings.setValue("/HeadAngle", defaultArrowHeadAngle);
4573     settings.setValue("/HeadFill", defaultArrowHeadFill);
4574     settings.setValue("/LineStyle", Graph::penStyleName(defaultArrowLineStyle));
4575     settings.endGroup(); // Arrows
4576     settings.endGroup();
4577     /* ----------------- end group 2D Plots -------- */
4578 
4579     /* ----------------- group 3D Plots ------------ */
4580     settings.beginGroup("/3DPlots");
4581     settings.setValue("/Legend", showPlot3DLegend);
4582     settings.setValue("/Projection", showPlot3DProjection);
4583     settings.setValue("/Antialiasing", smooth3DMesh);
4584     settings.setValue("/Resolution", plot3DResolution);
4585     settings.setValue("/Orthogonal", orthogonal3DPlots);
4586     settings.setValue("/Autoscale", autoscale3DPlots);
4587 
4588     QStringList plot3DFonts;
4589     plot3DFonts << plot3DTitleFont.family();
4590     plot3DFonts << QString::number(plot3DTitleFont.pointSize());
4591     plot3DFonts << QString::number(plot3DTitleFont.weight());
4592     plot3DFonts << QString::number(plot3DTitleFont.italic());
4593     plot3DFonts << plot3DNumbersFont.family();
4594     plot3DFonts << QString::number(plot3DNumbersFont.pointSize());
4595     plot3DFonts << QString::number(plot3DNumbersFont.weight());
4596     plot3DFonts << QString::number(plot3DNumbersFont.italic());
4597     plot3DFonts << plot3DAxesFont.family();
4598     plot3DFonts << QString::number(plot3DAxesFont.pointSize());
4599     plot3DFonts << QString::number(plot3DAxesFont.weight());
4600     plot3DFonts << QString::number(plot3DAxesFont.italic());
4601     settings.setValue("/Fonts", plot3DFonts);
4602 
4603     settings.beginGroup("/Colors");
4604     settings.setValue("/MaxData", plot3DColors[0]);
4605     settings.setValue("/Labels", plot3DColors[1]);
4606     settings.setValue("/Mesh", plot3DColors[2]);
4607     settings.setValue("/Grid", plot3DColors[3]);
4608     settings.setValue("/MinData", plot3DColors[4]);
4609     settings.setValue("/Numbers", plot3DColors[5]);
4610     settings.setValue("/Axes", plot3DColors[6]);
4611     settings.setValue("/Background", plot3DColors[7]);
4612     settings.endGroup(); // Colors
4613     settings.endGroup();
4614     /* ----------------- end group 2D Plots -------- */
4615 
4616     settings.beginGroup("/Fitting");
4617     settings.setValue("/OutputPrecision", fit_output_precision);
4618     settings.setValue("/PasteResultsToPlot", pasteFitResultsToPlot);
4619     settings.setValue("/WriteResultsToLog", writeFitResultsToLog);
4620     settings.setValue("/GenerateFunction", generateUniformFitPoints);
4621     settings.setValue("/Points", fitPoints);
4622     settings.setValue("/GeneratePeakCurves", generatePeakCurves);
4623     settings.setValue("/PeaksColor", COLORNAME(peakCurvesColor));
4624     settings.setValue("/ScaleErrors", fit_scale_errors);
4625     settings.setValue("/TwoPointsLinearFit", d_2_linear_fit_points);
4626     settings.endGroup(); // Fitting
4627 
4628     settings.beginGroup("/ImportASCII");
4629     QString sep = columnSeparator;
4630     settings.setValue("/ColumnSeparator", sep.replace("\t", "\\t").replace(" ", "\\s"));
4631     settings.setValue("/IgnoreLines", ignoredLines);
4632     settings.setValue("/RenameColumns", renameColumns);
4633     settings.setValue("/StripSpaces", strip_spaces);
4634     settings.setValue("/SimplifySpaces", simplify_spaces);
4635     settings.setValue("/AsciiFileTypeFilter", d_ASCII_file_filter);
4636     settings.setValue("/AsciiImportLocale", d_ASCII_import_locale.name());
4637     settings.setValue("/ConvertToNumeric", d_convert_to_numeric);
4638     settings.endGroup(); // ImportASCII
4639 
4640     settings.beginGroup("/ExportImage");
4641     settings.setValue("/ImageFileTypeFilter", d_image_export_filter);
4642     settings.setValue("/ExportTransparency", d_export_transparency);
4643     settings.setValue("/ImageQuality", d_export_quality);
4644     settings.setValue("/Resolution", d_export_resolution);
4645     settings.setValue("/ExportColor", d_export_color);
4646     settings.setValue("/ExportPageSize", d_export_vector_size);
4647     settings.setValue("/KeepAspect", d_keep_plot_aspect);
4648     settings.setValue("/Orientation", d_export_orientation);
4649     settings.endGroup(); // ExportImage
4650 }
4651 
exportGraph()4652 void ApplicationWindow::exportGraph()
4653 {
4654     QWidget *w = d_workspace.activeSubWindow();
4655     if (!w)
4656         return;
4657 
4658     MultiLayer *plot2D = 0;
4659     Graph3D *plot3D = 0;
4660     if (w->inherits("MultiLayer")) {
4661         plot2D = (MultiLayer *)w;
4662         if (plot2D->isEmpty()) {
4663             QMessageBox::critical(
4664                     this, tr("Export Error"),
4665                     tr("<h4>There are no plot layers available in this window!</h4>"));
4666             return;
4667         }
4668     } else if (w->inherits("Graph3D"))
4669         plot3D = (Graph3D *)w;
4670     else
4671         return;
4672 
4673     ImageExportDialog *ied = new ImageExportDialog(this, plot2D != NULL, d_extended_export_dialog);
4674     ied->setDirectory(workingDir);
4675     ied->selectFilter(d_image_export_filter);
4676     if (ied->exec() != QDialog::Accepted)
4677         return;
4678     workingDir = ied->directory().path();
4679     if (ied->selectedFiles().isEmpty())
4680         return;
4681 
4682     QString selected_filter = ied->selectedNameFilter();
4683     QString file_name = ied->selectedFiles()[0];
4684     QFileInfo file_info(file_name);
4685     if (!file_info.fileName().contains("."))
4686         file_name.append(selected_filter.remove("*"));
4687 
4688     QFile file(file_name);
4689     if (!file.open(QIODevice::WriteOnly)) {
4690         QMessageBox::critical(this, tr("Export Error"),
4691                               tr("Could not write to file: <br><h4> %1 </h4><p>Please verify that "
4692                                  "you have the right to write to this location!")
4693                                       .arg(file_name));
4694         return;
4695     }
4696 
4697     if (selected_filter.contains(".eps") || selected_filter.contains(".pdf")
4698         || selected_filter.contains(".ps")) {
4699         if (plot3D)
4700             plot3D->exportVector(file_name, selected_filter.remove(QRegularExpression("\\.")));
4701         else if (plot2D)
4702             plot2D->exportVector(file_name, ied->resolution(), ied->color(), ied->keepAspect(),
4703                                  ied->pageSize(), ied->pageOrientation());
4704     } else if (selected_filter.contains(".svg")) {
4705         if (plot2D)
4706             plot2D->exportSVG(file_name);
4707         else
4708             plot3D->exportVector(file_name, "svg");
4709     } else {
4710         QList<QByteArray> list = QImageWriter::supportedImageFormats();
4711         for (int i = 0; i < (int)list.count(); i++) {
4712             if (selected_filter.contains("." + (list[i]).toLower())) {
4713                 if (plot2D)
4714                     plot2D->exportImage(file_name, ied->quality());
4715                 else if (plot3D)
4716                     plot3D->exportImage(file_name, ied->quality());
4717             }
4718         }
4719     }
4720 }
4721 
exportLayer()4722 void ApplicationWindow::exportLayer()
4723 {
4724     QWidget *w = d_workspace.activeSubWindow();
4725     if (!w || !w->inherits("MultiLayer"))
4726         return;
4727 
4728     Graph *g = ((MultiLayer *)w)->activeGraph();
4729     if (!g)
4730         return;
4731 
4732     ImageExportDialog *ied = new ImageExportDialog(this, g != NULL, d_extended_export_dialog);
4733     ied->setDirectory(workingDir);
4734     ied->selectFilter(d_image_export_filter);
4735     if (ied->exec() != QDialog::Accepted)
4736         return;
4737     workingDir = ied->directory().path();
4738     if (ied->selectedFiles().isEmpty())
4739         return;
4740 
4741     QString selected_filter = ied->selectedNameFilter();
4742     QString file_name = ied->selectedFiles()[0];
4743     QFileInfo file_info(file_name);
4744     if (!file_info.fileName().contains("."))
4745         file_name.append(selected_filter.remove("*"));
4746 
4747     QFile file(file_name);
4748     if (!file.open(QIODevice::WriteOnly)) {
4749         QMessageBox::critical(this, tr("Export Error"),
4750                               tr("Could not write to file: <br><h4> %1 </h4><p>Please verify that "
4751                                  "you have the right to write to this location!")
4752                                       .arg(file_name));
4753         return;
4754     }
4755 
4756     if (selected_filter.contains(".eps") || selected_filter.contains(".pdf")
4757         || selected_filter.contains(".ps"))
4758         g->exportVector(file_name, ied->resolution(), ied->color(), ied->keepAspect(),
4759                         ied->pageSize(), ied->pageOrientation());
4760     else if (selected_filter.contains(".svg"))
4761         g->exportSVG(file_name);
4762     else {
4763         QList<QByteArray> list = QImageWriter::supportedImageFormats();
4764         for (int i = 0; i < (int)list.count(); i++)
4765             if (selected_filter.contains("." + (list[i]).toLower()))
4766                 g->exportImage(file_name, ied->quality());
4767     }
4768 }
4769 
exportAllGraphs()4770 void ApplicationWindow::exportAllGraphs()
4771 {
4772     ImageExportDialog *ied = new ImageExportDialog(this, true, d_extended_export_dialog);
4773     ied->setWindowTitle(tr("Choose a directory to export the graphs to"));
4774     QStringList tmp = ied->nameFilters();
4775     ied->setFileMode(QFileDialog::Directory);
4776     ied->setNameFilters(tmp);
4777     ied->setLabelText(QFileDialog::FileType, tr("Output format:"));
4778     ied->setLabelText(QFileDialog::FileName, tr("Directory:"));
4779 
4780     ied->setDirectory(workingDir);
4781     ied->selectFilter(d_image_export_filter);
4782 
4783     if (ied->exec() != QDialog::Accepted)
4784         return;
4785     workingDir = ied->directory().path();
4786     if (ied->selectedFiles().isEmpty())
4787         return;
4788 
4789     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
4790 
4791     QString output_dir = ied->selectedFiles()[0];
4792     QString file_suffix = ied->selectedNameFilter();
4793     file_suffix = file_suffix.toLower();
4794     file_suffix.remove("*");
4795 
4796     QList<MyWidget *> windows = windowsList();
4797     bool confirm_overwrite = true;
4798     MultiLayer *plot2D;
4799     Graph3D *plot3D;
4800 
4801     foreach (MyWidget *w, windows) {
4802         if (w->inherits("MultiLayer")) {
4803             plot3D = 0;
4804             plot2D = (MultiLayer *)w;
4805             if (plot2D->isEmpty()) {
4806                 QApplication::restoreOverrideCursor();
4807                 QMessageBox::warning(
4808                         this, tr("Warning"),
4809                         tr("There are no plot layers available in window <b>%1</b>.<br>"
4810                            "Graph window not exported!")
4811                                 .arg(plot2D->name()));
4812                 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
4813                 continue;
4814             }
4815         } else if (w->inherits("Graph3D")) {
4816             plot2D = 0;
4817             plot3D = (Graph3D *)w;
4818         } else
4819             continue;
4820 
4821         QString file_name = output_dir + "/" + w->objectName() + file_suffix;
4822         QFile f(file_name);
4823         if (f.exists() && confirm_overwrite) {
4824             QApplication::restoreOverrideCursor();
4825             switch (QMessageBox::question(this, tr("Overwrite file?"),
4826                                           tr("A file called: <p><b>%1</b><p>already exists. "
4827                                              "Do you want to overwrite it?")
4828                                                   .arg(file_name),
4829                                           tr("&Yes"), tr("&All"), tr("&Cancel"), 0, 1)) {
4830             case 1:
4831                 confirm_overwrite = false;
4832                 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
4833                 break;
4834             case 0:
4835                 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
4836                 break;
4837             case 2:
4838                 return;
4839             }
4840         }
4841         if (!f.open(QIODevice::WriteOnly)) {
4842             QApplication::restoreOverrideCursor();
4843             QMessageBox::critical(
4844                     this, tr("Export Error"),
4845                     tr("Could not write to file: <br><h4>%1</h4><p>"
4846                        "Please verify that you have the right to write to this location!")
4847                             .arg(file_name));
4848             return;
4849         }
4850         if (file_suffix.contains(".eps") || file_suffix.contains(".pdf")
4851             || file_suffix.contains(".ps")) {
4852             if (plot3D)
4853                 plot3D->exportVector(file_name, file_suffix.remove("."));
4854             else if (plot2D)
4855                 plot2D->exportVector(file_name, ied->resolution(), ied->color());
4856         } else if (file_suffix.contains(".svg")) {
4857             if (plot2D)
4858                 plot2D->exportSVG(file_name);
4859         } else {
4860             QList<QByteArray> list = QImageWriter::supportedImageFormats();
4861             for (int i = 0; i < (int)list.count(); i++) {
4862                 if (file_suffix.contains("." + (list[i]).toLower())) {
4863                     if (plot2D)
4864                         plot2D->exportImage(file_name, ied->quality());
4865                     else if (plot3D)
4866                         plot3D->exportImage(file_name, ied->quality());
4867                 }
4868             }
4869         }
4870     }
4871 
4872     QApplication::restoreOverrideCursor();
4873 }
4874 
windowGeometryInfo(MyWidget * w)4875 QString ApplicationWindow::windowGeometryInfo(MyWidget *w)
4876 {
4877     QString s = "geometry\t";
4878     if (w->status() == MyWidget::Maximized) {
4879         if (w == w->folder()->activeWindow())
4880             return s + "maximized\tactive\n";
4881         else
4882             return s + "maximized\n";
4883     }
4884 
4885     if (!w->parent())
4886         s += "0\t0\t500\t400\t";
4887     else {
4888         QPoint p = w->pos(); // store position
4889         s += QString::number(p.x()) + "\t";
4890         s += QString::number(p.y()) + "\t";
4891         s += QString::number(w->frameGeometry().width()) + "\t";
4892         s += QString::number(w->frameGeometry().height()) + "\t";
4893     }
4894 
4895     if (w->status() == MyWidget::Minimized)
4896         s += "minimized\t";
4897 
4898     bool hide = hidden(w);
4899     if (w == w->folder()->activeWindow() && !hide)
4900         s += "active\n";
4901     else if (hide)
4902         s += "hidden\n";
4903     else
4904         s += "\n";
4905     return s;
4906 }
4907 
restoreWindowGeometry(ApplicationWindow * app,MyWidget * w,const QString s)4908 void ApplicationWindow::restoreWindowGeometry(ApplicationWindow *app, MyWidget *w, const QString s)
4909 {
4910     w->blockSignals(true);
4911     QString caption = w->name();
4912     if (s.contains("minimized")) {
4913         QStringList lst = s.split("\t");
4914         if (lst.count() > 4)
4915             w->setGeometry(lst[1].toInt(), lst[2].toInt(), lst[3].toInt(), lst[4].toInt());
4916         w->setStatus(MyWidget::Minimized);
4917         app->setListView(caption, tr("Minimized"));
4918     } else if (s.contains("maximized")) {
4919         w->setStatus(MyWidget::Maximized);
4920         app->setListView(caption, tr("Maximized"));
4921     } else {
4922         QStringList lst = s.split("\t");
4923         w->setGeometry(lst[1].toInt(), lst[2].toInt(), lst[3].toInt(), lst[4].toInt());
4924         w->setStatus(MyWidget::Normal);
4925 
4926         if (lst.count() > 5) {
4927             if (lst[5] == "hidden")
4928                 app->hideWindow(w);
4929         }
4930     }
4931 
4932     if (s.contains("active")) {
4933         Folder *f = w->folder();
4934         if (f)
4935             f->setActiveWindow(w);
4936     }
4937 
4938     w->blockSignals(false);
4939 }
4940 
projectFolder()4941 Folder *ApplicationWindow::projectFolder()
4942 {
4943     return ((FolderListItem *)folders.topLevelItem(0))->folder();
4944 }
4945 
saveProject()4946 bool ApplicationWindow::saveProject()
4947 {
4948     if (projectname == "untitled" || projectname.endsWith(".opj", Qt::CaseInsensitive)
4949         || projectname.endsWith(".ogm", Qt::CaseInsensitive)
4950         || projectname.endsWith(".ogw", Qt::CaseInsensitive)
4951         || projectname.endsWith(".ogg", Qt::CaseInsensitive)
4952         || projectname.endsWith(".org", Qt::CaseInsensitive)) {
4953         saveProjectAs();
4954         return false;
4955     }
4956 
4957     bool compress = false;
4958     QString fn = projectname;
4959     if (fn.endsWith(".gz")) {
4960         fn = fn.left(fn.length() - 3);
4961         compress = true;
4962     }
4963 
4964     saveFolder(projectFolder(), fn);
4965 
4966     if (compress)
4967         file_compress(QFile::encodeName(fn).constData(), "wb9");
4968 
4969     setWindowTitle("SciDAVis - " + projectname);
4970     savedProject();
4971     actionUndo->setEnabled(false);
4972     actionRedo->setEnabled(false);
4973 
4974     if (autoSave) {
4975         if (savingTimerId)
4976             killTimer(savingTimerId);
4977         savingTimerId = startTimer(autoSaveTime * 60000);
4978     } else
4979         savingTimerId = 0;
4980 
4981     QApplication::restoreOverrideCursor();
4982     return true;
4983 }
4984 
saveProjectAs()4985 void ApplicationWindow::saveProjectAs()
4986 {
4987     QString filter = tr("SciDAVis project") + " (*.sciprj);;";
4988     filter += tr("Compressed SciDAVis project") + " (*.sciprj.gz)";
4989 
4990     QString selectedFilter;
4991     QString fn = QFileDialog::getSaveFileName(this, tr("Save Project As"), workingDir, filter,
4992                                               &selectedFilter);
4993     if (!fn.isEmpty()) {
4994         QFileInfo fi(fn);
4995         workingDir = fi.absolutePath();
4996         QString baseName = fi.fileName();
4997         if (!baseName.endsWith(".sciprj") && !baseName.endsWith(".sciprj.gz")) {
4998             fn.append(".sciprj");
4999             if (selectedFilter.contains(".gz"))
5000                 fn.append(".gz");
5001         }
5002         projectname = fn;
5003 
5004         if (saveProject()) {
5005             recentProjects.removeAll(fn);
5006             recentProjects.push_front(fn);
5007             updateRecentProjectsList();
5008 
5009             QFileInfo fi(fn);
5010             QString baseName = fi.baseName();
5011             FolderListItem *item = (FolderListItem *)folders.topLevelItem(0);
5012             item->setText(0, baseName);
5013             item->folder()->setName(baseName);
5014         }
5015     }
5016 }
5017 
saveNoteAs()5018 void ApplicationWindow::saveNoteAs()
5019 {
5020     Note *w = (Note *)d_workspace.activeSubWindow();
5021     if (!w || !w->inherits("Note"))
5022         return;
5023     w->exportASCII();
5024 }
5025 
saveAsTemplate()5026 void ApplicationWindow::saveAsTemplate()
5027 {
5028     MyWidget *w = (MyWidget *)d_workspace.activeSubWindow();
5029     if (!w)
5030         return;
5031 
5032     QString filter;
5033     if (w->inherits("Matrix"))
5034         filter = tr("SciDAVis/QtiPlot Matrix Template") + " (*.qmt)";
5035     else if (w->inherits("MultiLayer"))
5036         filter = tr("SciDAVis/QtiPlot 2D Graph Template") + " (*.qpt)";
5037     else if (w->inherits("Table"))
5038         filter = tr("SciDAVis/QtiPlot Table Template") + " (*.qtt)";
5039     else if (w->inherits("Graph3D"))
5040         filter = tr("SciDAVis/QtiPlot 3D Surface Template") + " (*.qst)";
5041 
5042     QString selectedFilter;
5043     QString fn =
5044             QFileDialog::getSaveFileName(this, tr("Save Window As Template"),
5045                                          templatesDir + "/" + w->name(), filter, &selectedFilter);
5046     if (!fn.isEmpty()) {
5047         QFileInfo fi(fn);
5048         workingDir = fi.absolutePath();
5049         QString baseName = fi.fileName();
5050         if (!baseName.contains(".")) {
5051             selectedFilter = selectedFilter.right(5).left(4);
5052             fn.append(selectedFilter);
5053         }
5054 
5055         QFile f(fn);
5056         if (!f.open(QIODevice::WriteOnly)) {
5057             QMessageBox::critical(this, tr("Export Error"),
5058                                   tr("Could not write to file: <br><h4> %1 </h4><p>Please verify "
5059                                      "that you have the right to write to this location!")
5060                                           .arg(fn));
5061             return;
5062         }
5063         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
5064         QString text = SciDAVis::schemaVersion() + " template file\n";
5065         text += w->saveAsTemplate(windowGeometryInfo(w));
5066         QTextStream t(&f);
5067         t.setCodec(QTextCodec::codecForName("UTF-8"));
5068         t << text;
5069         f.close();
5070         QApplication::restoreOverrideCursor();
5071     }
5072 }
5073 
renameActiveWindow()5074 void ApplicationWindow::renameActiveWindow()
5075 {
5076     MyWidget *m = (MyWidget *)d_workspace.activeSubWindow();
5077     if (!m)
5078         return;
5079 
5080     RenameWindowDialog *rwd = new RenameWindowDialog(this);
5081     rwd->setAttribute(Qt::WA_DeleteOnClose);
5082     rwd->setWidget(m);
5083     rwd->exec();
5084 }
5085 
renameWindow(QTreeWidgetItem * item,int,const QString & text)5086 void ApplicationWindow::renameWindow(QTreeWidgetItem *item, int, const QString &text)
5087 {
5088     if (auto wli = dynamic_cast<WindowListItem *>(item))
5089         if (auto w = wli->window())
5090             if (text != w->name())
5091                 renameWindow(w, text);
5092 }
5093 
renameWindow(MyWidget * w,const QString & text)5094 bool ApplicationWindow::renameWindow(MyWidget *w, const QString &text)
5095 {
5096     if (!w)
5097         return false;
5098 
5099     QString name = w->name();
5100 
5101     QString newName = text;
5102     newName.replace("-", "_");
5103     if (newName.isEmpty()) {
5104         QMessageBox::critical(this, tr("Error"), tr("Please enter a valid name!"));
5105         return false;
5106     } else if (newName.contains(QRegExp("\\W"))) {
5107         QMessageBox::critical(
5108                 this, tr("Error"),
5109                 tr("The name you chose is not valid: only letters and digits are allowed!") + "<p>"
5110                         + tr("Please choose another name!"));
5111         return false;
5112     }
5113 
5114     newName.replace("_", "-");
5115 
5116     while (alreadyUsedName(newName)) {
5117         QMessageBox::critical(this, tr("Error"),
5118                               tr("Name <b>%1</b> already exists!").arg(newName) + "<p>"
5119                                       + tr("Please choose another name!") + "<p>"
5120                                       + tr("Warning: for internal consistency reasons the "
5121                                            "underscore character is replaced with a minus sign."));
5122         return false;
5123     }
5124 
5125     if (w->inherits("Table")) {
5126         QStringList labels = ((Table *)w)->colNames();
5127         if (labels.contains(newName)) {
5128             QMessageBox::critical(
5129                     this, tr("Error"),
5130                     tr("The table name must be different from the names of its columns!") + "<p>"
5131                             + tr("Please choose another name!"));
5132             return false;
5133         }
5134 
5135         updateTableNames(name, newName);
5136     } else if (w->inherits("Matrix"))
5137         changeMatrixName(name, newName);
5138 
5139     w->setName(newName);
5140     w->setCaptionPolicy(w->captionPolicy());
5141     renameListViewItem(name, newName);
5142     return true;
5143 }
5144 
5145 // TODO: string list -> Column * list
columnsList(SciDAVis::PlotDesignation plotType)5146 QStringList ApplicationWindow::columnsList(SciDAVis::PlotDesignation plotType)
5147 {
5148     QList<MyWidget *> windows = windowsList();
5149     QStringList list;
5150     foreach (MyWidget *w, windows) {
5151         if (!w->inherits("Table"))
5152             continue;
5153 
5154         Table *t = (Table *)w;
5155         for (int i = 0; i < t->numCols(); i++) {
5156             if (t->colPlotDesignation(i) == plotType)
5157                 list << QString(t->name()) + "_" + t->colLabel(i);
5158         }
5159     }
5160 
5161     return list;
5162 }
5163 
5164 // TODO: string list -> Column * list
columnsList()5165 QStringList ApplicationWindow::columnsList()
5166 {
5167     QList<MyWidget *> windows = windowsList();
5168     QStringList list;
5169     foreach (MyWidget *w, windows) {
5170         if (!w->inherits("Table"))
5171             continue;
5172 
5173         Table *t = (Table *)w;
5174         for (int i = 0; i < t->numCols(); i++) {
5175             list << QString(t->name()) + "_" + t->colLabel(i);
5176         }
5177     }
5178 
5179     return list;
5180 }
5181 
showCurvesDialog()5182 void ApplicationWindow::showCurvesDialog()
5183 {
5184     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
5185         return;
5186 
5187     if (((MultiLayer *)d_workspace.activeSubWindow())->isEmpty()) {
5188         QMessageBox::warning(this, tr("Error"),
5189                              tr("<h4>There are no plot layers available in this window.</h4>"
5190                                 "<p><h4>Please add a layer and try again!</h4>"));
5191         return;
5192     }
5193 
5194     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
5195     if (!g)
5196         return;
5197 
5198     if (g->isPiePlot()) {
5199         QMessageBox::warning(this, tr("Error"),
5200                              tr("This functionality is not available for pie plots!"));
5201     } else {
5202         CurvesDialog *crvDialog = new CurvesDialog(this);
5203         crvDialog->setAttribute(Qt::WA_DeleteOnClose);
5204         crvDialog->setGraph(g);
5205         crvDialog->resize(d_add_curves_dialog_size);
5206         crvDialog->show();
5207     }
5208 }
5209 
tableList()5210 QList<MyWidget *> *ApplicationWindow::tableList()
5211 {
5212     QList<MyWidget *> *lst = new QList<MyWidget *>();
5213     foreach (MyWidget *w, windowsList()) {
5214         if (w->inherits("Table"))
5215             lst->append(w);
5216     }
5217     return lst;
5218 }
5219 
showPlotAssociations(int curve)5220 void ApplicationWindow::showPlotAssociations(int curve)
5221 {
5222     QWidget *w = d_workspace.activeSubWindow();
5223     if (!w || !w->inherits("MultiLayer"))
5224         return;
5225 
5226     Graph *g = ((MultiLayer *)w)->activeGraph();
5227     if (!g)
5228         return;
5229 
5230     AssociationsDialog *ad = new AssociationsDialog(this, Qt::WindowStaysOnTopHint);
5231     ad->setAttribute(Qt::WA_DeleteOnClose);
5232     ad->setGraph(g);
5233     ad->initTablesList(tableList(), curve);
5234     ad->exec();
5235 }
5236 
showTitleDialog()5237 void ApplicationWindow::showTitleDialog()
5238 {
5239     QWidget *w = d_workspace.activeSubWindow();
5240     if (!w)
5241         return;
5242 
5243     if (w->inherits("MultiLayer")) {
5244         Graph *g = ((MultiLayer *)w)->activeGraph();
5245         if (g) {
5246             TextDialog *td = new TextDialog(TextDialog::AxisTitle, this, Qt::Widget);
5247             td->setAttribute(Qt::WA_DeleteOnClose);
5248             connect(td, SIGNAL(changeFont(const QFont &)), g, SLOT(setTitleFont(const QFont &)));
5249             connect(td, SIGNAL(changeText(const QString &)), g, SLOT(setTitle(const QString &)));
5250             connect(td, SIGNAL(changeColor(const QColor &)), g,
5251                     SLOT(setTitleColor(const QColor &)));
5252             connect(td, SIGNAL(changeAlignment(int)), g, SLOT(setTitleAlignment(int)));
5253 
5254             QwtText t = g->plotWidget()->title();
5255             td->setText(t.text());
5256             td->setFont(t.font());
5257             td->setTextColor(t.color());
5258             td->setAlignment(t.renderFlags());
5259             td->exec();
5260         }
5261     } else if (w->inherits("Graph3D")) {
5262         Plot3DDialog *pd = (Plot3DDialog *)showPlot3dDialog();
5263         if (pd)
5264             pd->showTitleTab();
5265         delete pd;
5266     }
5267 }
5268 
showXAxisTitleDialog()5269 void ApplicationWindow::showXAxisTitleDialog()
5270 {
5271     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
5272         return;
5273 
5274     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
5275     if (g) {
5276         TextDialog *td = new TextDialog(TextDialog::AxisTitle, this, Qt::Widget);
5277         td->setAttribute(Qt::WA_DeleteOnClose);
5278         connect(td, SIGNAL(changeFont(const QFont &)), g, SLOT(setXAxisTitleFont(const QFont &)));
5279         connect(td, SIGNAL(changeText(const QString &)), g, SLOT(setXAxisTitle(const QString &)));
5280         connect(td, SIGNAL(changeColor(const QColor &)), g,
5281                 SLOT(setXAxisTitleColor(const QColor &)));
5282         connect(td, SIGNAL(changeAlignment(int)), g, SLOT(setXAxisTitleAlignment(int)));
5283 
5284         QStringList t = g->scalesTitles();
5285         td->setText(t[0]);
5286         td->setFont(g->axisTitleFont(2));
5287         td->setTextColor(g->axisTitleColor(2));
5288         td->setAlignment(g->axisTitleAlignment(2));
5289         td->setWindowTitle(tr("X Axis Title"));
5290         td->exec();
5291     }
5292 }
5293 
showYAxisTitleDialog()5294 void ApplicationWindow::showYAxisTitleDialog()
5295 {
5296     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
5297         return;
5298 
5299     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
5300     if (g) {
5301         TextDialog *td = new TextDialog(TextDialog::AxisTitle, this, Qt::Widget);
5302         td->setAttribute(Qt::WA_DeleteOnClose);
5303         connect(td, SIGNAL(changeFont(const QFont &)), g, SLOT(setYAxisTitleFont(const QFont &)));
5304         connect(td, SIGNAL(changeText(const QString &)), g, SLOT(setYAxisTitle(const QString &)));
5305         connect(td, SIGNAL(changeColor(const QColor &)), g,
5306                 SLOT(setYAxisTitleColor(const QColor &)));
5307         connect(td, SIGNAL(changeAlignment(int)), g, SLOT(setYAxisTitleAlignment(int)));
5308 
5309         QStringList t = g->scalesTitles();
5310         td->setText(t[1]);
5311         td->setFont(g->axisTitleFont(0));
5312         td->setTextColor(g->axisTitleColor(0));
5313         td->setAlignment(g->axisTitleAlignment(0));
5314         td->setWindowTitle(tr("Y Axis Title"));
5315         td->exec();
5316     }
5317 }
5318 
showRightAxisTitleDialog()5319 void ApplicationWindow::showRightAxisTitleDialog()
5320 {
5321     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
5322         return;
5323 
5324     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
5325     if (g) {
5326         TextDialog *td = new TextDialog(TextDialog::AxisTitle, this, Qt::Widget);
5327         td->setAttribute(Qt::WA_DeleteOnClose);
5328         connect(td, SIGNAL(changeFont(const QFont &)), g,
5329                 SLOT(setRightAxisTitleFont(const QFont &)));
5330         connect(td, SIGNAL(changeText(const QString &)), g,
5331                 SLOT(setRightAxisTitle(const QString &)));
5332         connect(td, SIGNAL(changeColor(const QColor &)), g,
5333                 SLOT(setRightAxisTitleColor(const QColor &)));
5334         connect(td, SIGNAL(changeAlignment(int)), g, SLOT(setRightAxisTitleAlignment(int)));
5335 
5336         QStringList t = g->scalesTitles();
5337         td->setText(t[3]);
5338         td->setFont(g->axisTitleFont(1));
5339         td->setTextColor(g->axisTitleColor(1));
5340         td->setAlignment(g->axisTitleAlignment(1));
5341         td->setWindowTitle(tr("Right Axis Title"));
5342         td->exec();
5343     }
5344 }
5345 
showTopAxisTitleDialog()5346 void ApplicationWindow::showTopAxisTitleDialog()
5347 {
5348     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
5349         return;
5350 
5351     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
5352     if (g) {
5353         TextDialog *td = new TextDialog(TextDialog::AxisTitle, this, Qt::Widget);
5354         td->setAttribute(Qt::WA_DeleteOnClose);
5355         connect(td, SIGNAL(changeFont(const QFont &)), g, SLOT(setTopAxisTitleFont(const QFont &)));
5356         connect(td, SIGNAL(changeText(const QString &)), g, SLOT(setTopAxisTitle(const QString &)));
5357         connect(td, SIGNAL(changeColor(const QColor &)), g,
5358                 SLOT(setTopAxisTitleColor(const QColor &)));
5359         connect(td, SIGNAL(changeAlignment(int)), g, SLOT(setTopAxisTitleAlignment(int)));
5360 
5361         QStringList t = g->scalesTitles();
5362         td->setText(t[2]);
5363         td->setFont(g->axisTitleFont(3));
5364         td->setTextColor(g->axisTitleColor(3));
5365         td->setAlignment(g->axisTitleAlignment(3));
5366         td->setWindowTitle(tr("Top Axis Title"));
5367         td->exec();
5368     }
5369 }
5370 
showExportASCIIDialog()5371 void ApplicationWindow::showExportASCIIDialog()
5372 {
5373     Table *table = qobject_cast<Table *>(d_workspace.activeSubWindow());
5374     if (table) {
5375         ExportDialog *ed = new ExportDialog(this, Qt::WindowContextHelpButtonHint);
5376         ed->setAttribute(Qt::WA_DeleteOnClose);
5377         connect(ed, SIGNAL(exportTable(const QString &, const QString &, bool, bool)), this,
5378                 SLOT(exportASCII(const QString &, const QString &, bool, bool)));
5379         connect(ed, SIGNAL(exportAllTables(const QString &, bool, bool)), this,
5380                 SLOT(exportAllTables(const QString &, bool, bool)));
5381 
5382         ed->setTableNames(tableWindows());
5383         ed->setActiveTableName(table->name());
5384         ed->setColumnSeparator(columnSeparator);
5385         ed->exec();
5386     }
5387 }
5388 
exportAllTables(const QString & sep,bool colNames,bool expSelection)5389 void ApplicationWindow::exportAllTables(const QString &sep, bool colNames, bool expSelection)
5390 {
5391     QString dir = QFileDialog::getExistingDirectory(
5392             this, tr("Choose a directory to export the tables to"), workingDir,
5393             QFileDialog::ShowDirsOnly);
5394     if (!dir.isEmpty()) {
5395         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
5396         workingDir = dir;
5397 
5398         bool confirmOverwrite = true;
5399         bool success = true;
5400         foreach (MyWidget *w, windowsList()) {
5401             if (w->inherits("Table")) {
5402                 Table *t = (Table *)w;
5403                 QString fileName = dir + "/" + t->name() + ".txt";
5404                 QFile f(fileName);
5405                 if (f.exists(fileName) && confirmOverwrite) {
5406                     QApplication::restoreOverrideCursor();
5407                     switch (QMessageBox::question(
5408                             this, tr("Overwrite file?"),
5409                             tr("A file called: <p><b>%1</b><p>already exists. "
5410                                "Do you want to overwrite it?")
5411                                     .arg(fileName),
5412                             tr("&Yes"), tr("&All"), tr("&Cancel"), 0, 1)) {
5413                     case 0:
5414                         success = t->exportASCII(fileName, sep, colNames, expSelection);
5415                         break;
5416 
5417                     case 1:
5418                         confirmOverwrite = false;
5419                         success = t->exportASCII(fileName, sep, colNames, expSelection);
5420                         break;
5421 
5422                     case 2:
5423                         return;
5424                         break;
5425                     }
5426                 } else
5427                     success = t->exportASCII(fileName, sep, colNames, expSelection);
5428 
5429                 if (!success)
5430                     break;
5431             }
5432         }
5433         QApplication::restoreOverrideCursor();
5434     }
5435 }
5436 
exportASCII(const QString & tableName,const QString & sep,bool colNames,bool expSelection)5437 void ApplicationWindow::exportASCII(const QString &tableName, const QString &sep, bool colNames,
5438                                     bool expSelection)
5439 {
5440     Table *t = table(tableName);
5441     if (!t)
5442         return;
5443 
5444     QString selectedFilter;
5445     QString fname =
5446             QFileDialog::getSaveFileName(this, tr("Choose a filename to save under"), asciiDirPath,
5447                                          "*.txt;;*.csv;;*.dat;;*.DAT", &selectedFilter);
5448     if (!fname.isEmpty()) {
5449         QFileInfo fi(fname);
5450         QString baseName = fi.fileName();
5451         if (baseName.contains(".") == 0)
5452             fname.append(selectedFilter.remove("*"));
5453 
5454         asciiDirPath = fi.absolutePath();
5455 
5456         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
5457         t->exportASCII(fname, sep, colNames, expSelection);
5458         QApplication::restoreOverrideCursor();
5459     }
5460 }
5461 
correlate()5462 void ApplicationWindow::correlate()
5463 {
5464     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Table"))
5465         return;
5466 
5467     Table *t = (Table *)d_workspace.activeSubWindow();
5468     QStringList s = t->selectedColumns();
5469     if ((int)s.count() != 2) {
5470         QMessageBox::warning(this, tr("Error"),
5471                              tr("Please select two columns for this operation!"));
5472         return;
5473     }
5474 
5475     Correlation *cor = new Correlation(this, t, s[0], s[1]);
5476     cor->run();
5477     delete cor;
5478 }
5479 
autoCorrelate()5480 void ApplicationWindow::autoCorrelate()
5481 {
5482     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Table"))
5483         return;
5484 
5485     Table *t = (Table *)d_workspace.activeSubWindow();
5486     QStringList s = t->selectedColumns();
5487     if ((int)s.count() != 1) {
5488         QMessageBox::warning(this, tr("Error"),
5489                              tr("Please select exactly one columns for this operation!"));
5490         return;
5491     }
5492 
5493     Correlation *cor = new Correlation(this, t, s[0], s[0]);
5494     cor->run();
5495     delete cor;
5496 }
5497 
convolute()5498 void ApplicationWindow::convolute()
5499 {
5500     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Table"))
5501         return;
5502 
5503     Table *t = (Table *)d_workspace.activeSubWindow();
5504     QStringList s = t->selectedColumns();
5505     if ((int)s.count() != 2) {
5506         QMessageBox::warning(this, tr("Error"),
5507                              tr("Please select two columns for this operation:\n the first "
5508                                 "represents the signal and the second the response function!"));
5509         return;
5510     }
5511 
5512     Convolution *cv = new Convolution(this, t, s[0], s[1]);
5513     cv->run();
5514     delete cv;
5515 }
5516 
deconvolute()5517 void ApplicationWindow::deconvolute()
5518 {
5519     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Table"))
5520         return;
5521 
5522     Table *t = (Table *)d_workspace.activeSubWindow();
5523     QStringList s = t->selectedColumns();
5524     if ((int)s.count() != 2) {
5525         QMessageBox::warning(this, tr("Error"),
5526                              tr("Please select two columns for this operation:\n the first "
5527                                 "represents the signal and the second the response function!"));
5528         return;
5529     }
5530 
5531     Deconvolution *dcv = new Deconvolution(this, t, s[0], s[1]);
5532     dcv->run();
5533     delete dcv;
5534 }
5535 
showColStatistics()5536 void ApplicationWindow::showColStatistics()
5537 {
5538     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Table"))
5539         return;
5540     Table *t = (Table *)d_workspace.activeSubWindow();
5541 
5542     if (int(t->selectedColumns().count()) > 0) {
5543         QList<int> targets;
5544         for (int i = 0; i < t->numCols(); i++)
5545             if (t->isColumnSelected(i, false))
5546                 targets << i;
5547         newTableStatistics(t, TableStatistics::StatColumn, targets)->showNormal();
5548     } else
5549         QMessageBox::warning(this, tr("Column selection error"),
5550                              tr("Please select a column first!"));
5551 }
5552 
showRowStatistics()5553 void ApplicationWindow::showRowStatistics()
5554 {
5555     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Table"))
5556         return;
5557     Table *t = (Table *)d_workspace.activeSubWindow();
5558 
5559     if (t->numSelectedRows() > 0) {
5560         QList<int> targets;
5561         for (int i = 0; i < t->numRows(); i++)
5562             if (t->isRowSelected(i, false))
5563                 targets << i;
5564         newTableStatistics(t, TableStatistics::StatRow, targets)->showNormal();
5565     } else
5566         QMessageBox::warning(this, tr("Row selection error"), tr("Please select a row first!"));
5567 }
5568 
plot2VerticalLayers()5569 void ApplicationWindow::plot2VerticalLayers()
5570 {
5571     multilayerPlot(1, 2, defaultCurveStyle);
5572 }
5573 
plot2HorizontalLayers()5574 void ApplicationWindow::plot2HorizontalLayers()
5575 {
5576     multilayerPlot(2, 1, defaultCurveStyle);
5577 }
5578 
plot4Layers()5579 void ApplicationWindow::plot4Layers()
5580 {
5581     multilayerPlot(2, 2, defaultCurveStyle);
5582 }
5583 
plotStackedLayers()5584 void ApplicationWindow::plotStackedLayers()
5585 {
5586     multilayerPlot(1, -1, defaultCurveStyle);
5587 }
5588 
plotStackedHistograms()5589 void ApplicationWindow::plotStackedHistograms()
5590 {
5591     multilayerPlot(1, -1, Graph::Histogram);
5592 }
5593 
showGeneralPlotDialog()5594 void ApplicationWindow::showGeneralPlotDialog()
5595 {
5596     MyWidget *plot = (MyWidget *)d_workspace.activeSubWindow();
5597     if (!plot)
5598         return;
5599 
5600     if (plot->inherits("MultiLayer") && ((MultiLayer *)plot)->layers())
5601         showPlotDialog();
5602     else if (plot->inherits("Graph3D")) {
5603         if (auto gd = dynamic_cast<Plot3DDialog *>(showScaleDialog()))
5604             gd->showGeneralTab();
5605     }
5606 }
5607 
showAxisDialog()5608 void ApplicationWindow::showAxisDialog()
5609 {
5610     QWidget *plot = (QWidget *)d_workspace.activeSubWindow();
5611     if (!plot)
5612         return;
5613 
5614     if (plot->inherits("MultiLayer") && ((MultiLayer *)plot)->layers()) {
5615         if (auto gd = dynamic_cast<AxesDialog *>(showScaleDialog()))
5616             gd->showAxesPage();
5617     } else if (plot->inherits("Graph3D"))
5618         if (auto gd = dynamic_cast<Plot3DDialog *>(showScaleDialog()))
5619             gd->showAxisTab();
5620 }
5621 
showGridDialog()5622 void ApplicationWindow::showGridDialog()
5623 {
5624     if (auto gd = dynamic_cast<AxesDialog *>(showScaleDialog()))
5625         gd->showGridPage();
5626 }
5627 
showScaleDialog()5628 QDialog *ApplicationWindow::showScaleDialog()
5629 {
5630     QWidget *w = d_workspace.activeSubWindow();
5631     if (!w)
5632         return 0;
5633 
5634     if (w->inherits("MultiLayer")) {
5635         if (((MultiLayer *)w)->isEmpty())
5636             return 0;
5637 
5638         Graph *g = ((MultiLayer *)w)->activeGraph();
5639         auto &ad = addChild<AxesDialog>();
5640         ad.setGraph(g);
5641         ad.exec();
5642         return &ad;
5643     } else if (w->inherits("Graph3D"))
5644         return showPlot3dDialog();
5645 
5646     return 0;
5647 }
5648 
showScalePageFromAxisDialog(int axisPos)5649 AxesDialog *ApplicationWindow::showScalePageFromAxisDialog(int axisPos)
5650 {
5651     AxesDialog *gd = (AxesDialog *)showScaleDialog();
5652     if (gd)
5653         gd->setCurrentScale(axisPos);
5654 
5655     return gd;
5656 }
5657 
showAxisPageFromAxisDialog(int axisPos)5658 AxesDialog *ApplicationWindow::showAxisPageFromAxisDialog(int axisPos)
5659 {
5660     AxesDialog *gd = (AxesDialog *)showScaleDialog();
5661     if (gd) {
5662         gd->showAxesPage();
5663         gd->setCurrentScale(axisPos);
5664     }
5665     return gd;
5666 }
5667 
showPlot3dDialog()5668 QDialog *ApplicationWindow::showPlot3dDialog()
5669 {
5670     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D")) {
5671         Graph3D *g = (Graph3D *)d_workspace.activeSubWindow();
5672         if (!g->hasData()) {
5673             QApplication::restoreOverrideCursor();
5674             QMessageBox::warning(this, tr("Warning"),
5675                                  tr("Not available for empty 3D surface plots!"));
5676             return 0;
5677         }
5678 
5679         Plot3DDialog *pd = new Plot3DDialog(this);
5680         pd->setPlot(g);
5681 
5682         connect(pd,
5683                 SIGNAL(updateColors(const QColor &, const QColor &, const QColor &, const QColor &,
5684                                     const QColor &, const QColor &)),
5685                 g,
5686                 SLOT(updateColors(const QColor &, const QColor &, const QColor &, const QColor &,
5687                                   const QColor &, const QColor &)));
5688         connect(pd, SIGNAL(setDataColorMap(const QString &)), g,
5689                 SLOT(setDataColorMap(const QString &)));
5690         connect(pd, SIGNAL(updateDataColors(const QColor &, const QColor &)), g,
5691                 SLOT(setDataColors(const QColor &, const QColor &)));
5692         connect(pd, SIGNAL(updateTitle(const QString &, const QColor &, const QFont &)), g,
5693                 SLOT(updateTitle(const QString &, const QColor &, const QFont &)));
5694         connect(pd, SIGNAL(updateResolution(int)), g, SLOT(setResolution(int)));
5695         connect(pd, SIGNAL(showColorLegend(bool)), g, SLOT(showColorLegend(bool)));
5696         connect(pd, SIGNAL(setOrtho(bool)), g, SLOT(setOrtho(bool)));
5697         connect(pd, SIGNAL(updateLabel(int, const QString &, const QFont &)), g,
5698                 SLOT(updateLabel(int, const QString &, const QFont &)));
5699         connect(pd, SIGNAL(updateScale(int, const QStringList &)), g,
5700                 SLOT(updateScale(int, const QStringList &)));
5701         connect(pd, SIGNAL(adjustLabels(int)), g, SLOT(adjustLabels(int)));
5702         connect(pd, SIGNAL(updateTickLength(int, double, double)), g,
5703                 SLOT(updateTickLength(int, double, double)));
5704         connect(pd, SIGNAL(setNumbersFont(const QFont &)), g, SLOT(setNumbersFont(const QFont &)));
5705         connect(pd, SIGNAL(updateMeshLineWidth(int)), g, SLOT(setMeshLineWidth(int)));
5706         connect(pd, SIGNAL(updateBars(double)), g, SLOT(updateBars(double)));
5707         connect(pd, SIGNAL(updatePoints(double, bool)), g, SLOT(updatePoints(double, bool)));
5708         connect(pd, SIGNAL(showWorksheet()), g, SLOT(showWorksheet()));
5709         connect(pd, SIGNAL(updateZoom(double)), g, SLOT(updateZoom(double)));
5710         connect(pd, SIGNAL(updateScaling(double, double, double)), g,
5711                 SLOT(updateScaling(double, double, double)));
5712         connect(pd, SIGNAL(updateCones(double, int)), g, SLOT(updateCones(double, int)));
5713         connect(pd, SIGNAL(updateCross(double, double, bool, bool)), g,
5714                 SLOT(updateCross(double, double, bool, bool)));
5715 
5716         pd->setMeshLineWidth(g->meshLineWidth());
5717         pd->setDataColors(g->minDataColor(), g->maxDataColor());
5718         pd->setColors(g->titleColor(), g->meshColor(), g->axesColor(), g->numColor(),
5719                       g->labelColor(), g->bgColor(), g->gridColor());
5720 
5721         pd->setTitle(g->plotTitle());
5722         pd->setTitleFont(g->titleFont());
5723 
5724         pd->setZoom(g->zoom());
5725         pd->setScaling(g->xScale(), g->yScale(), g->zScale());
5726         pd->setResolution(g->resolution());
5727         pd->showLegend(g->isLegendOn());
5728         pd->setOrthogonal(g->isOrthogonal());
5729         pd->setAxesLabels(g->axesLabels());
5730         pd->setAxesTickLengths(g->axisTickLengths());
5731         pd->setAxesFonts(g->xAxisLabelFont(), g->yAxisLabelFont(), g->zAxisLabelFont());
5732         pd->setScales(g->scaleLimits());
5733         pd->setLabelsDistance(g->labelsDistance());
5734         pd->setNumbersFonts(g->numbersFont());
5735 
5736         if (g->coordStyle() == Qwt3D::NOCOORD)
5737             pd->disableAxesOptions();
5738 
5739         Qwt3D::PLOTSTYLE style = g->plotStyle();
5740         Graph3D::PointStyle pt = g->pointType();
5741 
5742         if (style == Qwt3D::USER) {
5743             switch (pt) {
5744             case Graph3D::None:
5745                 break;
5746 
5747             case Graph3D::Dots:
5748                 pd->disableMeshOptions();
5749                 pd->initPointsOptionsStack();
5750                 pd->showPointsTab(g->pointsSize(), g->smoothPoints());
5751                 break;
5752 
5753             case Graph3D::VerticalBars:
5754                 pd->showBarsTab(g->barsRadius());
5755                 break;
5756 
5757             case Graph3D::HairCross:
5758                 pd->disableMeshOptions();
5759                 pd->initPointsOptionsStack();
5760                 pd->showCrossHairTab(g->crossHairRadius(), g->crossHairLinewidth(),
5761                                      g->smoothCrossHair(), g->boxedCrossHair());
5762                 break;
5763 
5764             case Graph3D::Cones:
5765                 pd->disableMeshOptions();
5766                 pd->initPointsOptionsStack();
5767                 pd->showConesTab(g->coneRadius(), g->coneQuality());
5768                 break;
5769             }
5770         } else if (style == Qwt3D::FILLED)
5771             pd->disableMeshOptions();
5772         else if (style == Qwt3D::HIDDENLINE || style == Qwt3D::WIREFRAME)
5773             pd->disableLegend();
5774 
5775         if (g->grids() == 0)
5776             pd->disableGridOptions();
5777 
5778         if (g->userFunction())
5779             pd->customWorksheetBtn(QString());
5780         else if (g->getTable())
5781             pd->customWorksheetBtn(tr("&Worksheet"));
5782         else if (g->matrix())
5783             pd->customWorksheetBtn(tr("&Matrix"));
5784 
5785         pd->exec();
5786         return pd;
5787     } else
5788         return 0;
5789 }
5790 
showPlotDialog(int curveKey)5791 void ApplicationWindow::showPlotDialog(int curveKey)
5792 {
5793     QWidget *w = d_workspace.activeSubWindow();
5794     if (!w)
5795         return;
5796 
5797     if (w->inherits("MultiLayer")) {
5798         PlotDialog *pd = new PlotDialog(d_extended_plot_dialog, this);
5799         pd->setAttribute(Qt::WA_DeleteOnClose);
5800         pd->setMultiLayer((MultiLayer *)w);
5801         pd->insertColumnsList(columnsList());
5802         if (curveKey >= 0) {
5803             Graph *g = ((MultiLayer *)w)->activeGraph();
5804             if (g)
5805                 pd->selectCurve(g->curveIndex(curveKey));
5806         }
5807         pd->initFonts(plotTitleFont, plotAxesFont, plotNumbersFont, plotLegendFont);
5808         pd->showAll(d_extended_plot_dialog);
5809         pd->show();
5810     }
5811 }
5812 
showCurvePlotDialog()5813 void ApplicationWindow::showCurvePlotDialog()
5814 {
5815     showPlotDialog(actionShowCurvePlotDialog->data().toInt());
5816 }
5817 
showCurveContextMenuImpl(int curveKey)5818 QMenu *ApplicationWindow::showCurveContextMenuImpl(int curveKey)
5819 {
5820     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
5821         return nullptr;
5822 
5823     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
5824     DataCurve *c = (DataCurve *)g->curve(g->curveIndex(curveKey));
5825     if (!c || !c->isVisible())
5826         return nullptr;
5827 
5828     auto curveMenu = new QMenu(this);
5829     curveMenu->addAction(c->title().text(), this, SLOT(showCurvePlotDialog()));
5830     curveMenu->addSeparator();
5831 
5832     curveMenu->addAction(actionHideCurve);
5833     actionHideCurve->setData(curveKey);
5834 
5835     if (g->visibleCurves() > 1 && c->type() == Graph::Function) {
5836         curveMenu->addAction(actionHideOtherCurves);
5837         actionHideOtherCurves->setData(curveKey);
5838     } else if (c->type() != Graph::Function) {
5839         if ((g->visibleCurves() - c->errorBarsList().count()) > 1) {
5840             curveMenu->addAction(actionHideOtherCurves);
5841             actionHideOtherCurves->setData(curveKey);
5842         }
5843     }
5844 
5845     if (g->visibleCurves() != g->curves())
5846         curveMenu->addAction(actionShowAllCurves);
5847     curveMenu->addSeparator();
5848 
5849     if (c->type() == Graph::Function) {
5850         curveMenu->addAction(actionEditFunction);
5851         actionEditFunction->setData(curveKey);
5852     } else if (c->type() != Graph::ErrorBars) {
5853         curveMenu->addAction(actionEditCurveRange);
5854         actionEditCurveRange->setData(curveKey);
5855 
5856         curveMenu->addAction(actionCurveFullRange);
5857         if (c->isFullRange())
5858             actionCurveFullRange->setDisabled(true);
5859         else
5860             actionCurveFullRange->setEnabled(true);
5861         actionCurveFullRange->setData(curveKey);
5862 
5863         curveMenu->addSeparator();
5864     }
5865 
5866     curveMenu->addAction(actionShowCurveWorksheet);
5867     actionShowCurveWorksheet->setData(curveKey);
5868 
5869     curveMenu->addAction(actionShowCurvePlotDialog);
5870     actionShowCurvePlotDialog->setData(curveKey);
5871 
5872     curveMenu->addSeparator();
5873 
5874     curveMenu->addAction(actionRemoveCurve);
5875     actionRemoveCurve->setData(curveKey);
5876     return curveMenu;
5877 }
5878 
showAllCurves()5879 void ApplicationWindow::showAllCurves()
5880 {
5881     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
5882         return;
5883 
5884     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
5885     if (!g)
5886         return;
5887 
5888     for (int i = 0; i < g->curves(); i++)
5889         g->showCurve(i);
5890     g->replot();
5891 }
5892 
hideOtherCurves()5893 void ApplicationWindow::hideOtherCurves()
5894 {
5895     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
5896         return;
5897 
5898     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
5899     if (!g)
5900         return;
5901 
5902     int curveKey = actionHideOtherCurves->data().toInt();
5903     for (int i = 0; i < g->curves(); i++)
5904         g->showCurve(i, false);
5905 
5906     g->showCurve(g->curveIndex(curveKey));
5907     g->replot();
5908 }
5909 
hideCurve()5910 void ApplicationWindow::hideCurve()
5911 {
5912     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
5913         return;
5914 
5915     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
5916     if (!g)
5917         return;
5918 
5919     int curveKey = actionHideCurve->data().toInt();
5920     g->showCurve(g->curveIndex(curveKey), false);
5921 }
5922 
removeCurve()5923 void ApplicationWindow::removeCurve()
5924 {
5925     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
5926         return;
5927 
5928     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
5929     if (!g)
5930         return;
5931 
5932     int curveKey = actionRemoveCurve->data().toInt();
5933     g->removeCurve(g->curveIndex(curveKey));
5934     g->updatePlot();
5935 }
5936 
showCurveWorksheet(Graph * g,int curveIndex)5937 void ApplicationWindow::showCurveWorksheet(Graph *g, int curveIndex)
5938 {
5939     if (!g)
5940         return;
5941 
5942     QwtPlotItem *it = g->plotItem(curveIndex);
5943     if (!it)
5944         return;
5945 
5946     if (auto sp = dynamic_cast<Spectrogram *>(it)) {
5947         if (sp->matrix())
5948             sp->matrix()->showMaximized();
5949     } else if (((PlotCurve *)it)->type() == Graph::Function)
5950         g->createTable((PlotCurve *)it);
5951     else
5952         showTable(it->title().text());
5953 }
5954 
showCurveWorksheet()5955 void ApplicationWindow::showCurveWorksheet()
5956 {
5957     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
5958         return;
5959 
5960     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
5961     if (!g)
5962         return;
5963 
5964     int curveKey = actionShowCurveWorksheet->data().toInt();
5965     showCurveWorksheet(g, g->curveIndex(curveKey));
5966 }
5967 
zoomIn()5968 void ApplicationWindow::zoomIn()
5969 {
5970     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
5971         return;
5972 
5973     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
5974     if (plot->isEmpty()) {
5975         QMessageBox::warning(this, tr("Warning"),
5976                              tr("<h4>There are no plot layers available in this window.</h4>"
5977                                 "<p><h4>Please add a layer and try again!</h4>"));
5978         btnPointer->setChecked(true);
5979         return;
5980     }
5981 
5982     if ((Graph *)plot->activeGraph()->isPiePlot()) {
5983         if (btnZoomIn->isChecked())
5984             QMessageBox::warning(this, tr("Warning"),
5985                                  tr("This functionality is not available for pie plots!"));
5986         btnPointer->setChecked(true);
5987         return;
5988     }
5989 
5990     QWidgetList graphsList = plot->graphPtrs();
5991     foreach (QWidget *widget, graphsList) {
5992         Graph *g = (Graph *)widget;
5993         if (!g->isPiePlot())
5994             g->zoom(true);
5995     }
5996 }
5997 
zoomOut()5998 void ApplicationWindow::zoomOut()
5999 {
6000     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6001         return;
6002 
6003     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6004     if (plot->isEmpty() || (Graph *)plot->activeGraph()->isPiePlot())
6005         return;
6006 
6007     ((Graph *)plot->activeGraph())->zoomOut();
6008     btnPointer->setChecked(true);
6009 }
6010 
setAutoScale()6011 void ApplicationWindow::setAutoScale()
6012 {
6013     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6014         return;
6015 
6016     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6017     if (plot->isEmpty()) {
6018         QMessageBox::warning(this, tr("Warning"),
6019                              tr("<h4>There are no plot layers available in this window.</h4>"));
6020         return;
6021     }
6022 
6023     Graph *g = (Graph *)plot->activeGraph();
6024     if (g) {
6025         g->setAutoScale();
6026         emit modified();
6027     }
6028 }
6029 
removePoints()6030 void ApplicationWindow::removePoints()
6031 {
6032     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6033         return;
6034 
6035     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6036     if (plot->isEmpty()) {
6037         QMessageBox::warning(this, tr("Warning"),
6038                              tr("<h4>There are no plot layers available in this window.</h4>"
6039                                 "<p><h4>Please add a layer and try again!</h4>"));
6040         btnPointer->setChecked(true);
6041         return;
6042     }
6043 
6044     Graph *g = (Graph *)plot->activeGraph();
6045     if (!g || !g->validCurvesDataSize()) {
6046         btnPointer->setChecked(true);
6047         return;
6048     }
6049 
6050     if (g->isPiePlot()) {
6051         QMessageBox::warning(this, tr("Warning"),
6052                              tr("This functionality is not available for pie plots!"));
6053         btnPointer->setChecked(true);
6054         return;
6055     } else {
6056         switch (QMessageBox::warning(this, tr("SciDAVis"),
6057                                      tr("This will modify the data in the worksheets!\nAre you "
6058                                         "sure you want to continue?"),
6059                                      tr("Continue"), tr("Cancel"), 0, 1)) {
6060         case 0:
6061             g->setActiveTool(new DataPickerTool(g, this, DataPickerTool::Remove, d_status_info,
6062                                                 SLOT(setText(const QString &))));
6063             break;
6064 
6065         case 1:
6066             btnPointer->setChecked(true);
6067             break;
6068         }
6069     }
6070 }
6071 
movePoints()6072 void ApplicationWindow::movePoints()
6073 {
6074     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6075         return;
6076 
6077     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6078     if (plot->isEmpty()) {
6079         QMessageBox::warning(this, tr("Warning"),
6080                              tr("<h4>There are no plot layers available in this window.</h4>"
6081                                 "<p><h4>Please add a layer and try again!</h4>"));
6082         btnPointer->setChecked(true);
6083         return;
6084     }
6085 
6086     Graph *g = (Graph *)plot->activeGraph();
6087     if (!g || !g->validCurvesDataSize()) {
6088         btnPointer->setChecked(true);
6089         return;
6090     }
6091 
6092     if (g->isPiePlot()) {
6093         QMessageBox::warning(this, tr("Warning"),
6094                              tr("This functionality is not available for pie plots!"));
6095 
6096         btnPointer->setChecked(true);
6097         return;
6098     } else {
6099         switch (QMessageBox::warning(this, tr("SciDAVis"),
6100                                      tr("This will modify the data in the worksheets!\nAre you "
6101                                         "sure you want to continue?"),
6102                                      tr("Continue"), tr("Cancel"), 0, 1)) {
6103         case 0:
6104             if (g) {
6105                 g->setActiveTool(new DataPickerTool(g, this, DataPickerTool::Move, d_status_info,
6106                                                     SLOT(setText(const QString &))));
6107             }
6108             break;
6109 
6110         case 1:
6111             btnPointer->setChecked(true);
6112             break;
6113         }
6114     }
6115 }
6116 
exportPDF()6117 void ApplicationWindow::exportPDF()
6118 {
6119     QWidget *w = d_workspace.activeSubWindow();
6120     if (!w)
6121         return;
6122 
6123     if (w->inherits("MultiLayer") && ((MultiLayer *)w)->isEmpty()) {
6124         QMessageBox::warning(this, tr("Warning"),
6125                              tr("<h4>There are no plot layers available in this window.</h4>"));
6126         return;
6127     }
6128 
6129     QString fname = QFileDialog::getSaveFileName(this, tr("Choose a filename to save under"),
6130                                                  workingDir, "*.pdf");
6131     if (!fname.isEmpty()) {
6132         QFileInfo fi(fname);
6133         QString baseName = fi.fileName();
6134         if (!baseName.contains("."))
6135             fname.append(".pdf");
6136 
6137         workingDir = fi.absolutePath();
6138 
6139         QFile f(fname);
6140         if (!f.open(QIODevice::WriteOnly)) {
6141             QMessageBox::critical(this, tr("Export Error"),
6142                                   tr("Could not write to file: <h4>%1</h4><p>Please verify that "
6143                                      "you have the right to write to this location or that the "
6144                                      "file is not being used by another application!")
6145                                           .arg(fname));
6146             return;
6147         }
6148 
6149         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
6150 
6151         ((MyWidget *)w)->exportPDF(fname);
6152 
6153         QApplication::restoreOverrideCursor();
6154     }
6155 }
6156 
print(MyWidget * w)6157 void ApplicationWindow::print(MyWidget *w)
6158 {
6159     if (w->inherits("MultiLayer") && ((MultiLayer *)w)->isEmpty()) {
6160         QMessageBox::warning(this, tr("Warning"),
6161                              tr("<h4>There are no plot layers available in this window.</h4>"));
6162         return;
6163     }
6164 
6165     w->print();
6166 }
6167 
6168 // print active window
print()6169 void ApplicationWindow::print()
6170 {
6171     MyWidget *w = (MyWidget *)(d_workspace.activeSubWindow());
6172     if (!w)
6173         return;
6174 
6175     print(w);
6176 }
6177 
6178 // print window from project explorer
printWindow()6179 void ApplicationWindow::printWindow()
6180 {
6181     WindowListItem *it = (WindowListItem *)lv.currentItem();
6182     MyWidget *w = it->window();
6183     if (!w)
6184         return;
6185 
6186     print(w);
6187 }
6188 
printAllPlots()6189 void ApplicationWindow::printAllPlots()
6190 {
6191     QPrinter printer;
6192     printer.setPageOrientation(QPageLayout::Landscape);
6193     printer.setColorMode(QPrinter::Color);
6194     printer.setFullPage(true);
6195 
6196     QList<MyWidget *> windows = windowsList();
6197 
6198     int plots = 0;
6199     for (auto w : windows) {
6200         if (w->inherits("MultiLayer"))
6201             plots++;
6202     }
6203 
6204     QPrintDialog dialog(&printer, this);
6205     dialog.setMinMax(0, plots);
6206     if (dialog.exec()) {
6207         QPainter paint(&printer);
6208 
6209         printer.setFromTo(0, plots);
6210 
6211         for (auto w : windows) {
6212             if (w->inherits("MultiLayer") && printer.newPage())
6213                 ((MultiLayer *)w)->printAllLayers(&paint);
6214         }
6215         paint.end();
6216     }
6217 }
6218 
showExpGrowthDialog()6219 void ApplicationWindow::showExpGrowthDialog()
6220 {
6221     showExpDecayDialog(-1);
6222 }
6223 
showExpDecayDialog()6224 void ApplicationWindow::showExpDecayDialog()
6225 {
6226     showExpDecayDialog(1);
6227 }
6228 
showExpDecayDialog(int type)6229 void ApplicationWindow::showExpDecayDialog(int type)
6230 {
6231     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6232         return;
6233 
6234     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
6235     if (!g || !g->validCurvesDataSize())
6236         return;
6237 
6238     ExpDecayDialog *edd = new ExpDecayDialog(type, this);
6239     edd->setAttribute(Qt::WA_DeleteOnClose);
6240     connect(g, SIGNAL(destroyed()), edd, SLOT(close()));
6241 
6242     edd->setGraph(g);
6243     edd->show();
6244 }
6245 
showTwoExpDecayDialog()6246 void ApplicationWindow::showTwoExpDecayDialog()
6247 {
6248     showExpDecayDialog(2);
6249 }
6250 
showExpDecay3Dialog()6251 void ApplicationWindow::showExpDecay3Dialog()
6252 {
6253     showExpDecayDialog(3);
6254 }
6255 
showFitDialog()6256 void ApplicationWindow::showFitDialog()
6257 {
6258     QWidget *w = d_workspace.activeSubWindow();
6259     if (!w)
6260         return;
6261 
6262     MultiLayer *plot = 0;
6263     if (w->inherits("MultiLayer"))
6264         plot = (MultiLayer *)w;
6265     else if (w->inherits("Table"))
6266         plot = multilayerPlot((Table *)w, ((Table *)w)->drawableColumnSelection(),
6267                               Graph::LineSymbols);
6268 
6269     if (!plot)
6270         return;
6271 
6272     Graph *g = (Graph *)plot->activeGraph();
6273     if (!g || !g->validCurvesDataSize())
6274         return;
6275 
6276     FitDialog *fd = new FitDialog(this);
6277     fd->setAttribute(Qt::WA_DeleteOnClose);
6278     connect(fd, SIGNAL(clearFunctionsList()), this, SLOT(clearFitFunctionsList()));
6279     connect(fd, SIGNAL(saveFunctionsList(const QStringList &)), this,
6280             SLOT(saveFitFunctionsList(const QStringList &)));
6281     connect(plot, SIGNAL(destroyed()), fd, SLOT(close()));
6282 
6283     fd->addUserFunctions(fitFunctions);
6284     fd->setGraph(g);
6285     fd->setSrcTables(tableList());
6286     fd->exec();
6287 }
6288 
showFilterDialog(int filter)6289 void ApplicationWindow::showFilterDialog(int filter)
6290 {
6291     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6292         return;
6293 
6294     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
6295     if (g && g->validCurvesDataSize()) {
6296         FilterDialog *fd = new FilterDialog(filter, this);
6297         fd->setAttribute(Qt::WA_DeleteOnClose);
6298         fd->setGraph(g);
6299         fd->exec();
6300     }
6301 }
6302 
lowPassFilterDialog()6303 void ApplicationWindow::lowPassFilterDialog()
6304 {
6305     showFilterDialog(FFTFilter::LowPass);
6306 }
6307 
highPassFilterDialog()6308 void ApplicationWindow::highPassFilterDialog()
6309 {
6310     showFilterDialog(FFTFilter::HighPass);
6311 }
6312 
bandPassFilterDialog()6313 void ApplicationWindow::bandPassFilterDialog()
6314 {
6315     showFilterDialog(FFTFilter::BandPass);
6316 }
6317 
bandBlockFilterDialog()6318 void ApplicationWindow::bandBlockFilterDialog()
6319 {
6320     showFilterDialog(FFTFilter::BandBlock);
6321 }
6322 
showFFTDialog()6323 void ApplicationWindow::showFFTDialog()
6324 {
6325     QWidget *w = d_workspace.activeSubWindow();
6326     if (!w)
6327         return;
6328 
6329     FFTDialog *sd = 0;
6330     if (w->inherits("MultiLayer")) {
6331         Graph *g = ((MultiLayer *)w)->activeGraph();
6332         if (g && g->validCurvesDataSize()) {
6333             sd = new FFTDialog(FFTDialog::onGraph, this);
6334             sd->setAttribute(Qt::WA_DeleteOnClose);
6335             sd->setGraph(g);
6336         }
6337     } else if (w->inherits("Table")) {
6338         sd = new FFTDialog(FFTDialog::onTable, this);
6339         sd->setAttribute(Qt::WA_DeleteOnClose);
6340         sd->setTable((Table *)w);
6341     }
6342 
6343     if (sd)
6344         sd->exec();
6345 }
6346 
showSmoothDialog(int m)6347 void ApplicationWindow::showSmoothDialog(int m)
6348 {
6349     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6350         return;
6351 
6352     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
6353     if (!g || !g->validCurvesDataSize())
6354         return;
6355 
6356     SmoothCurveDialog *sd = new SmoothCurveDialog(m, this);
6357     sd->setAttribute(Qt::WA_DeleteOnClose);
6358     sd->setGraph(g);
6359     sd->exec();
6360 }
6361 
showSmoothSavGolDialog()6362 void ApplicationWindow::showSmoothSavGolDialog()
6363 {
6364     showSmoothDialog(SmoothFilter::SavitzkyGolay);
6365 }
6366 
showSmoothFFTDialog()6367 void ApplicationWindow::showSmoothFFTDialog()
6368 {
6369     showSmoothDialog(SmoothFilter::FFT);
6370 }
6371 
showSmoothAverageDialog()6372 void ApplicationWindow::showSmoothAverageDialog()
6373 {
6374     showSmoothDialog(SmoothFilter::Average);
6375 }
6376 
showInterpolationDialog()6377 void ApplicationWindow::showInterpolationDialog()
6378 {
6379     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6380         return;
6381 
6382     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
6383     if (!g || !g->validCurvesDataSize())
6384         return;
6385 
6386     InterpolationDialog *id = new InterpolationDialog(this);
6387     id->setAttribute(Qt::WA_DeleteOnClose);
6388     connect(g, SIGNAL(destroyed()), id, SLOT(close()));
6389     id->setGraph(g);
6390     id->show();
6391 }
6392 
showFitPolynomDialog()6393 void ApplicationWindow::showFitPolynomDialog()
6394 {
6395     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6396         return;
6397 
6398     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
6399     if (!g || !g->validCurvesDataSize())
6400         return;
6401 
6402     PolynomFitDialog *pfd = new PolynomFitDialog(this);
6403     pfd->setAttribute(Qt::WA_DeleteOnClose);
6404     connect(g, SIGNAL(destroyed()), pfd, SLOT(close()));
6405     pfd->setGraph(g);
6406     pfd->show();
6407 }
6408 
fitLinear()6409 void ApplicationWindow::fitLinear()
6410 {
6411     analysis("fitLinear");
6412 }
6413 
updateLog(const QString & result)6414 void ApplicationWindow::updateLog(const QString &result)
6415 {
6416     if (!result.isEmpty()) {
6417         logInfo += result;
6418         showResults(true);
6419         emit modified();
6420     }
6421 }
6422 
showIntegrationDialog()6423 void ApplicationWindow::showIntegrationDialog()
6424 {
6425     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6426         return;
6427 
6428     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
6429     if (!g || !g->validCurvesDataSize())
6430         return;
6431 
6432     IntDialog *id = new IntDialog(this);
6433     id->setAttribute(Qt::WA_DeleteOnClose);
6434     connect(g, SIGNAL(destroyed()), id, SLOT(close()));
6435     id->setGraph(g);
6436     id->show();
6437 }
6438 
fitSigmoidal()6439 void ApplicationWindow::fitSigmoidal()
6440 {
6441     analysis("fitSigmoidal");
6442 }
6443 
fitGauss()6444 void ApplicationWindow::fitGauss()
6445 {
6446     analysis("fitGauss");
6447 }
6448 
fitLorentz()6449 void ApplicationWindow::fitLorentz()
6450 
6451 {
6452     analysis("fitLorentz");
6453 }
6454 
differentiate()6455 void ApplicationWindow::differentiate()
6456 {
6457     analysis("differentiate");
6458 }
6459 
showResults(bool ok)6460 void ApplicationWindow::showResults(bool ok)
6461 {
6462     if (ok) {
6463         if (!logInfo.isEmpty())
6464             results->setText(logInfo);
6465         else
6466             results->setText(tr("Sorry, there are no results to display!"));
6467 
6468         logWindow.show();
6469         QTextCursor cur = results->textCursor();
6470         cur.movePosition(QTextCursor::End);
6471         results->setTextCursor(cur);
6472     } else
6473         logWindow.hide();
6474 }
6475 
showResults(const QString & s,bool ok)6476 void ApplicationWindow::showResults(const QString &s, bool ok)
6477 {
6478     logInfo += s;
6479     if (!logInfo.isEmpty())
6480         results->setText(logInfo);
6481     showResults(ok);
6482 }
6483 
showScreenReader()6484 void ApplicationWindow::showScreenReader()
6485 {
6486     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6487         return;
6488 
6489     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6490     if (plot->isEmpty()) {
6491         QMessageBox::warning(this, tr("Warning"),
6492                              tr("<h4>There are no plot layers available in this window.</h4>"
6493                                 "<p><h4>Please add a layer and try again!</h4>"));
6494         btnPointer->setChecked(true);
6495         return;
6496     }
6497 
6498     QWidgetList graphsList = plot->graphPtrs();
6499     foreach (QWidget *w, graphsList)
6500         ((Graph *)w)
6501                 ->setActiveTool(new ScreenPickerTool((Graph *)w, d_status_info,
6502                                                      SLOT(setText(const QString &))));
6503 }
6504 
showRangeSelectors()6505 void ApplicationWindow::showRangeSelectors()
6506 {
6507     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6508         return;
6509 
6510     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6511     if (plot->isEmpty()) {
6512         QMessageBox::warning(this, tr("Warning"),
6513                              tr("There are no plot layers available in this window!"));
6514         btnPointer->setChecked(true);
6515         return;
6516     }
6517 
6518     Graph *g = (Graph *)plot->activeGraph();
6519     if (!g)
6520         return;
6521 
6522     if (!g->curves()) {
6523         QMessageBox::warning(this, tr("Warning"),
6524                              tr("There are no curves available on this plot!"));
6525         btnPointer->setChecked(true);
6526         return;
6527     } else if (g->isPiePlot()) {
6528         QMessageBox::warning(this, tr("Warning"),
6529                              tr("This functionality is not available for pie plots!"));
6530         btnPointer->setChecked(true);
6531         return;
6532     }
6533 
6534     g->enableRangeSelectors(d_status_info, SLOT(setText(const QString &)));
6535 }
6536 
showCursor()6537 void ApplicationWindow::showCursor()
6538 {
6539     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6540         return;
6541 
6542     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6543     if (plot->isEmpty()) {
6544         QMessageBox::warning(this, tr("Warning"),
6545                              tr("<h4>There are no plot layers available in this window.</h4>"
6546                                 "<p><h4>Please add a layer and try again!</h4>"));
6547         btnPointer->setChecked(true);
6548         return;
6549     }
6550 
6551     if ((Graph *)plot->activeGraph()->isPiePlot()) {
6552         QMessageBox::warning(this, tr("Warning"),
6553                              tr("This functionality is not available for pie plots!"));
6554 
6555         btnPointer->setChecked(true);
6556         return;
6557     }
6558 
6559     QWidgetList graphsList = plot->graphPtrs();
6560     foreach (QWidget *w, graphsList)
6561         if (!((Graph *)w)->isPiePlot() && ((Graph *)w)->validCurvesDataSize())
6562             ((Graph *)w)
6563                     ->setActiveTool(new DataPickerTool((Graph *)w, this, DataPickerTool::Display,
6564                                                        d_status_info,
6565                                                        SLOT(setText(const QString &))));
6566 }
6567 
newLegend()6568 void ApplicationWindow::newLegend()
6569 {
6570     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6571         return;
6572 
6573     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6574     if (plot->isEmpty()) {
6575         QMessageBox::warning(this, tr("Warning"),
6576                              tr("<h4>There are no plot layers available in this window.</h4>"
6577                                 "<p><h4>Please add a layer and try again!</h4>"));
6578         return;
6579     }
6580 
6581     Graph *g = (Graph *)plot->activeGraph();
6582     if (g)
6583         g->newLegend();
6584 }
6585 
addTimeStamp()6586 void ApplicationWindow::addTimeStamp()
6587 {
6588     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6589         return;
6590 
6591     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6592     if (plot->isEmpty()) {
6593         QMessageBox::warning(this, tr("Warning"),
6594                              tr("<h4>There are no plot layers available in this window.</h4>"
6595                                 "<p><h4>Please add a layer and try again!</h4>"));
6596         return;
6597     }
6598 
6599     Graph *g = (Graph *)plot->activeGraph();
6600     if (g)
6601         g->addTimeStamp();
6602 }
6603 
disableAddText()6604 void ApplicationWindow::disableAddText()
6605 {
6606     actionAddText->setChecked(false);
6607     showTextDialog();
6608 }
6609 
addText()6610 void ApplicationWindow::addText()
6611 {
6612     if (!btnPointer->isChecked())
6613         btnPointer->setChecked(true);
6614 
6615     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6616         return;
6617 
6618     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6619 
6620     switch (QMessageBox::information(
6621             this, tr("Add new layer?"),
6622             tr("Do you want to add the text on a new layer or on the active layer?"),
6623             tr("On &New Layer"), tr("On &Active Layer"), tr("&Cancel"), 0, 2)) {
6624     case 0:
6625         plot->addTextLayer(legendFrameStyle, plotLegendFont, legendTextColor, legendBackground);
6626         break;
6627 
6628     case 1: {
6629         if (plot->isEmpty()) {
6630             QMessageBox::warning(this, tr("Warning"),
6631                                  tr("<h4>There are no plot layers available in this window.</h4>"
6632                                     "<p><h4>Please add a layer and try again!</h4>"));
6633 
6634             actionAddText->setChecked(false);
6635             return;
6636         }
6637 
6638         Graph *g = (Graph *)plot->activeGraph();
6639         if (g)
6640             g->drawText(true);
6641     } break;
6642 
6643     case 2:
6644         actionAddText->setChecked(false);
6645         return;
6646         break;
6647     }
6648 }
6649 
addImage()6650 void ApplicationWindow::addImage()
6651 {
6652     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6653         return;
6654 
6655     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6656     if (plot->isEmpty()) {
6657         QMessageBox::warning(this, tr("Warning"),
6658                              tr("<h4>There are no plot layers available in this window.</h4>"
6659                                 "<p><h4>Please add a layer and try again!</h4>"));
6660         return;
6661     }
6662 
6663     Graph *g = (Graph *)plot->activeGraph();
6664     if (!g)
6665         return;
6666 
6667     QList<QByteArray> list = QImageReader::supportedImageFormats();
6668     QString filter = tr("Images") + " (", aux1, aux2;
6669     for (int i = 0; i < (int)list.count(); i++) {
6670         aux1 = " *." + list[i] + " ";
6671         aux2 += " *." + list[i] + ";;";
6672         filter += aux1;
6673     }
6674     filter += ");;" + aux2;
6675 
6676     QString fn =
6677             QFileDialog::getOpenFileName(this, tr("Insert image from file"), imagesDirPath, filter);
6678     if (!fn.isEmpty()) {
6679         QFileInfo fi(fn);
6680         imagesDirPath = fi.absolutePath();
6681 
6682         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
6683         g->addImage(fn);
6684         QApplication::restoreOverrideCursor();
6685     }
6686 }
6687 
drawLine()6688 void ApplicationWindow::drawLine()
6689 {
6690     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6691         return;
6692 
6693     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6694     if (plot->isEmpty()) {
6695         QMessageBox::warning(this, tr("Warning"),
6696                              tr("<h4>There are no plot layers available in this window.</h4>"
6697                                 "<p><h4>Please add a layer and try again!</h4>"));
6698 
6699         btnPointer->setChecked(true);
6700         return;
6701     }
6702 
6703     Graph *g = (Graph *)plot->activeGraph();
6704     if (g) {
6705         g->drawLine(true);
6706         emit modified();
6707     }
6708 }
6709 
drawArrow()6710 void ApplicationWindow::drawArrow()
6711 {
6712     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6713         return;
6714 
6715     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6716     if (plot->isEmpty()) {
6717         QMessageBox::warning(this, tr("Warning"),
6718                              tr("<h4>There are no plot layers available in this window.</h4>"
6719                                 "<p><h4>Please add a layer and try again!</h4>"));
6720 
6721         btnPointer->setChecked(true);
6722         return;
6723     }
6724 
6725     Graph *g = (Graph *)plot->activeGraph();
6726     if (g) {
6727         g->drawLine(true, 1);
6728         emit modified();
6729     }
6730 }
6731 
showImageDialog()6732 void ApplicationWindow::showImageDialog()
6733 {
6734     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6735         return;
6736 
6737     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
6738     if (g) {
6739         ImageMarker *im = (ImageMarker *)g->selectedMarkerPtr();
6740         if (!im)
6741             return;
6742 
6743         ImageDialog *id = new ImageDialog(this);
6744         id->setAttribute(Qt::WA_DeleteOnClose);
6745         connect(id, SIGNAL(setGeometry(int, int, int, int)), g,
6746                 SLOT(updateImageMarker(int, int, int, int)));
6747         id->setWindowIcon(QPixmap(":/appicon"));
6748         id->setOrigin(im->origin());
6749         id->setSize(im->size());
6750         id->exec();
6751     }
6752 }
6753 
showLayerDialog()6754 void ApplicationWindow::showLayerDialog()
6755 {
6756     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6757         return;
6758 
6759     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6760     if (plot->isEmpty()) {
6761         QMessageBox::warning(this, tr("Warning"),
6762                              tr("There are no plot layers available in this window."));
6763         return;
6764     }
6765 
6766     LayerDialog *id = new LayerDialog(this);
6767     id->setAttribute(Qt::WA_DeleteOnClose);
6768     id->setMultiLayer(plot);
6769     id->exec();
6770 }
6771 
showPlotGeometryDialog()6772 void ApplicationWindow::showPlotGeometryDialog()
6773 {
6774     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6775         return;
6776 
6777     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
6778     Graph *g = plot->activeGraph();
6779     if (g) {
6780         ImageDialog *id = new ImageDialog(this);
6781         id->setAttribute(Qt::WA_DeleteOnClose);
6782         connect(id, SIGNAL(setGeometry(int, int, int, int)), plot,
6783                 SLOT(setGraphGeometry(int, int, int, int)));
6784         id->setWindowIcon(QPixmap(":/appicon"));
6785         id->setWindowTitle(tr("Layer Geometry"));
6786         id->setOrigin(g->pos());
6787         id->setSize(g->plotWidget()->size());
6788         id->exec();
6789     }
6790 }
6791 
showTextDialog()6792 void ApplicationWindow::showTextDialog()
6793 {
6794     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6795         return;
6796 
6797     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
6798     if (g) {
6799         Legend *m = (Legend *)g->selectedMarkerPtr();
6800         if (!m)
6801             return;
6802 
6803         TextDialog *td = new TextDialog(TextDialog::TextMarker, this, Qt::Widget);
6804         td->setAttribute(Qt::WA_DeleteOnClose);
6805         connect(td,
6806                 SIGNAL(values(const QString &, int, int, const QFont &, const QColor &,
6807                               const QColor &)),
6808                 g,
6809                 SLOT(updateTextMarker(const QString &, int, int, const QFont &, const QColor &,
6810                                       const QColor &)));
6811 
6812         td->setWindowIcon(QPixmap(":/appicon"));
6813         td->setText(m->text());
6814         td->setFont(m->font());
6815         td->setTextColor(m->textColor());
6816         td->setBackgroundColor(m->backgroundColor());
6817         td->setBackgroundType(m->frameStyle());
6818         td->setAngle(m->angle());
6819         td->exec();
6820     }
6821 }
6822 
showLineDialog()6823 void ApplicationWindow::showLineDialog()
6824 {
6825     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
6826         return;
6827 
6828     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
6829     if (g) {
6830         ArrowMarker *lm = (ArrowMarker *)g->selectedMarkerPtr();
6831         if (!lm)
6832             return;
6833 
6834         LineDialog *ld = new LineDialog(lm, this);
6835         ld->setAttribute(Qt::WA_DeleteOnClose);
6836         ld->exec();
6837     }
6838 }
6839 
addColToTable()6840 void ApplicationWindow::addColToTable()
6841 {
6842     Table *m = (Table *)d_workspace.activeSubWindow();
6843     if (m)
6844         m->addCol();
6845 }
6846 
clearSelection()6847 void ApplicationWindow::clearSelection()
6848 {
6849     if (lv.hasFocus()) {
6850         deleteSelectedItems();
6851         return;
6852     }
6853 
6854     QWidget *m = (QWidget *)d_workspace.activeSubWindow();
6855     if (!m)
6856         return;
6857 
6858     if (m->inherits("Table"))
6859         ((Table *)m)->clearSelection();
6860     else if (m->inherits("Matrix"))
6861         ((Matrix *)m)->clearSelection();
6862     else if (m->inherits("MultiLayer")) {
6863         Graph *g = ((MultiLayer *)m)->activeGraph();
6864         if (!g)
6865             return;
6866 
6867         if (g->titleSelected())
6868             g->removeTitle();
6869         else if (g->markerSelected())
6870             g->removeMarker();
6871     } else if (m->inherits("Note"))
6872         ((Note *)m)->textWidget()->clear();
6873     emit modified();
6874 }
6875 
copySelection()6876 void ApplicationWindow::copySelection()
6877 {
6878     if (results->hasFocus()) {
6879         results->copy();
6880         return;
6881     }
6882 
6883     QWidget *m = (QWidget *)d_workspace.activeSubWindow();
6884     if (!m)
6885         return;
6886 
6887     if (m->inherits("Table"))
6888         ((Table *)m)->copySelection();
6889     else if (m->inherits("Matrix"))
6890         ((Matrix *)m)->copySelection();
6891     else if (m->inherits("MultiLayer")) {
6892         MultiLayer *plot = (MultiLayer *)m;
6893         if (!plot || plot->layers() == 0)
6894             return;
6895 
6896         Graph *g = (Graph *)plot->activeGraph();
6897         if (!g)
6898             return;
6899         if (g->markerSelected())
6900             copyMarker();
6901         else
6902             copyActiveLayer();
6903     } else if (m->inherits("Note"))
6904         ((Note *)m)->textWidget()->copy();
6905 }
6906 
cutSelection()6907 void ApplicationWindow::cutSelection()
6908 {
6909     QWidget *m = (QWidget *)d_workspace.activeSubWindow();
6910     if (!m)
6911         return;
6912 
6913     if (m->inherits("Table"))
6914         ((Table *)m)->cutSelection();
6915     else if (m->inherits("Matrix"))
6916         ((Matrix *)m)->cutSelection();
6917     else if (m->inherits("MultiLayer")) {
6918         MultiLayer *plot = (MultiLayer *)m;
6919         if (!plot || plot->layers() == 0)
6920             return;
6921 
6922         Graph *g = (Graph *)plot->activeGraph();
6923         if (!g)
6924             return;
6925         if (g->markerSelected()) {
6926             copyMarker();
6927             g->removeMarker();
6928         } else {
6929             copyActiveLayer();
6930             plot->removeLayer();
6931         }
6932     } else if (m->inherits("Note"))
6933         ((Note *)m)->textWidget()->cut();
6934 
6935     emit modified();
6936 }
6937 
copyMarker()6938 void ApplicationWindow::copyMarker()
6939 {
6940     QWidget *m = (QWidget *)d_workspace.activeSubWindow();
6941     MultiLayer *plot = (MultiLayer *)m;
6942     Graph *g = (Graph *)plot->activeGraph();
6943     if (g && g->markerSelected()) {
6944         g->copyMarker();
6945         copiedMarkerType = g->copiedMarkerType();
6946         QRect rect = g->copiedMarkerRect();
6947         auxMrkStart = rect.topLeft();
6948         auxMrkEnd = rect.bottomRight();
6949 
6950         if (copiedMarkerType == Graph::Text) {
6951             Legend *m = (Legend *)g->selectedMarkerPtr();
6952             auxMrkText = m->text();
6953             auxMrkColor = m->textColor();
6954             auxMrkFont = m->font();
6955             auxMrkBkg = m->frameStyle();
6956             auxMrkBkgColor = m->backgroundColor();
6957         } else if (copiedMarkerType == Graph::Arrow) {
6958             ArrowMarker *m = (ArrowMarker *)g->selectedMarkerPtr();
6959             auxMrkWidth = m->width();
6960             auxMrkColor = m->color();
6961             auxMrkStyle = m->style();
6962             startArrowOn = m->hasStartArrow();
6963             endArrowOn = m->hasEndArrow();
6964             arrowHeadLength = m->headLength();
6965             arrowHeadAngle = m->headAngle();
6966             fillArrowHead = m->filledArrowHead();
6967         } else if (copiedMarkerType == Graph::Image) {
6968             ImageMarker *im = (ImageMarker *)g->selectedMarkerPtr();
6969             if (im)
6970                 auxMrkFileName = im->fileName();
6971         }
6972     }
6973     copiedLayer = false;
6974 }
6975 
pasteSelection()6976 void ApplicationWindow::pasteSelection()
6977 {
6978     QWidget *m = (QWidget *)d_workspace.activeSubWindow();
6979     if (!m)
6980         return;
6981 
6982     if (m->inherits("Table"))
6983         ((Table *)m)->pasteSelection();
6984     else if (m->inherits("Matrix"))
6985         ((Matrix *)m)->pasteSelection();
6986     else if (m->inherits("Note"))
6987         ((Note *)m)->textWidget()->paste();
6988     else if (m->inherits("MultiLayer")) {
6989         MultiLayer *plot = (MultiLayer *)m;
6990         if (!plot)
6991             return;
6992         if (copiedLayer) {
6993             QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
6994 
6995             Graph *g = plot->addLayer();
6996             setPreferences(g);
6997             g->copy(this, lastCopiedLayer);
6998             QPoint pos = plot->mapFromGlobal(QCursor::pos());
6999             plot->setGraphGeometry(pos.x(), pos.y() - 20, lastCopiedLayer->width(),
7000                                    lastCopiedLayer->height());
7001 
7002             QApplication::restoreOverrideCursor();
7003         } else {
7004             if (plot->layers() == 0)
7005                 return;
7006 
7007             Graph *g = (Graph *)plot->activeGraph();
7008             if (!g)
7009                 return;
7010 
7011             g->setCopiedMarkerType(copiedMarkerType);
7012             g->setCopiedMarkerEnds(auxMrkStart, auxMrkEnd);
7013 
7014             if (copiedMarkerType == Graph::Text)
7015                 g->setCopiedTextOptions(auxMrkBkg, auxMrkText, auxMrkFont, auxMrkColor,
7016                                         auxMrkBkgColor);
7017             if (copiedMarkerType == Graph::Arrow)
7018                 g->setCopiedArrowOptions(auxMrkWidth, auxMrkStyle, auxMrkColor, startArrowOn,
7019                                          endArrowOn, arrowHeadLength, arrowHeadAngle,
7020                                          fillArrowHead);
7021             if (copiedMarkerType == Graph::Image)
7022                 g->setCopiedImageName(auxMrkFileName);
7023             g->pasteMarker();
7024         }
7025     }
7026     emit modified();
7027 }
7028 
clone()7029 MyWidget *ApplicationWindow::clone()
7030 {
7031     MyWidget *w = (MyWidget *)d_workspace.activeSubWindow();
7032     if (!w) {
7033         QMessageBox::critical(this, tr("Duplicate window error"),
7034                               tr("There are no windows available in this project!"));
7035         return 0;
7036     }
7037 
7038     return clone(w);
7039 }
7040 
clone(MyWidget * w)7041 MyWidget *ApplicationWindow::clone(MyWidget *w)
7042 {
7043     if (!w)
7044         return 0;
7045 
7046     MyWidget *nw = 0;
7047     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
7048 
7049     if (w->inherits("MultiLayer")) {
7050         nw = multilayerPlot(generateUniqueName(tr("Graph")));
7051         ((MultiLayer *)nw)->copy(this, (MultiLayer *)w);
7052     } else if (w->inherits("Table")) {
7053         Table *t = (Table *)w;
7054         QString caption = generateUniqueName(tr("Table"));
7055         nw = newTable(caption, t->numRows(), t->numCols());
7056         ((Table *)nw)->copy(t);
7057     } else if (w->inherits("Graph3D")) {
7058         Graph3D *g = (Graph3D *)w;
7059         if (!g->hasData()) {
7060             QApplication::restoreOverrideCursor();
7061             QMessageBox::warning(this, tr("Duplicate error"),
7062                                  tr("Empty 3D surface plots cannot be duplicated!"));
7063             return 0;
7064         }
7065 
7066         QString caption = generateUniqueName(tr("Graph"));
7067         QString s = g->formula();
7068         if (g->userFunction())
7069             nw = newPlot3D(caption, s, g->xStart(), g->xStop(), g->yStart(), g->yStop(),
7070                            g->zStart(), g->zStop());
7071         else if (s.endsWith("(Z)"))
7072             nw = dataPlotXYZ(caption, s, g->xStart(), g->xStop(), g->yStart(), g->yStop(),
7073                              g->zStart(), g->zStop());
7074         else if (s.endsWith("(Y)")) // Ribbon plot
7075             nw = dataPlot3D(caption, s, g->xStart(), g->xStop(), g->yStart(), g->yStop(),
7076                             g->zStart(), g->zStop());
7077         else
7078             nw = openMatrixPlot3D(caption, s, g->xStart(), g->xStop(), g->yStart(), g->yStop(),
7079                                   g->zStart(), g->zStop());
7080 
7081         if (!nw)
7082             return 0;
7083 
7084         ((Graph3D *)nw)->copy(g);
7085         customToolBars((MyWidget *)nw);
7086     } else if (w->inherits("Matrix")) {
7087         nw = newMatrix(((Matrix *)w)->numRows(), ((Matrix *)w)->numCols());
7088         ((Matrix *)nw)->copy((Matrix *)w);
7089     } else if (w->inherits("Note")) {
7090         nw = newNote();
7091         if (nw)
7092             ((Note *)nw)->setText(((Note *)w)->text());
7093     }
7094 
7095     if (nw) {
7096         if (w->inherits("MultiLayer")) {
7097             if (w->status() == MyWidget::Maximized)
7098                 nw->showMaximized();
7099         } else if (w->inherits("Graph3D")) {
7100             ((Graph3D *)nw)->setIgnoreFonts(true);
7101             if (w->status() == MyWidget::Maximized) {
7102                 w->showNormal();
7103                 w->resize(500, 400);
7104                 nw->resize(w->size());
7105                 nw->showMaximized();
7106             } else
7107                 nw->resize(w->size());
7108             ((Graph3D *)nw)->setIgnoreFonts(false);
7109         } else {
7110             nw->resize(w->size());
7111             nw->showNormal();
7112         }
7113 
7114         nw->setWindowLabel(w->windowLabel());
7115         nw->setCaptionPolicy(w->captionPolicy());
7116         setListViewLabel(nw->name(), w->windowLabel());
7117     }
7118     QApplication::restoreOverrideCursor();
7119     return nw;
7120 }
7121 
undo()7122 void ApplicationWindow::undo()
7123 {
7124     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
7125     d_project->undoStack()->undo();
7126     QApplication::restoreOverrideCursor();
7127 }
7128 
redo()7129 void ApplicationWindow::redo()
7130 {
7131     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
7132     d_project->undoStack()->redo();
7133     QApplication::restoreOverrideCursor();
7134 }
7135 
hidden(MyWidget * window)7136 bool ApplicationWindow::hidden(MyWidget *window)
7137 {
7138     if (hiddenWindows.contains(window) || outWindows.contains(window))
7139         return true;
7140 
7141     return false;
7142 }
7143 
updateWindowStatus(MyWidget * w)7144 void ApplicationWindow::updateWindowStatus(MyWidget *w)
7145 {
7146     setListView(w->name(), w->aspect());
7147     if (w->status() == MyWidget::Maximized) {
7148         QList<MyWidget *> windows = current_folder->windowsList();
7149         foreach (MyWidget *oldMaxWindow, windows) {
7150             if (oldMaxWindow != w && oldMaxWindow->status() == MyWidget::Maximized)
7151                 oldMaxWindow->setStatus(MyWidget::Normal);
7152         }
7153     }
7154 }
7155 
hideActiveWindow()7156 void ApplicationWindow::hideActiveWindow()
7157 {
7158     MyWidget *w = (MyWidget *)d_workspace.activeSubWindow();
7159     if (!w)
7160         return;
7161 
7162     hideWindow(w);
7163 }
7164 
hideWindow(MyWidget * w)7165 void ApplicationWindow::hideWindow(MyWidget *w)
7166 {
7167     hiddenWindows.append(w);
7168     w->setHidden();
7169     emit modified();
7170 }
7171 
resizeActiveWindow()7172 void ApplicationWindow::resizeActiveWindow()
7173 {
7174     MyWidget *w = qobject_cast<MyWidget *>(d_workspace.activeSubWindow());
7175     if (!w)
7176         return;
7177 
7178     ImageDialog *id = new ImageDialog(this);
7179     id->setAttribute(Qt::WA_DeleteOnClose);
7180     connect(id, SIGNAL(setGeometry(int, int, int, int)), this,
7181             SLOT(setWindowGeometry(int, int, int, int)));
7182 
7183     id->setWindowTitle(tr("Window Geometry"));
7184     id->setOrigin(w->pos());
7185     id->setSize(w->size());
7186     id->exec();
7187 }
7188 
resizeWindow()7189 void ApplicationWindow::resizeWindow()
7190 {
7191     MyWidget *w = qobject_cast<MyWidget *>(d_workspace.activeSubWindow());
7192     if (!w)
7193         return;
7194 
7195     d_workspace.setActiveSubWindow(w);
7196 
7197     ImageDialog *id = new ImageDialog(this);
7198     id->setAttribute(Qt::WA_DeleteOnClose);
7199     connect(id, SIGNAL(setGeometry(int, int, int, int)), this,
7200             SLOT(setWindowGeometry(int, int, int, int)));
7201 
7202     id->setWindowTitle(tr("Window Geometry"));
7203     id->setOrigin(w->pos());
7204     id->setSize(w->size());
7205     id->exec();
7206 }
7207 
setWindowGeometry(int x,int y,int w,int h)7208 void ApplicationWindow::setWindowGeometry(int x, int y, int w, int h)
7209 {
7210     d_workspace.activeSubWindow()->setGeometry(x, y, w, h);
7211 }
7212 
activateSubWindow()7213 void ApplicationWindow::activateSubWindow()
7214 {
7215     setWindowState(Qt::WindowActive);
7216     raise();
7217     show();
7218     WindowListItem *it = (WindowListItem *)lv.currentItem();
7219     activateSubWindow(it->window());
7220 }
7221 
activateSubWindow(MyWidget * w)7222 void ApplicationWindow::activateSubWindow(MyWidget *w)
7223 {
7224     if (!w)
7225         return;
7226 
7227     w->setNormal();
7228     d_workspace.setActiveSubWindow(w);
7229 
7230     updateWindowLists(w);
7231     emit modified();
7232 }
7233 
maximizeWindow()7234 void ApplicationWindow::maximizeWindow()
7235 {
7236     MyWidget *w = qobject_cast<MyWidget *>(d_workspace.activeSubWindow());
7237     if (!w)
7238         return;
7239 
7240     updateWindowLists(w);
7241     w->setMaximized();
7242     emit modified();
7243 }
7244 
minimizeWindow()7245 void ApplicationWindow::minimizeWindow()
7246 {
7247     MyWidget *w = qobject_cast<MyWidget *>(d_workspace.activeSubWindow());
7248     if (!w)
7249         return;
7250 
7251     updateWindowLists(w);
7252     w->setMinimized();
7253     emit modified();
7254 }
7255 
updateWindowLists(MyWidget * w)7256 void ApplicationWindow::updateWindowLists(MyWidget *w)
7257 {
7258     if (!w)
7259         return;
7260 
7261     if (hiddenWindows.contains(w))
7262         hiddenWindows.takeAt(hiddenWindows.indexOf(w));
7263     else if (outWindows.contains(w)) {
7264         outWindows.takeAt(outWindows.indexOf(w));
7265         d_workspace.addSubWindow(w);
7266         w->setAttribute(Qt::WA_DeleteOnClose);
7267     }
7268 }
7269 
closeActiveWindow()7270 void ApplicationWindow::closeActiveWindow()
7271 {
7272     QWidget *w = (QWidget *)d_workspace.activeSubWindow();
7273     if (w)
7274         w->close();
7275 }
7276 
removeWindowFromLists(MyWidget * w)7277 void ApplicationWindow::removeWindowFromLists(MyWidget *w)
7278 {
7279     if (!w)
7280         return;
7281 
7282     QString caption = w->name();
7283     if (w->inherits("Table")) {
7284         Table *m = (Table *)w;
7285         for (int i = 0; i < m->numCols(); i++) {
7286             QString name = m->colName(i);
7287             removeCurves(name);
7288         }
7289         if (w == lastModified) {
7290             actionUndo->setEnabled(false);
7291             actionRedo->setEnabled(false);
7292         }
7293     } else if (w->inherits("MultiLayer")) {
7294         MultiLayer *ml = (MultiLayer *)w;
7295         Graph *g = ml->activeGraph();
7296         if (g)
7297             btnPointer->setChecked(true);
7298     } else if (w->inherits("Matrix"))
7299         remove3DMatrixPlots((Matrix *)w);
7300 
7301     if (hiddenWindows.contains(w))
7302         hiddenWindows.takeAt(hiddenWindows.indexOf(w));
7303     else if (outWindows.contains(w))
7304         outWindows.takeAt(outWindows.indexOf(w));
7305 }
7306 
closeWindow(MyWidget * window)7307 void ApplicationWindow::closeWindow(MyWidget *window)
7308 {
7309     if (!window)
7310         return;
7311 
7312     removeWindowFromLists(window);
7313     window->folder()->removeWindow(window);
7314 
7315     // update list view in project explorer
7316     QTreeWidgetItem *it =
7317             lv.findItems(window->name(), Qt::MatchExactly | Qt::MatchCaseSensitive).at(0);
7318     if (it)
7319         lv.takeTopLevelItem(lv.indexOfTopLevelItem(it));
7320 
7321     if (window->inherits("Matrix"))
7322         window->setParent(0);
7323     else if (window->inherits("Table"))
7324         window->setParent(0);
7325     else
7326         window->deleteLater();
7327     emit modified();
7328 }
7329 
about()7330 void ApplicationWindow::about()
7331 {
7332     SciDAVis::about();
7333 }
7334 
windowsMenuAboutToShow()7335 void ApplicationWindow::windowsMenuAboutToShow()
7336 {
7337     QList<QMdiSubWindow *> windows = d_workspace.subWindowList();
7338     int n = int(windows.count());
7339     if (!n)
7340         return;
7341 
7342     windowsMenu->clear();
7343     windowsMenu->addAction(tr("&Cascade"), this, SLOT(cascade()));
7344     windowsMenu->addAction(tr("&Tile"), &d_workspace, SLOT(tileSubWindows()));
7345     windowsMenu->addSeparator();
7346     windowsMenu->addAction(actionNextWindow);
7347     windowsMenu->addAction(actionPrevWindow);
7348     windowsMenu->addSeparator();
7349     windowsMenu->addAction(actionRename);
7350     windowsMenu->addAction(actionCopyWindow);
7351     windowsMenu->addSeparator();
7352     windowsMenu->addAction(actionResizeActiveWindow);
7353     windowsMenu->addAction(tr("&Hide Window"), this, SLOT(hideActiveWindow()));
7354     windowsMenu->addAction(QPixmap(":/close.xpm"), tr("Close &Window"), this,
7355                            SLOT(closeActiveWindow()), Qt::CTRL + Qt::Key_W);
7356 
7357     if (n > 0 && n < 10) {
7358         windowsMenu->addSeparator();
7359         for (int i = 0; i < n; ++i) {
7360             MyWidget *widget = qobject_cast<MyWidget *>(windows.at(i));
7361             if (!widget)
7362                 continue;
7363             QAction *actId =
7364                     windowsMenu->addAction(widget->name(), this, SLOT(windowsMenuActivated(bool)));
7365             actId->setData(i);
7366             actId->setCheckable(true);
7367             actId->setChecked(d_workspace.activeSubWindow() == windows.at(i));
7368         }
7369     } else if (n >= 10) {
7370         windowsMenu->addSeparator();
7371         for (int i = 0; i < 9; ++i) {
7372             MyWidget *widget = qobject_cast<MyWidget *>(windows.at(i));
7373             if (!widget)
7374                 continue;
7375             QAction *actId =
7376                     windowsMenu->addAction(widget->name(), this, SLOT(windowsMenuActivated(bool)));
7377             actId->setData(i);
7378             actId->setCheckable(true);
7379             actId->setChecked(d_workspace.activeSubWindow() == windows.at(i));
7380         }
7381         windowsMenu->addSeparator();
7382         windowsMenu->addAction(tr("More windows..."), this, SLOT(showMoreWindows()));
7383     }
7384 }
7385 
showMarkerPopupMenuImpl()7386 QMenu *ApplicationWindow::showMarkerPopupMenuImpl()
7387 {
7388     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
7389         return nullptr;
7390 
7391     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
7392     auto markerMenu = new QMenu(this);
7393 
7394     if (g->imageMarkerSelected()) {
7395         markerMenu->addAction(QPixmap(":/pixelProfile.xpm"), tr("&View Pixel Line profile"), this,
7396                               SLOT(pixelLineProfile()));
7397         markerMenu->addAction(tr("&Intensity Matrix"), this, SLOT(intensityTable()));
7398         markerMenu->addSeparator();
7399     }
7400 
7401     markerMenu->addAction(IconLoader::load("edit-cut"), tr("&Cut"), this, SLOT(cutSelection()));
7402     markerMenu->addAction(IconLoader::load("edit-copy"), tr("&Copy"), this, SLOT(copySelection()));
7403     markerMenu->addAction(QPixmap(":/erase.xpm"), tr("&Delete"), this, SLOT(clearSelection()));
7404     markerMenu->addSeparator();
7405     if (g->arrowMarkerSelected())
7406         markerMenu->addAction(tr("&Properties..."), this, SLOT(showLineDialog()));
7407     else if (g->imageMarkerSelected())
7408         markerMenu->addAction(tr("&Properties..."), this, SLOT(showImageDialog()));
7409     else
7410         markerMenu->addAction(tr("&Properties..."), this, SLOT(showTextDialog()));
7411 
7412     return markerMenu;
7413 }
7414 
showMoreWindows()7415 void ApplicationWindow::showMoreWindows()
7416 {
7417     if (explorerWindow.isVisible())
7418         QMessageBox::information(this, "SciDAVis",
7419                                  tr("Please use the project explorer to select a window!"));
7420     else
7421         explorerWindow.show();
7422 }
7423 
windowsMenuActivated(bool checked)7424 void ApplicationWindow::windowsMenuActivated(bool checked)
7425 {
7426     Q_UNUSED(checked)
7427 
7428     QAction *act = qobject_cast<QAction *>(sender());
7429     if (!act)
7430         return;
7431     int id = act->data().toInt();
7432 
7433     QList<QMdiSubWindow *> windows = d_workspace.subWindowList();
7434     MyWidget *w = qobject_cast<MyWidget *>(windows.at(id));
7435     if (w) {
7436         w->showNormal();
7437         w->setFocus();
7438         if (hidden(w)) {
7439             hiddenWindows.takeAt(hiddenWindows.indexOf(w));
7440             setListView(w->name(), tr("Normal"));
7441         }
7442     }
7443 }
7444 
newProject()7445 void ApplicationWindow::newProject()
7446 {
7447     saveSettings(); // the recent projects must be saved
7448 
7449     ApplicationWindow *ed = new ApplicationWindow();
7450     ed->applyUserSettings();
7451     ed->newTable();
7452 
7453     if (this->isMaximized())
7454         ed->showMaximized();
7455     else
7456         ed->show();
7457 
7458     ed->savedProject();
7459 
7460     this->close();
7461 }
7462 
savedProject()7463 void ApplicationWindow::savedProject()
7464 {
7465     actionSaveProject->setEnabled(false);
7466     saved = true;
7467     d_project->undoStack()->clear();
7468 }
7469 
modifiedProject()7470 void ApplicationWindow::modifiedProject()
7471 {
7472     actionSaveProject->setEnabled(true);
7473     saved = false;
7474 }
7475 
modifiedProject(MyWidget * w)7476 void ApplicationWindow::modifiedProject(MyWidget *w)
7477 {
7478     modifiedProject();
7479 
7480     actionUndo->setEnabled(true);
7481     lastModified = w;
7482 }
7483 
timerEvent(QTimerEvent * e)7484 void ApplicationWindow::timerEvent(QTimerEvent *e)
7485 {
7486     if (e->timerId() == savingTimerId)
7487         saveProject();
7488     else
7489         QWidget::timerEvent(e);
7490 }
7491 
dropEvent(QDropEvent * e)7492 void ApplicationWindow::dropEvent(QDropEvent *e)
7493 {
7494     if (e->mimeData()->hasUrls()) {
7495         QStringList asciiFiles;
7496         QList<QUrl> urls = e->mimeData()->urls();
7497 
7498         foreach (QUrl url, urls) {
7499             QString fileName = url.toLocalFile();
7500             QFileInfo fileInfo(fileName);
7501             QString ext = fileInfo.completeSuffix().toLower();
7502 
7503             if (ext == "sciprj" || ext == "sciprj~" || ext == "sciprj.gz" || ext == "sciprj.gz~"
7504                 || ext == "opj" || ext == "qti" || ext == "qti.gz" || ext == "ogm" || ext == "ogw"
7505                 || ext == "ogg" || ext == "org") {
7506                 open(fileName);
7507             } else if (ext == "csv" || ext == "dat" || ext == "txt" || ext == "tsv") {
7508                 asciiFiles << fileName;
7509             } else if (ext == "bmp" || ext == "bw" || ext == "eps" || ext == "epsf" || ext == "epsi"
7510                        || ext == "exr" || ext == "kra" || ext == "ora" || ext == "pcx"
7511                        || ext == "psd" || ext == "ras" || ext == "rgb" || ext == "rgba"
7512                        || ext == "sgi" || ext == "tga" || ext == "xcf" || ext == "dds"
7513                        || ext == "gif" || ext == "ico" || ext == "jp2" || ext == "jpeg"
7514                        || ext == "jpg" || ext == "mng" || ext == "pbm" || ext == "pgm"
7515                        || ext == "pic" || ext == "png" || ext == "ppm" || ext == "svg"
7516                        || ext == "svgz" || ext == "tif" || ext == "tiff" || ext == "webp"
7517                        || ext == "xbm" || ext == "xpm" || ext == "xv") {
7518                 loadImage(fileName);
7519             }
7520         }
7521         if (!asciiFiles.isEmpty()) {
7522             importASCII(asciiFiles, ImportASCIIDialog::NewTables, columnSeparator, ignoredLines,
7523                         renameColumns, strip_spaces, simplify_spaces, d_convert_to_numeric,
7524                         d_ASCII_import_locale);
7525         }
7526     }
7527 }
7528 
dragEnterEvent(QDragEnterEvent * e)7529 void ApplicationWindow::dragEnterEvent(QDragEnterEvent *e)
7530 {
7531     if (e->source()) {
7532         e->ignore();
7533         return;
7534     }
7535     (e->mimeData()->hasUrls()) ? e->acceptProposedAction() : e->ignore();
7536 }
7537 
closeEvent(QCloseEvent * ce)7538 void ApplicationWindow::closeEvent(QCloseEvent *ce)
7539 {
7540     if (!saved) {
7541         QString s = tr("Save changes to project: <p><b> %1 </b> ?").arg(projectname);
7542         switch (QMessageBox::information(this, tr("SciDAVis"), s, tr("Yes"), tr("No"), tr("Cancel"),
7543                                          0, 2)) {
7544         case 0:
7545             if (!saveProject()) {
7546                 ce->ignore();
7547                 break;
7548             }
7549             saveSettings(); // the recent projects must be saved
7550             ce->accept();
7551             break;
7552 
7553         case 1:
7554         default:
7555             saveSettings(); // the recent projects must be saved
7556             ce->accept();
7557             break;
7558 
7559         case 2:
7560             ce->ignore();
7561             break;
7562         }
7563     } else {
7564         saveSettings(); // the recent projects must be saved
7565         ce->accept();
7566     }
7567 }
7568 
customEvent(QEvent * e)7569 void ApplicationWindow::customEvent(QEvent *e)
7570 {
7571     if (e->type() == SCRIPTING_CHANGE_EVENT) {
7572         scriptingChangeEvent((ScriptingChangeEvent *)e);
7573         // If the event is triggered by setScriptingLang(), the connections are already made
7574         // (for messages emitted during initialization). However, it's good programming practice not
7575         // to assume a particular call path for an event; which means that we don't know for sure
7576         // at this point whether scriptEnv is connected or not.
7577         scriptEnv->disconnect(this);
7578         connect(scriptEnv, SIGNAL(error(const QString &, const QString &, int)), this,
7579                 SLOT(scriptError(const QString &, const QString &, int)));
7580         connect(scriptEnv, SIGNAL(print(const QString &)), this,
7581                 SLOT(scriptPrint(const QString &)));
7582     }
7583 }
7584 
deleteSelectedItems()7585 void ApplicationWindow::deleteSelectedItems()
7586 {
7587     if (folders.hasFocus()
7588         && folders.currentItem()
7589                 != folders.topLevelItem(
7590                         0)) { // we never allow the user to delete the project folder item
7591         deleteFolder();
7592         return;
7593     }
7594 
7595     QList<QTreeWidgetItem *> lst;
7596     for (QTreeWidgetItemIterator it(&lv); *it; it++) {
7597         if ((*it)->isSelected())
7598             lst.append((*it));
7599     }
7600 
7601     folders.blockSignals(true);
7602     for (auto item : lst) {
7603         if (item->type() == FolderListItem::FolderType) {
7604             Folder *f = ((FolderListItem *)item)->folder();
7605             if (deleteFolder(f))
7606                 delete item;
7607         } else
7608             ((WindowListItem *)item)->window()->close();
7609     }
7610     folders.blockSignals(false);
7611 }
7612 
showListViewSelectionMenuImpl()7613 QMenu *ApplicationWindow::showListViewSelectionMenuImpl()
7614 {
7615     QMenu *cm = new QMenu(this);
7616     cm->addAction(tr("&Delete Selection"), this, SLOT(deleteSelectedItems()), Qt::Key_F8);
7617     return cm;
7618 }
7619 
showListViewPopupMenuImpl()7620 QMenu *ApplicationWindow::showListViewPopupMenuImpl()
7621 {
7622     QMenu *cm = new QMenu(this);
7623     QMenu *window = cm->addMenu(tr("New &Window"));
7624 
7625     window->addAction(actionNewTable);
7626     window->addAction(actionNewMatrix);
7627     window->addAction(actionNewNote);
7628     window->addAction(actionNewGraph);
7629     window->addAction(actionNewFunctionPlot);
7630     window->addAction(actionNewSurfacePlot);
7631     cm->addAction(QPixmap(":/newfolder.xpm"), tr("New F&older"), this, SLOT(addFolder()),
7632                   Qt::Key_F7);
7633     cm->addSeparator();
7634     cm->addAction(tr("Auto &Column Width"), &lv, SLOT(adjustColumns()));
7635     return cm;
7636 }
7637 
showWindowPopupMenu(const QPoint & p)7638 void ApplicationWindow::showWindowPopupMenu(const QPoint &p)
7639 {
7640     if (auto m = showWindowPopupMenuImpl(lv.itemAt(p)))
7641         m->exec(lv.mapToGlobal(p) + QPoint(0, lv.header()->height()));
7642 }
7643 
showWindowPopupMenuImpl(QTreeWidgetItem * it)7644 QMenu *ApplicationWindow::showWindowPopupMenuImpl(QTreeWidgetItem *it)
7645 {
7646     if (folders.isRenaming())
7647         return nullptr;
7648 
7649     if (!it)
7650         return showListViewPopupMenuImpl();
7651 
7652     int selected = 0;
7653     QTreeWidgetItemIterator itv(&lv);
7654     while (*itv) {
7655         if ((*itv)->isSelected())
7656             selected++;
7657 
7658         if (selected > 1)
7659             return showListViewSelectionMenuImpl();
7660         itv++;
7661     }
7662 
7663     if (auto fl = dynamic_cast<FolderListItem *>(it)) {
7664         current_folder = fl->folder();
7665         return showFolderPopupMenuImpl(fl, false);
7666     }
7667 
7668     if (auto wli = dynamic_cast<WindowListItem *>(it))
7669         if (auto w = wli->window())
7670             return showWindowMenuImpl(w);
7671     return nullptr;
7672 }
7673 
showTable(const QString & curve)7674 void ApplicationWindow::showTable(const QString &curve)
7675 {
7676     Table *w = table(curve);
7677     if (!w)
7678         return;
7679 
7680     updateWindowLists(w);
7681     int colIndex = w->colIndex(curve);
7682     w->deselectAll();
7683     w->setCellsSelected(0, colIndex, w->d_future_table->rowCount() - 1, colIndex);
7684     w->showMaximized();
7685     QTreeWidgetItem *it = lv.findItems(w->name(), Qt::MatchExactly | Qt::MatchCaseSensitive).at(0);
7686     if (it)
7687         it->setText(2, tr("Maximized"));
7688     emit modified();
7689 }
7690 
depending3DPlots(Matrix * m)7691 QStringList ApplicationWindow::depending3DPlots(Matrix *m)
7692 {
7693     QList<MyWidget *> windows = windowsList();
7694     QStringList plots;
7695     for (int i = 0; i < (int)windows.count(); i++) {
7696         MyWidget *w = windows.at(i);
7697         if (w && w->inherits("Graph3D") && ((Graph3D *)w)->matrix() == m)
7698             plots << w->name();
7699     }
7700     return plots;
7701 }
7702 
7703 // TODO: Implement this in an elegant way
dependingPlots(const QString & name)7704 QStringList ApplicationWindow::dependingPlots(const QString &name)
7705 {
7706     QList<MyWidget *> windows = windowsList();
7707     QStringList onPlot, plots;
7708 
7709     for (int i = 0; i < windows.count(); i++) {
7710         MyWidget *w = windows.at(i);
7711         if (!w)
7712             continue;
7713         if (w->inherits("MultiLayer")) {
7714             QWidgetList lst = ((MultiLayer *)w)->graphPtrs();
7715             foreach (QWidget *widget, lst) {
7716                 Graph *g = (Graph *)widget;
7717                 onPlot = g->curvesList();
7718                 onPlot = onPlot.filter(QRegExp("^" + name + "_.*"));
7719                 if (onPlot.count() > 0 && !plots.contains(w->name()))
7720                     plots << w->name();
7721             }
7722         } else if (w->inherits("Graph3D")) {
7723             if ((((Graph3D *)w)->formula()).contains(name, Qt::CaseSensitive)
7724                 && !plots.contains(w->name()))
7725                 plots << w->name();
7726         }
7727     }
7728     return plots;
7729 }
7730 
multilayerDependencies(MyWidget * w)7731 QStringList ApplicationWindow::multilayerDependencies(MyWidget *w)
7732 {
7733     QStringList tables;
7734     MultiLayer *g = (MultiLayer *)w;
7735     QWidgetList graphsList = g->graphPtrs();
7736     for (int i = 0; i < graphsList.count(); i++) {
7737         Graph *ag = (Graph *)graphsList.at(i);
7738         QStringList onPlot = ag->curvesList();
7739         for (int j = 0; j < onPlot.count(); j++) {
7740 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
7741             QStringList tl = onPlot[j].split("_", Qt::SkipEmptyParts);
7742 #else
7743             QStringList tl = onPlot[j].split("_", QString::SkipEmptyParts);
7744 #endif
7745             if (!tables.contains(tl[0]))
7746                 tables << tl[0];
7747         }
7748     }
7749     return tables;
7750 }
7751 
showGraphContextMenu()7752 void ApplicationWindow::showGraphContextMenu()
7753 {
7754     QWidget *w = (QWidget *)d_workspace.activeSubWindow();
7755     if (!w)
7756         return;
7757 
7758     if (w->inherits("MultiLayer")) {
7759         MultiLayer *plot = (MultiLayer *)w;
7760         QMenu cm(this);
7761         QMenu *calcul = cm.addMenu(tr("Anal&yze"));
7762 
7763         Graph *ag = (Graph *)plot->activeGraph();
7764         if (ag->isPiePlot())
7765             cm.addAction(tr("Re&move Pie Curve"), ag, SLOT(removePie()));
7766         else {
7767             if (ag->visibleCurves() != ag->curves()) {
7768                 cm.addAction(actionShowAllCurves);
7769                 cm.addSeparator();
7770             }
7771             cm.addAction(actionShowCurvesDialog);
7772             cm.addAction(actionAddFunctionCurve);
7773 
7774             QMenu *translate = calcul->addMenu(tr("&Translate"));
7775             translate->addAction(actionTranslateVert);
7776             translate->addAction(actionTranslateHor);
7777             calcul->addSeparator();
7778 
7779             calcul->addAction(actionDifferentiate);
7780             calcul->addAction(actionShowIntDialog);
7781             calcul->addSeparator();
7782 
7783             QMenu *smooth = calcul->addMenu(tr("&Smooth"));
7784             smooth->addAction(actionSmoothSavGol);
7785             smooth->addAction(actionSmoothFFT);
7786             smooth->addAction(actionSmoothAverage);
7787 
7788             QMenu *filter = calcul->addMenu(tr("&FFT Filter"));
7789             filter->addAction(actionLowPassFilter);
7790             filter->addAction(actionHighPassFilter);
7791             filter->addAction(actionBandPassFilter);
7792             filter->addAction(actionBandBlockFilter);
7793 
7794             calcul->addSeparator();
7795             calcul->addAction(actionInterpolate);
7796             calcul->addAction(actionFFT);
7797             calcul->addSeparator();
7798             calcul->addAction(actionFitLinear);
7799             calcul->addAction(actionShowFitPolynomDialog);
7800             calcul->addSeparator();
7801 
7802             QMenu *decay = calcul->addMenu(tr("Fit E&xponential Decay"));
7803             decay->addAction(actionShowExpDecayDialog);
7804             decay->addAction(actionShowTwoExpDecayDialog);
7805             decay->addAction(actionShowExpDecay3Dialog);
7806 
7807             calcul->addAction(actionFitExpGrowth);
7808             calcul->addAction(actionFitSigmoidal);
7809             calcul->addAction(actionFitGauss);
7810             calcul->addAction(actionFitLorentz);
7811 
7812             QMenu *multiPeakMenu = calcul->addMenu(tr("Fit &Multi-Peak"));
7813             multiPeakMenu->addAction(actionMultiPeakGauss);
7814             multiPeakMenu->addAction(actionMultiPeakLorentz);
7815 
7816             calcul->addSeparator();
7817             calcul->addAction(actionShowFitDialog);
7818         }
7819 
7820         if (copiedLayer) {
7821             cm.addSeparator();
7822             cm.addAction(IconLoader::load("edit-paste"), tr("&Paste Layer"), this,
7823                          SLOT(pasteSelection()));
7824         } else if (copiedMarkerType >= 0) {
7825             cm.addSeparator();
7826             if (copiedMarkerType == Graph::Text)
7827                 cm.addAction(IconLoader::load("edit-paste"), tr("&Paste Text"), plot,
7828                              SIGNAL(pasteMarker()));
7829             else if (copiedMarkerType == Graph::Arrow)
7830                 cm.addAction(IconLoader::load("edit-paste"), tr("&Paste Line/Arrow"), plot,
7831                              SIGNAL(pasteMarker()));
7832             else if (copiedMarkerType == Graph::Image)
7833                 cm.addAction(IconLoader::load("edit-paste"), tr("&Paste Image"), plot,
7834                              SIGNAL(pasteMarker()));
7835         }
7836         cm.addSeparator();
7837         QMenu *copy = cm.addMenu(tr("&Copy"));
7838         copy->setIcon(IconLoader::load("edit-copy"));
7839         copy->addAction(tr("&Layer"), this, SLOT(copyActiveLayer()));
7840         copy->addAction(tr("&Window"), plot, SLOT(copyAllLayers()));
7841 
7842         QMenu *exports = cm.addMenu(tr("E&xport"));
7843         exports->addAction(tr("&Layer"), this, SLOT(exportLayer()));
7844         exports->addAction(tr("&Window"), this, SLOT(exportGraph()));
7845 
7846         QMenu *prints = cm.addMenu(tr("&Print"));
7847         prints->setIcon(QPixmap(":/fileprint.xpm"));
7848         prints->addAction(tr("&Layer"), plot, SLOT(printActiveLayer()));
7849         prints->addAction(tr("&Window"), plot, SLOT(print()));
7850 
7851         cm.addSeparator();
7852         cm.addAction(QPixmap(":/resize.xpm"), tr("&Geometry..."), plot,
7853                      SIGNAL(showGeometryDialog()));
7854         cm.addAction(tr("P&roperties..."), this, SLOT(showGeneralPlotDialog()));
7855         cm.addSeparator();
7856         cm.addAction(QPixmap(":/close.xpm"), tr("&Delete Layer"), plot, SLOT(confirmRemoveLayer()));
7857         cm.exec(QCursor::pos());
7858     }
7859 }
7860 
showLayerButtonContextMenu()7861 void ApplicationWindow::showLayerButtonContextMenu()
7862 {
7863     QWidget *w = (QWidget *)d_workspace.activeSubWindow();
7864     if (!w)
7865         return;
7866 
7867     if (w->inherits("MultiLayer")) {
7868         MultiLayer *plot = (MultiLayer *)w;
7869         QMenu cm(this);
7870 
7871         Graph *ag = (Graph *)plot->activeGraph();
7872 
7873         cm.addAction(actionAddLayer);
7874         cm.addAction(actionDeleteLayer);
7875         cm.addSeparator();
7876 
7877         if (ag->isPiePlot())
7878             cm.addAction(tr("Re&move Pie Curve"), ag, SLOT(removePie()));
7879         else {
7880             if (ag->visibleCurves() != ag->curves()) {
7881                 cm.addAction(actionShowAllCurves);
7882                 cm.addSeparator();
7883             }
7884             cm.addAction(actionShowCurvesDialog);
7885             cm.addAction(actionAddFunctionCurve);
7886 
7887             QMenu *calcul = cm.addMenu(tr("Anal&yze"));
7888 
7889             QMenu *translate = calcul->addMenu(tr("&Translate"));
7890             translate->addAction(actionTranslateVert);
7891             translate->addAction(actionTranslateHor);
7892             calcul->addSeparator();
7893 
7894             calcul->addAction(actionDifferentiate);
7895             calcul->addAction(actionShowIntDialog);
7896             calcul->addSeparator();
7897 
7898             QMenu *smooth = calcul->addMenu(tr("&Smooth"));
7899             smooth->addAction(actionSmoothSavGol);
7900             smooth->addAction(actionSmoothFFT);
7901             smooth->addAction(actionSmoothAverage);
7902 
7903             QMenu *filter = calcul->addMenu(tr("&FFT Filter"));
7904             filter->addAction(actionLowPassFilter);
7905             filter->addAction(actionHighPassFilter);
7906             filter->addAction(actionBandPassFilter);
7907             filter->addAction(actionBandBlockFilter);
7908 
7909             calcul->addSeparator();
7910             calcul->addAction(actionInterpolate);
7911             calcul->addAction(actionFFT);
7912             calcul->addSeparator();
7913             calcul->addAction(actionFitLinear);
7914             calcul->addAction(actionShowFitPolynomDialog);
7915             calcul->addSeparator();
7916 
7917             QMenu *decay = calcul->addMenu(tr("Fit E&xponential Decay"));
7918             decay->addAction(actionShowExpDecayDialog);
7919             decay->addAction(actionShowTwoExpDecayDialog);
7920             decay->addAction(actionShowExpDecay3Dialog);
7921 
7922             calcul->addAction(actionFitExpGrowth);
7923             calcul->addAction(actionFitSigmoidal);
7924             calcul->addAction(actionFitGauss);
7925             calcul->addAction(actionFitLorentz);
7926 
7927             QMenu *multiPeakMenu = calcul->addMenu(tr("Fit &Multi-Peak"));
7928             multiPeakMenu->addAction(actionMultiPeakGauss);
7929             multiPeakMenu->addAction(actionMultiPeakLorentz);
7930 
7931             calcul->addSeparator();
7932             calcul->addAction(actionShowFitDialog);
7933         }
7934 
7935         if (copiedLayer) {
7936             cm.addSeparator();
7937             cm.addAction(IconLoader::load("edit-paste"), tr("&Paste Layer"), this,
7938                          SLOT(pasteSelection()));
7939         } else if (copiedMarkerType >= 0) {
7940             cm.addSeparator();
7941             if (copiedMarkerType == Graph::Text)
7942                 cm.addAction(IconLoader::load("edit-paste"), tr("&Paste Text"), plot,
7943                              SIGNAL(pasteMarker()));
7944             else if (copiedMarkerType == Graph::Arrow)
7945                 cm.addAction(IconLoader::load("edit-paste"), tr("&Paste Line/Arrow"), plot,
7946                              SIGNAL(pasteMarker()));
7947             else if (copiedMarkerType == Graph::Image)
7948                 cm.addAction(IconLoader::load("edit-paste"), tr("&Paste Image"), plot,
7949                              SIGNAL(pasteMarker()));
7950         }
7951         cm.addSeparator();
7952 
7953         QMenu *copy = cm.addMenu(tr("&Copy"));
7954         copy->setIcon(IconLoader::load("edit-copy"));
7955         copy->addAction(tr("&Layer"), this, SLOT(copyActiveLayer()));
7956         copy->addAction(tr("&Window"), plot, SLOT(copyAllLayers()));
7957 
7958         QMenu *exports = cm.addMenu(tr("E&xport"));
7959         exports->addAction(tr("&Layer"), this, SLOT(exportLayer()));
7960         exports->addAction(tr("&Window"), this, SLOT(exportGraph()));
7961 
7962         QMenu *prints = cm.addMenu(tr("&Print"));
7963         prints->setIcon(QPixmap(":/fileprint.xpm"));
7964         prints->addAction(tr("&Layer"), plot, SLOT(printActiveLayer()));
7965         prints->addAction(tr("&Window"), plot, SLOT(print()));
7966 
7967         cm.addSeparator();
7968         cm.addAction(QPixmap(":/resize.xpm"), tr("&Geometry..."), plot,
7969                      SIGNAL(showGeometryDialog()));
7970         cm.addAction(tr("P&roperties..."), this, SLOT(showGeneralPlotDialog()));
7971         cm.addSeparator();
7972         cm.addAction(QPixmap(":/close.xpm"), tr("&Delete Layer"), plot, SLOT(confirmRemoveLayer()));
7973         cm.exec(QCursor::pos());
7974     }
7975 }
7976 
showWindowContextMenu()7977 void ApplicationWindow::showWindowContextMenu()
7978 {
7979     QWidget *w = (QWidget *)d_workspace.activeSubWindow();
7980     if (!w)
7981         return;
7982 
7983     QMenu cm(this);
7984     if (w->inherits("MultiLayer")) {
7985         MultiLayer *g = (MultiLayer *)w;
7986         if (copiedLayer) {
7987             cm.addAction(IconLoader::load("edit-paste"), tr("&Paste Layer"), this,
7988                          SLOT(pasteSelection()));
7989             cm.addSeparator();
7990         }
7991 
7992         cm.addAction(actionAddLayer);
7993         if (g->layers() != 0) {
7994             cm.addAction(actionDeleteLayer);
7995             cm.addSeparator();
7996             cm.addAction(actionShowPlotGeometryDialog);
7997             cm.addAction(actionShowLayerDialog);
7998             cm.addSeparator();
7999         } else
8000             cm.addSeparator();
8001         cm.addAction(actionRename);
8002         cm.addAction(actionCopyWindow);
8003         cm.addSeparator();
8004         cm.addAction(IconLoader::load("edit-copy"), tr("&Copy Page"), g, SLOT(copyAllLayers()));
8005         cm.addAction(tr("E&xport Page"), this, SLOT(exportGraph()));
8006         cm.addAction(actionPrint);
8007         cm.addSeparator();
8008         cm.addAction(actionCloseWindow);
8009     } else if (w->inherits("Graph3D")) {
8010         Graph3D *g = (Graph3D *)w;
8011         if (!g->hasData()) {
8012             QMenu *plot3D = cm.addMenu(tr("3D &Plot"));
8013             plot3D->addAction(actionAdd3DData);
8014             plot3D->addAction(tr("&Matrix..."), this, SLOT(add3DMatrixPlot()));
8015             plot3D->addAction(actionEditSurfacePlot);
8016         } else {
8017             if (g->getTable())
8018                 cm.addAction(tr("Choose &Data Set..."), this, SLOT(change3DData()));
8019             else if (g->matrix())
8020                 cm.addAction(tr("Choose &Matrix..."), this, SLOT(change3DMatrix()));
8021             else if (g->userFunction())
8022                 cm.addAction(actionEditSurfacePlot);
8023             cm.addAction(QPixmap(":/erase.xpm"), tr("C&lear"), g, SLOT(clearData()));
8024         }
8025 
8026         cm.addSeparator();
8027         cm.addAction(actionRename);
8028         cm.addAction(actionCopyWindow);
8029         cm.addSeparator();
8030         cm.addAction(tr("&Copy Graph"), g, SLOT(copyImage()));
8031         cm.addAction(tr("&Export"), this, SLOT(exportGraph()));
8032         cm.addAction(actionPrint);
8033         cm.addSeparator();
8034         cm.addAction(actionCloseWindow);
8035     } else if (w->inherits("Matrix")) {
8036         Matrix *t = (Matrix *)w;
8037         cm.addAction(IconLoader::load("edit-cut"), tr("Cu&t"), t, SLOT(cutSelection()));
8038         cm.addAction(IconLoader::load("edit-copy"), tr("&Copy"), t, SLOT(copySelection()));
8039         cm.addAction(IconLoader::load("edit-paste"), tr("&Paste"), t, SLOT(pasteSelection()));
8040         cm.addSeparator();
8041         cm.addAction(tr("&Insert Row"), t, SLOT(insertRow()));
8042         cm.addAction(tr("&Insert Column"), t, SLOT(insertColumn()));
8043         if (t->rowsSelected()) {
8044             cm.addAction(QPixmap(":/close.xpm"), tr("&Delete Rows"), t, SLOT(deleteSelectedRows()));
8045         } else if (t->columnsSelected()) {
8046             cm.addAction(QPixmap(":/close.xpm"), tr("&Delete Columns"), t,
8047                          SLOT(deleteSelectedColumns()));
8048         }
8049         cm.addAction(QPixmap(":/erase.xpm"), tr("Clea&r"), t, SLOT(clearSelection()));
8050     }
8051     cm.exec(QCursor::pos());
8052 }
8053 
showWindowTitleBarMenu()8054 void ApplicationWindow::showWindowTitleBarMenu()
8055 {
8056     if (!qobject_cast<MyWidget *>(d_workspace.activeSubWindow()))
8057         return;
8058 
8059     showWindowMenu(qobject_cast<MyWidget *>(d_workspace.activeSubWindow()));
8060 }
8061 
chooseHelpFolder()8062 void ApplicationWindow::chooseHelpFolder()
8063 {
8064 // TODO: move all paths & location handling to anothor class
8065 #ifdef DOC_PATH
8066     const QString locateDefaultHelp = DOC_PATH +
8067         QDir::toNativeSeparators("/manual/index.html");
8068 #else // defined DOC_PATH
8069 #if defined(Q_OS_WIN)
8070     const QString locateDefaultHelp =
8071             qApp->applicationDirPath() + QDir::toNativeSeparators("/manual/index.html");
8072 #else
8073     const QString locateDefaultHelp =
8074             QDir::toNativeSeparators("/usr/share/doc/scidavis/manual/index.html");
8075 #endif
8076 #endif // defined DOC_PATH
8077 
8078     if (QFile(locateDefaultHelp).exists()) {
8079         helpFilePath = locateDefaultHelp;
8080     } else {
8081         const QString dir = QFileDialog::getExistingDirectory(
8082                 this, tr("Choose the location of the SciDAVis help folder!"),
8083                 qApp->applicationDirPath());
8084 
8085         if (!dir.isEmpty()) {
8086             const QFile helpFile(dir + QDir::toNativeSeparators("/index.html"));
8087             // TODO: Probably some kind of validity check to make sure that the
8088             // index.html file belongs to sciDavis
8089             if (!helpFile.exists()) {
8090                 QMessageBox::information(
8091                         this, tr("index.html File Not Found!"),
8092                         tr("There is no file called <b>index.html</b> in this folder."
8093                            "<br>Please choose another folder!"));
8094             } else {
8095                 helpFilePath = dir + QDir::toNativeSeparators("/index.html");
8096             }
8097         }
8098     }
8099 }
8100 
showHelp()8101 void ApplicationWindow::showHelp()
8102 {
8103     QFile helpFile(helpFilePath);
8104     if (!helpFile.exists()) {
8105         QMessageBox::information(
8106                 this, tr("Help Files Not Found!"),
8107                 tr("Please indicate the location of the help file!") + "<br>"
8108                         + tr("The manual can be downloaded from the following internet address:")
8109                         + "<p><a href = \"" MANUAL_URI "\">" MANUAL_URI "</a></p>");
8110         chooseHelpFolder();
8111 #ifdef Q_OS_MAC
8112         QSettings settings(QSettings::IniFormat, QSettings::UserScope, "SciDAVis", "SciDAVis");
8113 #else
8114         QSettings settings(QSettings::NativeFormat, QSettings::UserScope, "SciDAVis", "SciDAVis");
8115 #endif
8116         settings.beginGroup("/Paths");
8117         settings.setValue("/HelpFile", helpFilePath);
8118         settings.endGroup();
8119     }
8120 
8121     if (!QDesktopServices::openUrl(QUrl(helpFilePath))) {
8122         QMessageBox::information(this, tr("unable to open index.html!"),
8123                                  tr("<b>index.html</b> file cannot be opened"));
8124     }
8125 }
8126 
showPlotWizard()8127 void ApplicationWindow::showPlotWizard()
8128 {
8129     if (tableWindows().count() > 0) {
8130         PlotWizard *pw = new PlotWizard(this, Qt::Widget);
8131         pw->setAttribute(Qt::WA_DeleteOnClose);
8132         connect(pw, SIGNAL(plot(const QStringList &)), this,
8133                 SLOT(multilayerPlot(const QStringList &)));
8134 
8135         pw->insertTablesList(tableWindows());
8136         // TODO: string list -> Column * list
8137         pw->setColumnsList(columnsList());
8138         pw->changeColumnsList(tableWindows()[0]);
8139         pw->exec();
8140     } else
8141         QMessageBox::warning(this, tr("Warning"),
8142                              tr("<h4>There are no tables available in this project.</h4>"
8143                                 "<p><h4>Please create a table and try again!</h4>"));
8144 }
8145 
setCurveFullRange()8146 void ApplicationWindow::setCurveFullRange()
8147 {
8148     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
8149         return;
8150 
8151     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
8152     if (!g)
8153         return;
8154 
8155     int curveKey = actionCurveFullRange->data().toInt();
8156     g->setCurveFullRange(g->curveIndex(curveKey));
8157 }
8158 
showCurveRangeDialog()8159 void ApplicationWindow::showCurveRangeDialog()
8160 {
8161     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
8162         return;
8163 
8164     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
8165     if (!g)
8166         return;
8167 
8168     int curveKey = actionEditCurveRange->data().toInt();
8169     showCurveRangeDialog(g, g->curveIndex(curveKey));
8170 }
8171 
showCurveRangeDialog(Graph * g,int curve)8172 CurveRangeDialog *ApplicationWindow::showCurveRangeDialog(Graph *g, int curve)
8173 {
8174     if (!g)
8175         return 0;
8176 
8177     CurveRangeDialog *crd = new CurveRangeDialog(this);
8178     crd->setAttribute(Qt::WA_DeleteOnClose);
8179     crd->setCurveToModify(g, curve);
8180     crd->show();
8181     return crd;
8182 }
8183 
showFunctionDialog()8184 void ApplicationWindow::showFunctionDialog()
8185 {
8186     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
8187         return;
8188 
8189     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
8190     if (!g)
8191         return;
8192 
8193     int curveKey = actionEditFunction->data().toInt();
8194     showFunctionDialog(g, g->curveIndex(curveKey));
8195 }
8196 
showFunctionDialog(Graph * g,int curve)8197 void ApplicationWindow::showFunctionDialog(Graph *g, int curve)
8198 {
8199     if (!g)
8200         return;
8201 
8202     FunctionDialog *fd = functionDialog();
8203     fd->setWindowTitle(tr("Edit function"));
8204     fd->setCurveToModify(g, curve);
8205 }
8206 
functionDialog()8207 FunctionDialog *ApplicationWindow::functionDialog()
8208 {
8209     FunctionDialog *fd = new FunctionDialog(this);
8210     fd->setAttribute(Qt::WA_DeleteOnClose);
8211     connect(fd, SIGNAL(clearParamFunctionsList()), this, SLOT(clearParamFunctionsList()));
8212     connect(fd, SIGNAL(clearPolarFunctionsList()), this, SLOT(clearPolarFunctionsList()));
8213 
8214     fd->insertParamFunctionsList(xFunctions, yFunctions);
8215     fd->insertPolarFunctionsList(rFunctions, thetaFunctions);
8216     fd->show();
8217     fd->activateWindow();
8218     return fd;
8219 }
8220 
addFunctionCurve()8221 void ApplicationWindow::addFunctionCurve()
8222 {
8223     QWidget *w = d_workspace.activeSubWindow();
8224     if (!w || !w->inherits("MultiLayer"))
8225         return;
8226 
8227     if (((MultiLayer *)w)->isEmpty()) {
8228         QMessageBox::warning(this, tr("Warning"),
8229                              tr("<h4>There are no plot layers available in this window.</h4>"
8230                                 "<p><h4>Please add a layer and try again!</h4>"));
8231         return;
8232     }
8233 
8234     Graph *g = ((MultiLayer *)w)->activeGraph();
8235     if (g) {
8236         FunctionDialog *fd = functionDialog();
8237         if (fd)
8238             fd->setGraph(g);
8239     }
8240 }
8241 
updateFunctionLists(int type,QStringList & formulas)8242 void ApplicationWindow::updateFunctionLists(int type, QStringList &formulas)
8243 {
8244     int maxListSize = 10;
8245     if (type == 2) {
8246         rFunctions.removeAll(formulas[0]);
8247         rFunctions.push_front(formulas[0]);
8248 
8249         thetaFunctions.removeAll(formulas[1]);
8250         thetaFunctions.push_front(formulas[1]);
8251 
8252         while ((int)rFunctions.size() > maxListSize)
8253             rFunctions.pop_back();
8254         while ((int)thetaFunctions.size() > maxListSize)
8255             thetaFunctions.pop_back();
8256     } else if (type == 1) {
8257         xFunctions.removeAll(formulas[0]);
8258         xFunctions.push_front(formulas[0]);
8259 
8260         yFunctions.removeAll(formulas[1]);
8261         yFunctions.push_front(formulas[1]);
8262 
8263         while ((int)xFunctions.size() > maxListSize)
8264             xFunctions.pop_back();
8265         while ((int)yFunctions.size() > maxListSize)
8266             yFunctions.pop_back();
8267     }
8268 }
8269 
newFunctionPlot(int type,QStringList & formulas,const QString & var,QList<double> & ranges,int points)8270 bool ApplicationWindow::newFunctionPlot(int type, QStringList &formulas, const QString &var,
8271                                         QList<double> &ranges, int points)
8272 {
8273     MultiLayer *ml = newGraph();
8274     if (!ml)
8275         return false;
8276 
8277     if (!ml->activeGraph()->addFunctionCurve(this, type, formulas, var, ranges, points))
8278         return false;
8279 
8280     updateFunctionLists(type, formulas);
8281     return true;
8282 }
8283 
clearLogInfo()8284 void ApplicationWindow::clearLogInfo()
8285 {
8286     if (!logInfo.isEmpty()) {
8287         logInfo = "";
8288         results->setText(logInfo);
8289         emit modified();
8290     }
8291 }
8292 
clearParamFunctionsList()8293 void ApplicationWindow::clearParamFunctionsList()
8294 {
8295     xFunctions.clear();
8296     yFunctions.clear();
8297 }
8298 
clearPolarFunctionsList()8299 void ApplicationWindow::clearPolarFunctionsList()
8300 {
8301     rFunctions.clear();
8302     thetaFunctions.clear();
8303 }
8304 
clearFitFunctionsList()8305 void ApplicationWindow::clearFitFunctionsList()
8306 {
8307     fitFunctions.clear();
8308 }
8309 
saveFitFunctionsList(const QStringList & l)8310 void ApplicationWindow::saveFitFunctionsList(const QStringList &l)
8311 {
8312     fitFunctions = l;
8313 }
8314 
clearSurfaceFunctionsList()8315 void ApplicationWindow::clearSurfaceFunctionsList()
8316 {
8317     surfaceFunc.clear();
8318 }
8319 
setFramed3DPlot()8320 void ApplicationWindow::setFramed3DPlot()
8321 {
8322     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D")) {
8323         ((Graph3D *)d_workspace.activeSubWindow())->setFramed();
8324         actionShowAxisDialog->setEnabled(true);
8325     }
8326 }
8327 
setBoxed3DPlot()8328 void ApplicationWindow::setBoxed3DPlot()
8329 {
8330     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D")) {
8331         ((Graph3D *)d_workspace.activeSubWindow())->setBoxed();
8332         actionShowAxisDialog->setEnabled(true);
8333     }
8334 }
8335 
removeAxes3DPlot()8336 void ApplicationWindow::removeAxes3DPlot()
8337 {
8338     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D")) {
8339         ((Graph3D *)d_workspace.activeSubWindow())->setNoAxes();
8340         actionShowAxisDialog->setEnabled(false);
8341     }
8342 }
8343 
removeGrid3DPlot()8344 void ApplicationWindow::removeGrid3DPlot()
8345 {
8346     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8347         ((Graph3D *)d_workspace.activeSubWindow())->setNoGrid();
8348 }
8349 
setHiddenLineGrid3DPlot()8350 void ApplicationWindow::setHiddenLineGrid3DPlot()
8351 {
8352     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8353         ((Graph3D *)d_workspace.activeSubWindow())->setHiddenLineGrid();
8354 }
8355 
setPoints3DPlot()8356 void ApplicationWindow::setPoints3DPlot()
8357 {
8358     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8359         ((Graph3D *)d_workspace.activeSubWindow())->setPointsMesh();
8360 }
8361 
setCones3DPlot()8362 void ApplicationWindow::setCones3DPlot()
8363 {
8364     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8365         ((Graph3D *)d_workspace.activeSubWindow())->setConesMesh();
8366 }
8367 
setCrosses3DPlot()8368 void ApplicationWindow::setCrosses3DPlot()
8369 {
8370     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8371         ((Graph3D *)d_workspace.activeSubWindow())->setCrossMesh();
8372 }
8373 
setBars3DPlot()8374 void ApplicationWindow::setBars3DPlot()
8375 {
8376     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8377         ((Graph3D *)d_workspace.activeSubWindow())->setBarsPlot();
8378 }
8379 
setLineGrid3DPlot()8380 void ApplicationWindow::setLineGrid3DPlot()
8381 {
8382     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8383         ((Graph3D *)d_workspace.activeSubWindow())->setLineGrid();
8384 }
8385 
setFilledMesh3DPlot()8386 void ApplicationWindow::setFilledMesh3DPlot()
8387 {
8388     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8389         ((Graph3D *)d_workspace.activeSubWindow())->setFilledMesh();
8390 }
8391 
setFloorData3DPlot()8392 void ApplicationWindow::setFloorData3DPlot()
8393 {
8394     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8395         ((Graph3D *)d_workspace.activeSubWindow())->setFloorData();
8396 }
8397 
setFloorIso3DPlot()8398 void ApplicationWindow::setFloorIso3DPlot()
8399 {
8400     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8401         ((Graph3D *)d_workspace.activeSubWindow())->setFloorIsolines();
8402 }
8403 
setEmptyFloor3DPlot()8404 void ApplicationWindow::setEmptyFloor3DPlot()
8405 {
8406     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8407         ((Graph3D *)d_workspace.activeSubWindow())->setEmptyFloor();
8408 }
8409 
setFrontGrid3DPlot(bool on)8410 void ApplicationWindow::setFrontGrid3DPlot(bool on)
8411 {
8412     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8413         ((Graph3D *)d_workspace.activeSubWindow())->setFrontGrid(on);
8414 }
8415 
setBackGrid3DPlot(bool on)8416 void ApplicationWindow::setBackGrid3DPlot(bool on)
8417 {
8418     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8419         ((Graph3D *)d_workspace.activeSubWindow())->setBackGrid(on);
8420 }
8421 
setFloorGrid3DPlot(bool on)8422 void ApplicationWindow::setFloorGrid3DPlot(bool on)
8423 {
8424     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8425         ((Graph3D *)d_workspace.activeSubWindow())->setFloorGrid(on);
8426 }
8427 
setCeilGrid3DPlot(bool on)8428 void ApplicationWindow::setCeilGrid3DPlot(bool on)
8429 {
8430     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8431         ((Graph3D *)d_workspace.activeSubWindow())->setCeilGrid(on);
8432 }
8433 
setRightGrid3DPlot(bool on)8434 void ApplicationWindow::setRightGrid3DPlot(bool on)
8435 {
8436     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8437         ((Graph3D *)d_workspace.activeSubWindow())->setRightGrid(on);
8438 }
8439 
setLeftGrid3DPlot(bool on)8440 void ApplicationWindow::setLeftGrid3DPlot(bool on)
8441 {
8442     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
8443         ((Graph3D *)d_workspace.activeSubWindow())->setLeftGrid(on);
8444 }
8445 
pickPlotStyle(QAction * action)8446 void ApplicationWindow::pickPlotStyle(QAction *action)
8447 {
8448     if (!action)
8449         return;
8450 
8451     if (action == polygon) {
8452         removeGrid3DPlot();
8453     } else if (action == filledmesh) {
8454         setFilledMesh3DPlot();
8455     } else if (action == wireframe) {
8456         setLineGrid3DPlot();
8457     } else if (action == hiddenline) {
8458         setHiddenLineGrid3DPlot();
8459     } else if (action == pointstyle) {
8460         setPoints3DPlot();
8461     } else if (action == conestyle) {
8462         setCones3DPlot();
8463     } else if (action == crossHairStyle) {
8464         setCrosses3DPlot();
8465     } else if (action == barstyle) {
8466         setBars3DPlot();
8467     }
8468     emit modified();
8469 }
8470 
pickCoordSystem(QAction * action)8471 void ApplicationWindow::pickCoordSystem(QAction *action)
8472 {
8473     if (!action)
8474         return;
8475 
8476     if (action == Box || action == Frame) {
8477         if (action == Box)
8478             setBoxed3DPlot();
8479         if (action == Frame)
8480             setFramed3DPlot();
8481         grids->setEnabled(true);
8482     } else if (action == None) {
8483         removeAxes3DPlot();
8484         grids->setEnabled(false);
8485     }
8486 
8487     emit modified();
8488 }
8489 
pickFloorStyle(QAction * action)8490 void ApplicationWindow::pickFloorStyle(QAction *action)
8491 {
8492     if (!action)
8493         return;
8494 
8495     if (action == floordata) {
8496         setFloorData3DPlot();
8497     } else if (action == flooriso) {
8498         setFloorIso3DPlot();
8499     } else {
8500         setEmptyFloor3DPlot();
8501     }
8502 
8503     emit modified();
8504 }
8505 
custom3DActions(MyWidget * w)8506 void ApplicationWindow::custom3DActions(MyWidget *w)
8507 {
8508     if (w && w->inherits("Graph3D")) {
8509         Graph3D *plot = (Graph3D *)w;
8510         actionAnimate->setChecked(plot->isAnimated());
8511         actionPerspective->setChecked(!plot->isOrthogonal());
8512         switch (plot->plotStyle()) {
8513         case FILLEDMESH:
8514             wireframe->setChecked(false);
8515             hiddenline->setChecked(false);
8516             polygon->setChecked(false);
8517             filledmesh->setChecked(true);
8518             pointstyle->setChecked(false);
8519             barstyle->setChecked(false);
8520             conestyle->setChecked(false);
8521             crossHairStyle->setChecked(false);
8522             break;
8523 
8524         case FILLED:
8525             wireframe->setChecked(false);
8526             hiddenline->setChecked(false);
8527             polygon->setChecked(true);
8528             filledmesh->setChecked(false);
8529             pointstyle->setChecked(false);
8530             barstyle->setChecked(false);
8531             conestyle->setChecked(false);
8532             crossHairStyle->setChecked(false);
8533             break;
8534 
8535         case Qwt3D::USER:
8536             wireframe->setChecked(false);
8537             hiddenline->setChecked(false);
8538             polygon->setChecked(false);
8539             filledmesh->setChecked(false);
8540 
8541             if (plot->pointType() == Graph3D::VerticalBars) {
8542                 pointstyle->setChecked(false);
8543                 conestyle->setChecked(false);
8544                 crossHairStyle->setChecked(false);
8545                 barstyle->setChecked(true);
8546             } else if (plot->pointType() == Graph3D::Dots) {
8547                 pointstyle->setChecked(true);
8548                 barstyle->setChecked(false);
8549                 conestyle->setChecked(false);
8550                 crossHairStyle->setChecked(false);
8551             } else if (plot->pointType() == Graph3D::HairCross) {
8552                 pointstyle->setChecked(false);
8553                 barstyle->setChecked(false);
8554                 conestyle->setChecked(false);
8555                 crossHairStyle->setChecked(true);
8556             } else if (plot->pointType() == Graph3D::Cones) {
8557                 pointstyle->setChecked(false);
8558                 barstyle->setChecked(false);
8559                 conestyle->setChecked(true);
8560                 crossHairStyle->setChecked(false);
8561             }
8562             break;
8563 
8564         case WIREFRAME:
8565             wireframe->setChecked(true);
8566             hiddenline->setChecked(false);
8567             polygon->setChecked(false);
8568             filledmesh->setChecked(false);
8569             pointstyle->setChecked(false);
8570             barstyle->setChecked(false);
8571             conestyle->setChecked(false);
8572             crossHairStyle->setChecked(false);
8573             break;
8574 
8575         case HIDDENLINE:
8576             wireframe->setChecked(false);
8577             hiddenline->setChecked(true);
8578             polygon->setChecked(false);
8579             filledmesh->setChecked(false);
8580             pointstyle->setChecked(false);
8581             barstyle->setChecked(false);
8582             conestyle->setChecked(false);
8583             crossHairStyle->setChecked(false);
8584             break;
8585 
8586         default:
8587             break;
8588         }
8589 
8590         switch (plot->coordStyle()) {
8591         case Qwt3D::NOCOORD:
8592             None->setChecked(true);
8593             Box->setChecked(false);
8594             Frame->setChecked(false);
8595             break;
8596 
8597         case Qwt3D::BOX:
8598             None->setChecked(false);
8599             Box->setChecked(true);
8600             Frame->setChecked(false);
8601             break;
8602 
8603         case Qwt3D::FRAME:
8604             None->setChecked(false);
8605             Box->setChecked(false);
8606             Frame->setChecked(true);
8607             break;
8608         }
8609 
8610         switch (plot->floorStyle()) {
8611         case NOFLOOR:
8612             floornone->setChecked(true);
8613             flooriso->setChecked(false);
8614             floordata->setChecked(false);
8615             break;
8616 
8617         case FLOORISO:
8618             floornone->setChecked(false);
8619             flooriso->setChecked(true);
8620             floordata->setChecked(false);
8621             break;
8622 
8623         case FLOORDATA:
8624             floornone->setChecked(false);
8625             flooriso->setChecked(false);
8626             floordata->setChecked(true);
8627             break;
8628         }
8629         custom3DGrids(plot->grids());
8630     }
8631 }
8632 
custom3DGrids(int grids)8633 void ApplicationWindow::custom3DGrids(int grids)
8634 {
8635     if (Qwt3D::BACK & grids)
8636         back->setChecked(true);
8637     else
8638         back->setChecked(false);
8639 
8640     if (Qwt3D::FRONT & grids)
8641         front->setChecked(true);
8642     else
8643         front->setChecked(false);
8644 
8645     if (Qwt3D::CEIL & grids)
8646         ceil->setChecked(true);
8647     else
8648         ceil->setChecked(false);
8649 
8650     if (Qwt3D::FLOOR & grids)
8651         floor->setChecked(true);
8652     else
8653         floor->setChecked(false);
8654 
8655     if (Qwt3D::RIGHT & grids)
8656         right->setChecked(true);
8657     else
8658         right->setChecked(false);
8659 
8660     if (Qwt3D::LEFT & grids)
8661         left->setChecked(true);
8662     else
8663         left->setChecked(false);
8664 }
8665 
initPlot3DToolBar()8666 void ApplicationWindow::initPlot3DToolBar()
8667 {
8668     graph_3D_tools = new QToolBar(tr("3D Surface"), this);
8669     graph_3D_tools->setObjectName(
8670             "graph_3D_tools"); // this is needed for QMainWindow::restoreState()
8671     graph_3D_tools->setIconSize(QSize(20, 20));
8672     addToolBarBreak(Qt::TopToolBarArea);
8673     addToolBar(Qt::TopToolBarArea, graph_3D_tools);
8674 
8675     coord = new QActionGroup(this);
8676     Box = new QAction(coord);
8677     Box->setIcon(QIcon(QPixmap(":/box.xpm")));
8678     Box->setCheckable(true);
8679 
8680     Frame = new QAction(coord);
8681     Frame->setIcon(QIcon(QPixmap(":/free_axes.xpm")));
8682     Frame->setCheckable(true);
8683 
8684     None = new QAction(coord);
8685     None->setIcon(QIcon(QPixmap(":/no_axes.xpm")));
8686     None->setCheckable(true);
8687 
8688     graph_3D_tools->addAction(Frame);
8689     graph_3D_tools->addAction(Box);
8690     graph_3D_tools->addAction(None);
8691     Box->setChecked(true);
8692 
8693     graph_3D_tools->addSeparator();
8694 
8695     // grid actions
8696     grids = new QActionGroup(this);
8697     grids->setEnabled(true);
8698     grids->setExclusive(false);
8699     front = new QAction(grids);
8700     front->setCheckable(true);
8701     front->setIcon(QIcon(QPixmap(":/frontGrid.xpm")));
8702     back = new QAction(grids);
8703     back->setCheckable(true);
8704     back->setIcon(QIcon(QPixmap(":/backGrid.xpm")));
8705     right = new QAction(grids);
8706     right->setCheckable(true);
8707     right->setIcon(QIcon(QPixmap(":/leftGrid.xpm")));
8708     left = new QAction(grids);
8709     left->setCheckable(true);
8710     left->setIcon(QIcon(QPixmap(":/rightGrid.xpm")));
8711     ceil = new QAction(grids);
8712     ceil->setCheckable(true);
8713     ceil->setIcon(QIcon(QPixmap(":/ceilGrid.xpm")));
8714     floor = new QAction(grids);
8715     floor->setCheckable(true);
8716     floor->setIcon(QIcon(QPixmap(":/floorGrid.xpm")));
8717 
8718     graph_3D_tools->addAction(front);
8719     graph_3D_tools->addAction(back);
8720     graph_3D_tools->addAction(right);
8721     graph_3D_tools->addAction(left);
8722     graph_3D_tools->addAction(ceil);
8723     graph_3D_tools->addAction(floor);
8724 
8725     graph_3D_tools->addSeparator();
8726 
8727     actionPerspective = new QAction(this);
8728     actionPerspective->setCheckable(true);
8729     actionPerspective->setIcon(QPixmap(":/perspective.xpm"));
8730     graph_3D_tools->addAction(actionPerspective);
8731     actionPerspective->setChecked(!orthogonal3DPlots);
8732     connect(actionPerspective, SIGNAL(toggled(bool)), this, SLOT(togglePerspective(bool)));
8733 
8734     actionResetRotation = new QAction(this);
8735     actionResetRotation->setCheckable(false);
8736     actionResetRotation->setIcon(QPixmap(":/reset_rotation.xpm"));
8737     graph_3D_tools->addAction(actionResetRotation);
8738     connect(actionResetRotation, SIGNAL(triggered()), this, SLOT(resetRotation()));
8739 
8740     actionFitFrame = new QAction(this);
8741     actionFitFrame->setCheckable(false);
8742     actionFitFrame->setIcon(QPixmap(":/fit_frame.xpm"));
8743     graph_3D_tools->addAction(actionFitFrame);
8744     connect(actionFitFrame, SIGNAL(triggered()), this, SLOT(fitFrameToLayer()));
8745 
8746     graph_3D_tools->addSeparator();
8747 
8748     // plot style actions
8749     plotstyle = new QActionGroup(this);
8750     wireframe = new QAction(plotstyle);
8751     wireframe->setCheckable(true);
8752     wireframe->setEnabled(true);
8753     wireframe->setIcon(QIcon(QPixmap(":/lineMesh.xpm")));
8754     hiddenline = new QAction(plotstyle);
8755     hiddenline->setCheckable(true);
8756     hiddenline->setEnabled(true);
8757     hiddenline->setIcon(QIcon(QPixmap(":/grid_only.xpm")));
8758     polygon = new QAction(plotstyle);
8759     polygon->setCheckable(true);
8760     polygon->setEnabled(true);
8761     polygon->setIcon(QIcon(QPixmap(":/no_grid.xpm")));
8762     filledmesh = new QAction(plotstyle);
8763     filledmesh->setCheckable(true);
8764     filledmesh->setIcon(QIcon(QPixmap(":/grid_poly.xpm")));
8765     pointstyle = new QAction(plotstyle);
8766     pointstyle->setCheckable(true);
8767     pointstyle->setIcon(QIcon(QPixmap(":/pointsMesh.xpm")));
8768 
8769     conestyle = new QAction(plotstyle);
8770     conestyle->setCheckable(true);
8771     conestyle->setIcon(QIcon(QPixmap(":/cones.xpm")));
8772 
8773     crossHairStyle = new QAction(plotstyle);
8774     crossHairStyle->setCheckable(true);
8775     crossHairStyle->setIcon(QIcon(QPixmap(":/crosses.xpm")));
8776 
8777     barstyle = new QAction(plotstyle);
8778     barstyle->setCheckable(true);
8779     barstyle->setIcon(QIcon(QPixmap(":/plot_bars.xpm")));
8780 
8781     graph_3D_tools->addAction(barstyle);
8782     graph_3D_tools->addAction(pointstyle);
8783 
8784     graph_3D_tools->addAction(conestyle);
8785     graph_3D_tools->addAction(crossHairStyle);
8786     graph_3D_tools->addSeparator();
8787 
8788     graph_3D_tools->addAction(wireframe);
8789     graph_3D_tools->addAction(hiddenline);
8790     graph_3D_tools->addAction(polygon);
8791     graph_3D_tools->addAction(filledmesh);
8792     filledmesh->setChecked(true);
8793 
8794     graph_3D_tools->addSeparator();
8795 
8796     // floor actions
8797     floorstyle = new QActionGroup(this);
8798     floordata = new QAction(floorstyle);
8799     floordata->setCheckable(true);
8800     floordata->setIcon(QIcon(QPixmap(":/floor.xpm")));
8801     flooriso = new QAction(floorstyle);
8802     flooriso->setCheckable(true);
8803     flooriso->setIcon(QIcon(QPixmap(":/isolines.xpm")));
8804     floornone = new QAction(floorstyle);
8805     floornone->setCheckable(true);
8806     floornone->setIcon(QIcon(QPixmap(":/no_floor.xpm")));
8807 
8808     graph_3D_tools->addAction(floordata);
8809     graph_3D_tools->addAction(flooriso);
8810     graph_3D_tools->addAction(floornone);
8811     floornone->setChecked(true);
8812 
8813     graph_3D_tools->addSeparator();
8814 
8815     actionAnimate = new QAction(this);
8816     actionAnimate->setCheckable(true);
8817     actionAnimate->setIcon(QPixmap(":/movie.xpm"));
8818     graph_3D_tools->addAction(actionAnimate);
8819 
8820     connect(actionAnimate, SIGNAL(toggled(bool)), this, SLOT(toggle3DAnimation(bool)));
8821     connect(coord, SIGNAL(triggered(QAction *)), this, SLOT(pickCoordSystem(QAction *)));
8822     connect(floorstyle, SIGNAL(triggered(QAction *)), this, SLOT(pickFloorStyle(QAction *)));
8823     connect(plotstyle, SIGNAL(triggered(QAction *)), this, SLOT(pickPlotStyle(QAction *)));
8824 
8825     connect(left, SIGNAL(triggered(bool)), this, SLOT(setLeftGrid3DPlot(bool)));
8826     connect(right, SIGNAL(triggered(bool)), this, SLOT(setRightGrid3DPlot(bool)));
8827     connect(ceil, SIGNAL(triggered(bool)), this, SLOT(setCeilGrid3DPlot(bool)));
8828     connect(floor, SIGNAL(triggered(bool)), this, SLOT(setFloorGrid3DPlot(bool)));
8829     connect(back, SIGNAL(triggered(bool)), this, SLOT(setBackGrid3DPlot(bool)));
8830     connect(front, SIGNAL(triggered(bool)), this, SLOT(setFrontGrid3DPlot(bool)));
8831 }
8832 
pixelLineProfile()8833 void ApplicationWindow::pixelLineProfile()
8834 {
8835     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
8836         return;
8837 
8838     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
8839     if (!g)
8840         return;
8841 
8842     bool ok;
8843     int res = QInputDialog::getInt(this, tr("Set the number of pixels to average"),
8844                                    tr("Number of averaged pixels"), 1, 1, 2000, 2, &ok);
8845     if (!ok)
8846         return;
8847 
8848     LineProfileTool *lpt = new LineProfileTool(g, res);
8849     connect(lpt, SIGNAL(createTablePlot(const QString &, const QString &, QList<Column *>)), this,
8850             SLOT(newWrksheetPlot(const QString &, const QString &, QList<Column *>)));
8851     g->setActiveTool(lpt);
8852 }
8853 
intensityTable()8854 void ApplicationWindow::intensityTable()
8855 {
8856     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
8857         return;
8858 
8859     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
8860     if (g)
8861         g->showIntensityTable();
8862 }
8863 
importImage(const QString & fileName)8864 Matrix *ApplicationWindow::importImage(const QString &fileName)
8865 {
8866     QImage image(fileName);
8867     if (image.isNull())
8868         return NULL;
8869 
8870     Matrix *m = Matrix::fromImage(image, scriptEnv);
8871     if (!m) {
8872         QMessageBox::information(0, tr("Error importing image"),
8873                                  tr("Import of image '%1' failed").arg(fileName));
8874         return NULL;
8875     }
8876     QString caption = generateUniqueName(tr("Matrix"));
8877     m->setName(caption);
8878     d_project->addChild(m->d_future_matrix);
8879     return m;
8880 }
8881 
autoArrangeLayers()8882 void ApplicationWindow::autoArrangeLayers()
8883 {
8884     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
8885         return;
8886 
8887     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
8888     plot->setMargins(5, 5, 5, 5);
8889     plot->setSpacing(5, 5);
8890     plot->arrangeLayers(true, false);
8891 }
8892 
addLayer()8893 void ApplicationWindow::addLayer()
8894 {
8895     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
8896         return;
8897 
8898     MultiLayer *plot = (MultiLayer *)d_workspace.activeSubWindow();
8899     switch (QMessageBox::information(
8900             this, tr("Guess best origin for the new layer?"),
8901             tr("Do you want SciDAVis to guess the best position for the new layer?\n Warning: this "
8902                "will rearrange existing layers!"),
8903             tr("&Guess"), tr("&Top-left corner"), tr("&Cancel"), 0, 2)) {
8904     case 0: {
8905         setPreferences(plot->addLayer());
8906         plot->arrangeLayers(true, false);
8907     } break;
8908 
8909     case 1:
8910         setPreferences(plot->addLayer(0, 0, plot->size().width(), plot->size().height()));
8911         break;
8912 
8913     case 2:
8914         return;
8915         break;
8916     }
8917 }
8918 
deleteLayer()8919 void ApplicationWindow::deleteLayer()
8920 {
8921     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
8922         return;
8923 
8924     ((MultiLayer *)d_workspace.activeSubWindow())->confirmRemoveLayer();
8925 }
8926 
openNote(ApplicationWindow * app,const QStringList & flist)8927 Note *ApplicationWindow::openNote(ApplicationWindow *app, const QStringList &flist)
8928 {
8929 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
8930     QStringList lst = flist[0].split("\t", Qt::SkipEmptyParts);
8931 #else
8932     QStringList lst = flist[0].split("\t", QString::SkipEmptyParts);
8933 #endif
8934     QString caption = lst[0];
8935     Note *w = app->newNote(caption);
8936     if (lst.count() == 2) {
8937         app->setListViewDate(caption, lst[1]);
8938         w->setBirthDate(lst[1]);
8939     }
8940     restoreWindowGeometry(app, w, flist[1]);
8941 
8942     lst = flist[2].split("\t");
8943     w->setWindowLabel(lst[1]);
8944     w->setCaptionPolicy((MyWidget::CaptionPolicy)lst[2].toInt());
8945     app->setListViewLabel(w->name(), lst[1]);
8946     return w;
8947 }
8948 
8949 // TODO: most of this code belongs into matrix
openMatrix(ApplicationWindow * app,const QStringList & flist)8950 Matrix *ApplicationWindow::openMatrix(ApplicationWindow *app, const QStringList &flist)
8951 {
8952     if (app->d_file_version < 0x000200) {
8953         QStringList::const_iterator line = flist.begin();
8954 
8955         QStringList list = (*line).split("\t");
8956         QString caption = list[0];
8957         int rows = list[1].toInt();
8958         int cols = list[2].toInt();
8959 
8960         Matrix *w = app->newMatrix(caption, rows, cols);
8961         app->setListViewDate(caption, list[3]);
8962         w->setBirthDate(list[3]);
8963 
8964         for (line++; line != flist.end(); line++) {
8965             QStringList fields = (*line).split("\t");
8966             if (fields[0] == "geometry") {
8967                 restoreWindowGeometry(app, w, *line);
8968             } else if (fields[0] == "ColWidth") {
8969                 w->setColumnsWidth(fields[1].toInt());
8970             } else if (fields[0] == "Formula") {
8971                 w->setFormula(fields[1]);
8972             } else if (fields[0] == "<formula>") {
8973                 QString formula;
8974                 for (line++; line != flist.end() && *line != "</formula>"; line++)
8975                     formula += *line + "\n";
8976                 formula.truncate(formula.length() - 1);
8977                 w->setFormula(formula);
8978             } else if (fields[0] == "TextFormat") {
8979                 if (fields[1] == "f")
8980                     w->setTextFormat('f', fields[2].toInt());
8981                 else
8982                     w->setTextFormat('e', fields[2].toInt());
8983             } else if (fields[0] == "WindowLabel") { // d_file_version > 71
8984                 w->setWindowLabel(fields[1]);
8985                 w->setCaptionPolicy((MyWidget::CaptionPolicy)fields[2].toInt());
8986                 app->setListViewLabel(w->name(), fields[1]);
8987             } else if (fields[0] == "Coordinates") { // d_file_version > 81
8988                 w->setCoordinates(fields[1].toDouble(), fields[2].toDouble(), fields[3].toDouble(),
8989                                   fields[4].toDouble());
8990             } else // <data> or values
8991                 break;
8992         }
8993         if (*line == "<data>")
8994             line++;
8995 
8996         QElapsedTimer t;
8997         t.start();
8998         // read and set table values
8999         for (; line != flist.end() && *line != "</data>"; line++) {
9000             QStringList fields = (*line).split("\t");
9001             int row = fields[0].toInt();
9002             for (int col = 0; col < cols; col++) {
9003                 QString cell = fields[col + 1];
9004                 if (cell.isEmpty())
9005                     continue;
9006 
9007                 if (d_file_version < 90)
9008                     w->setCell(row, col, QLocale::c().toDouble(cell));
9009                 else if (d_file_version >= 0x000100)
9010                     w->setCell(row, col, QLocale().toDouble(cell));
9011                 else
9012                     w->setText(row, col, cell);
9013             }
9014             if (t.elapsed() > 1000) {
9015                 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
9016                 t.start();
9017             }
9018         }
9019 
9020         return w;
9021     } else {
9022         Matrix *w = app->newMatrix("matrix", 1, 1);
9023         int length = flist.at(0).toInt();
9024         int index = 1;
9025         QString xml(flist.at(index++));
9026         while (xml.length() < length && index < flist.size())
9027             xml += '\n' + flist.at(index++);
9028         XmlStreamReader reader(xml);
9029         reader.readNext();
9030         reader.readNext(); // read the start document
9031         if (w->d_future_matrix->load(&reader) == false) {
9032             QString msg_text = reader.errorString();
9033             QMessageBox::critical(this, tr("Error reading matrix from project file"), msg_text);
9034         }
9035         if (reader.hasWarnings()) {
9036             QString msg_text =
9037                     tr("The following problems occured when loading the project file:\n");
9038             QStringList warnings = reader.warningStrings();
9039             foreach (QString str, warnings)
9040                 msg_text += str + "\n";
9041             QMessageBox::warning(this, tr("Project loading partly failed"), msg_text);
9042         }
9043         restoreWindowGeometry(app, w, flist.at(index));
9044 
9045         activateSubWindow(w);
9046         return w;
9047     }
9048 }
9049 
9050 // TODO: most of this code belongs into Table
openTable(ApplicationWindow * app,QTextStream & stream)9051 Table *ApplicationWindow::openTable(ApplicationWindow *app, QTextStream &stream)
9052 {
9053     if (app->d_file_version < 0x000200) {
9054         QStringList flist;
9055         QString s;
9056         while (s != "</table>") {
9057             s = stream.readLine();
9058             flist << s;
9059         }
9060         flist.pop_back();
9061         QStringList::const_iterator line = flist.begin();
9062 
9063         QStringList list = (*line).split("\t");
9064         QString caption = list[0];
9065         int rows = list[1].toInt();
9066         int cols = list[2].toInt();
9067 
9068         Table *w = app->newTable(caption, rows, cols);
9069         app->setListViewDate(caption, list[3]);
9070         w->setBirthDate(list[3]);
9071 
9072         for (line++; line != flist.end(); line++) {
9073             QStringList fields = (*line).split("\t");
9074             if (fields[0] == "geometry" || fields[0] == "tgeometry") {
9075                 restoreWindowGeometry(app, w, *line);
9076             } else if (fields[0] == "header") {
9077                 fields.pop_front();
9078                 if (d_file_version >= 78)
9079                     w->importV0x0001XXHeader(fields);
9080                 else {
9081                     w->setColPlotDesignation(list[4].toInt(), SciDAVis::X);
9082                     w->setColPlotDesignation(list[6].toInt(), SciDAVis::Y);
9083                     w->setHeader(fields);
9084                 }
9085             } else if (fields[0] == "ColWidth") {
9086                 fields.pop_front();
9087                 w->setColWidths(fields);
9088             } else if (fields[0] == "com") { // legacy code
9089                 w->setCommands(*line);
9090             } else if (fields[0] == "<com>") {
9091                 for (line++; line != flist.end() && *line != "</com>"; line++) {
9092                     int col = (*line).mid(9, (*line).length() - 11).toInt();
9093                     QString formula;
9094                     for (line++; line != flist.end() && *line != "</col>"; line++)
9095                         formula += *line + "\n";
9096                     formula.truncate(formula.length() - 1);
9097                     w->setCommand(col, formula);
9098                 }
9099             } else if (fields[0] == "ColType") { // d_file_version > 65
9100                 fields.pop_front();
9101                 w->setColumnTypes(fields);
9102             } else if (fields[0] == "Comments") { // d_file_version > 71
9103                 fields.pop_front();
9104                 w->setColComments(fields);
9105             } else if (fields[0] == "WindowLabel") { // d_file_version > 71
9106                 w->setWindowLabel(fields[1]);
9107                 w->setCaptionPolicy((MyWidget::CaptionPolicy)fields[2].toInt());
9108                 app->setListViewLabel(w->name(), fields[1]);
9109             } else // <data> or values
9110                 break;
9111         }
9112 
9113         QElapsedTimer t;
9114         t.start();
9115         QApplication::setOverrideCursor(Qt::WaitCursor);
9116         for (line++; line != flist.end() && *line != "</data>";
9117              line++) { // read and set table values
9118             QStringList fields = (*line).split("\t");
9119             int row = fields[0].toInt();
9120             for (int col = 0; col < cols; col++) {
9121                 if (fields.count() >= col + 2) {
9122                     QString cell = fields[col + 1];
9123                     if (cell.isEmpty())
9124                         continue;
9125 
9126                     if (d_file_version < 90 && w->columnType(col) == SciDAVis::ColumnMode::Numeric)
9127                         w->setCell(row, col, QLocale::c().toDouble(cell.replace(",", ".")));
9128                     else if (d_file_version >= 0x000100 && w->columnType(col) == SciDAVis::ColumnMode::Numeric)
9129                         w->setCell(row, col, QLocale().toDouble(cell));
9130                     else
9131                         w->setText(row, col, cell);
9132                 }
9133             }
9134             if (t.elapsed() > 1000) {
9135                 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
9136                 t.start();
9137             }
9138         }
9139         QApplication::restoreOverrideCursor();
9140 
9141         return w;
9142     } else {
9143         QString s = stream.readLine();
9144         int length = s.toInt();
9145 
9146         // On Windows, loading large tables to a QString has been observed to crash
9147         // (apparently due to excessive memory usage).
9148         // => use temporary file if possible
9149         QTemporaryFile tmp_file;
9150         QString tmp_string;
9151         if (tmp_file.open()) {
9152             QTextStream tmp(&tmp_file);
9153             tmp.setCodec(QTextCodec::codecForName("UTF-8"));
9154             int read = 0;
9155             while (length - read >= 1024) {
9156                 tmp << stream.read(1024);
9157                 read += 1024;
9158             }
9159             tmp << stream.read(length - read);
9160             tmp.flush();
9161             tmp_file.seek(0);
9162             stream.readLine(); // skip to next newline
9163         } else
9164             while (tmp_string.length() < length)
9165                 tmp_string += '\n' + stream.readLine();
9166 
9167         XmlStreamReader reader(tmp_string);
9168         if (tmp_file.isOpen())
9169             reader.setDevice(&tmp_file);
9170 
9171         Table *w = app->newTable("table", 1, 1);
9172         reader.readNext();
9173         reader.readNext(); // read the start document
9174         if (w->d_future_table->load(&reader) == false) {
9175             QString msg_text = reader.errorString();
9176             QMessageBox::critical(this, tr("Error reading table from project file"), msg_text);
9177         }
9178         if (reader.hasWarnings()) {
9179             QString msg_text =
9180                     tr("The following problems occured when loading the project file:\n");
9181             QStringList warnings = reader.warningStrings();
9182             foreach (QString str, warnings)
9183                 msg_text += str + "\n";
9184             QMessageBox::warning(this, tr("Project loading partly failed"), msg_text);
9185         }
9186         w->setBirthDate(QLocale().toString(w->d_future_table->creationTime()));
9187 
9188         s = stream.readLine();
9189         restoreWindowGeometry(app, w, s);
9190 
9191         s = stream.readLine(); // </table>
9192 
9193         activateSubWindow(w);
9194         return w;
9195     }
9196 }
9197 
openTableStatistics(const QStringList & flist)9198 TableStatistics *ApplicationWindow::openTableStatistics(const QStringList &flist)
9199 {
9200     QStringList::const_iterator line = flist.begin();
9201 
9202     QStringList list = (*line++).split("\t");
9203     QString caption = list[0];
9204 
9205     QList<int> targets;
9206     for (int i = 1; i <= (*line).count('\t'); i++)
9207         targets << (*line).section('\t', i, i).toInt();
9208 
9209     TableStatistics *w = newTableStatistics(table(list[1]),
9210                                             list[2] == "row" ? TableStatistics::StatRow
9211                                                              : TableStatistics::StatColumn,
9212                                             targets, caption);
9213 
9214     setListViewDate(caption, list[3]);
9215     w->setBirthDate(list[3]);
9216 
9217     for (line++; line != flist.end(); line++) {
9218         QStringList fields = (*line).split("\t");
9219         if (fields[0] == "geometry") {
9220             restoreWindowGeometry(this, w, *line);
9221         } else if (fields[0] == "header") {
9222             fields.pop_front();
9223             if (d_file_version >= 78)
9224                 w->importV0x0001XXHeader(fields);
9225             else {
9226                 w->setColPlotDesignation(list[4].toInt(), SciDAVis::X);
9227                 w->setColPlotDesignation(list[6].toInt(), SciDAVis::Y);
9228                 w->setHeader(fields);
9229             }
9230         } else if (fields[0] == "ColWidth") {
9231             fields.pop_front();
9232             w->setColWidths(fields);
9233         } else if (fields[0] == "com") { // legacy code
9234             w->setCommands(*line);
9235         } else if (fields[0] == "<com>") {
9236             for (line++; line != flist.end() && *line != "</com>"; line++) {
9237                 int col = (*line).mid(9, (*line).length() - 11).toInt();
9238                 QString formula;
9239                 for (line++; line != flist.end() && *line != "</col>"; line++)
9240                     formula += *line + "\n";
9241                 formula.truncate(formula.length() - 1);
9242                 w->setCommand(col, formula);
9243             }
9244         } else if (fields[0] == "ColType") { // d_file_version > 65
9245             fields.pop_front();
9246             w->setColumnTypes(fields);
9247         } else if (fields[0] == "Comments") { // d_file_version > 71
9248             fields.pop_front();
9249             w->setColComments(fields);
9250         } else if (fields[0] == "WindowLabel") { // d_file_version > 71
9251             w->setWindowLabel(fields[1]);
9252             w->setCaptionPolicy((MyWidget::CaptionPolicy)fields[2].toInt());
9253             setListViewLabel(w->name(), fields[1]);
9254         }
9255     }
9256     return w;
9257 }
9258 
openGraph(ApplicationWindow * app,MultiLayer * plot,const QStringList & list)9259 Graph *ApplicationWindow::openGraph(ApplicationWindow *app, MultiLayer *plot,
9260                                     const QStringList &list)
9261 {
9262     Graph *ag = 0;
9263     int curveID = 0;
9264     for (int j = 0; j < (int)list.count() - 1; j++) {
9265         QString s = list[j];
9266         if (s.contains("ggeometry")) {
9267             QStringList fList = s.split("\t");
9268             ag = (Graph *)plot->addLayer(fList[1].toInt(), fList[2].toInt(), fList[3].toInt(),
9269                                          fList[4].toInt());
9270             ag->blockSignals(true);
9271             ag->enableAutoscaling(autoscale2DPlots);
9272         } else if (s.left(10) == "Background") {
9273             QStringList fList = s.split("\t");
9274             QColor c = QColor(COLORVALUE(fList[1]));
9275             if (fList.count() == 3)
9276                 c.setAlpha(fList[2].toInt());
9277             ag->setBackgroundColor(c);
9278         } else if (s.startsWith("Margin")) {
9279             QStringList fList = s.split("\t");
9280             ag->plotWidget()->setMargin(fList[1].toInt());
9281         } else if (s.startsWith("Border")) {
9282             QStringList fList = s.split("\t");
9283             ag->setFrame(fList[1].toInt(), QColor(COLORVALUE(fList[2])));
9284         } else if (s.contains("EnabledAxes")) {
9285             QStringList fList = s.split("\t");
9286             ag->enableAxes(fList);
9287         } else if (s.contains("AxesBaseline")) {
9288 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9289             QStringList fList = s.split("\t", Qt::SkipEmptyParts);
9290 #else
9291             QStringList fList = s.split("\t", QString::SkipEmptyParts);
9292 #endif
9293             ag->setAxesBaseline(fList);
9294         } else if (s.contains("EnabledTicks")) { // version < 0.8.6
9295             QStringList fList = s.split("\t");
9296             fList.pop_front();
9297             fList.replaceInStrings("-1", "3");
9298             ag->setMajorTicksType(fList);
9299             ag->setMinorTicksType(fList);
9300         } else if (s.contains("MajorTicks")) { // version >= 0.8.6
9301             QStringList fList = s.split("\t");
9302             fList.pop_front();
9303             ag->setMajorTicksType(fList);
9304         } else if (s.contains("MinorTicks")) { // version >= 0.8.6
9305             QStringList fList = s.split("\t");
9306             fList.pop_front();
9307             ag->setMinorTicksType(fList);
9308         } else if (s.contains("TicksLength")) {
9309             QStringList fList = s.split("\t");
9310             ag->setTicksLength(fList[1].toInt(), fList[2].toInt());
9311         } else if (s.contains("EnabledTickLabels")) {
9312             QStringList fList = s.split("\t");
9313             fList.pop_front();
9314             ag->setEnabledTickLabels(fList);
9315         } else if (s.contains("AxesColors")) {
9316             QStringList fList = s.split("\t");
9317             fList.pop_front();
9318             ag->setAxesColors(fList);
9319         } else if (s.contains("AxesNumberColors")) {
9320 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9321             QStringList fList = s.split("\t", Qt::KeepEmptyParts);
9322 #else
9323             QStringList fList = s.split("\t", QString::KeepEmptyParts);
9324 #endif
9325             fList.pop_front();
9326             ag->setAxesNumColors(fList);
9327         } else if (s.left(5) == "grid\t") {
9328             ag->plotWidget()->grid()->load(s.split("\t"));
9329         } else if (s.startsWith("<Antialiasing>") && s.endsWith("</Antialiasing>")) {
9330             bool antialiasing = s.remove("<Antialiasing>").remove("</Antialiasing>").toInt();
9331             ag->setAntialiasing(antialiasing, false);
9332         } else if (s.contains("PieCurve")) {
9333             QStringList curve = s.split("\t");
9334             if (!app->renamedTables.isEmpty()) {
9335                 QString caption = (curve[1]).left((curve[1]).indexOf("_", 0));
9336                 if (app->renamedTables.contains(caption)) { // modify the name of the curve
9337                                                             // according to the new table name
9338                     int index = app->renamedTables.indexOf(caption);
9339                     QString newCaption = app->renamedTables[++index];
9340                     curve.replaceInStrings(caption + "_", newCaption + "_");
9341                 }
9342             }
9343             QPen pen = QPen(QColor(COLORVALUE(curve[3])), curve[2].toInt(),
9344                             Graph::getPenStyle(curve[4]));
9345 
9346             Table *table = app->table(curve[1]);
9347             if (table) {
9348                 int startRow = 0;
9349                 int endRow = table->numRows() - 1;
9350                 int first_color = curve[7].toInt();
9351                 bool visible = true;
9352                 if (d_file_version >= 90) {
9353                     startRow = curve[8].toInt();
9354                     endRow = curve[9].toInt();
9355                     visible = ((curve.last() == "1") ? true : false);
9356                 }
9357 
9358                 if (d_file_version <= 89)
9359                     first_color = convertOldToNewColorIndex(first_color);
9360 
9361                 ag->plotPie(table, curve[1], pen, curve[5].toInt(), curve[6].toInt(), first_color,
9362                             startRow, endRow, visible);
9363             }
9364         } else if (s.left(6) == "curve\t") {
9365             bool curve_loaded = false; // Graph::insertCurve may fail
9366 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9367             QStringList curve = s.split("\t", Qt::KeepEmptyParts);
9368 #else
9369             QStringList curve = s.split("\t", QString::KeepEmptyParts);
9370 #endif
9371             int s_offset = 0;
9372             if (curve.count() > 14) {
9373                 if (!app->renamedTables.isEmpty()) {
9374                     QString caption = (curve[2]).left((curve[2]).indexOf("_", 0));
9375 
9376                     if (app->renamedTables.contains(caption)) { // modify the name of the curve
9377                                                                 // according to the new table name
9378                         int index = app->renamedTables.indexOf(caption);
9379                         QString newCaption = app->renamedTables[++index];
9380                         curve.replaceInStrings(caption + "_", newCaption + "_");
9381                     }
9382                 }
9383 
9384                 CurveLayout cl;
9385                 cl.connectType = curve[4].toInt();
9386                 cl.lCol = COLORUINT(curve[5]);
9387                 if (d_file_version <= 89)
9388                     cl.lCol = convertOldToNewColorIndex(cl.lCol);
9389                 cl.lStyle = curve[6].toInt();
9390                 cl.lWidth = curve[7].toInt();
9391                 cl.sSize = curve[8].toInt();
9392                 if (d_file_version <= 78)
9393                     cl.sType = Graph::obsoleteSymbolStyle(curve[9].toInt());
9394                 else
9395                     cl.sType = curve[9].toInt();
9396 
9397                 cl.symCol = COLORUINT(curve[10]);
9398                 if (d_file_version <= 89)
9399                     cl.symCol = convertOldToNewColorIndex(cl.symCol);
9400                 if (curve[11] == "-1")
9401                     cl.symbolFill = false;
9402                 else {
9403                     cl.symbolFill = true;
9404                     cl.fillCol = COLORUINT(curve[11]);
9405                 }
9406                 if (d_file_version <= 89)
9407                     cl.fillCol = convertOldToNewColorIndex(cl.fillCol);
9408                 cl.filledArea = curve[12].toInt();
9409                 cl.aCol = COLORUINT(curve[13]);
9410                 if (d_file_version <= 89)
9411                     cl.aCol = convertOldToNewColorIndex(cl.aCol);
9412                 cl.aStyle = curve[14].toInt();
9413                 if (curve.count() < 16)
9414                     cl.penWidth = cl.lWidth;
9415                 else if ((d_file_version >= 79) && (curve[3].toInt() == Graph::Box)) {
9416                     cl.penWidth = curve[15].toInt();
9417                     s_offset++;
9418                 } else if ((d_file_version >= 78) && (curve[3].toInt() <= Graph::LineSymbols)) {
9419                     cl.penWidth = curve[15].toInt();
9420                     s_offset++;
9421                 } else
9422                     cl.penWidth = cl.lWidth;
9423                 if (d_file_version >= 0x011800) // 1.24.0
9424                 {
9425                     // custom dash pattern
9426                     cl.lCapStyle = curve[15 + s_offset].toInt();
9427                     cl.lJoinStyle = curve[16 + s_offset].toInt();
9428                     cl.lCustomDash = curve[17 + s_offset];
9429                     s_offset += 3;
9430                 }
9431 
9432                 Table *w = app->table(curve[2]);
9433                 if (w) {
9434                     int plotType = curve[3].toInt();
9435                     if (curve.count() > (21 + s_offset)
9436                         && (plotType == Graph::VectXYXY || plotType == Graph::VectXYAM)) {
9437                         QStringList colsList;
9438                         colsList << curve[2];
9439                         colsList << curve[20 + s_offset];
9440                         colsList << curve[21 + s_offset];
9441                         if (d_file_version < 72)
9442                             colsList.prepend(w->colName(curve[1].toInt()));
9443                         else
9444                             colsList.prepend(curve[1]);
9445 
9446                         int startRow = 0;
9447                         int endRow = -1;
9448                         if (d_file_version >= 90) {
9449                             startRow = curve[curve.count() - 3].toInt();
9450                             endRow = curve[curve.count() - 2].toInt();
9451                         }
9452 
9453                         ag->plotVectorCurve(w, colsList, plotType, startRow, endRow);
9454                         curve_loaded = true;
9455 
9456                         if (d_file_version <= 77) {
9457                             int temp_index = convertOldToNewColorIndex(curve[15].toInt());
9458                             ag->updateVectorsLayout(curveID, ColorButton::color(temp_index),
9459                                                     curve[16].toInt(), curve[17].toInt(),
9460                                                     curve[18].toInt(), curve[19].toInt(), 0,
9461                                                     curve[20], curve[21]);
9462                         } else {
9463                             if (plotType == Graph::VectXYXY)
9464                                 ag->updateVectorsLayout(
9465                                         curveID, curve[15 + s_offset], curve[16 + s_offset].toInt(),
9466                                         curve[17 + s_offset].toInt(), curve[18 + s_offset].toInt(),
9467                                         curve[19 + s_offset].toInt(), 0);
9468                             else if (curve.count() > 22 + s_offset)
9469                                 ag->updateVectorsLayout(
9470                                         curveID, curve[15 + s_offset], curve[16 + s_offset].toInt(),
9471                                         curve[17 + s_offset].toInt(), curve[18 + s_offset].toInt(),
9472                                         curve[19 + s_offset].toInt(), curve[22 + s_offset].toInt());
9473                         }
9474                     } else if (plotType == Graph::Box) {
9475                         ag->openBoxDiagram(w, curve, d_file_version);
9476                         curve_loaded = true;
9477                     } else if (plotType == Graph::Histogram && curve.count() > 19) {
9478                         if (d_file_version < 90)
9479                             curve_loaded = ag->plotHistogram(w, QStringList() << curve[2]);
9480                         else
9481                             curve_loaded = ag->plotHistogram(w, QStringList() << curve[2],
9482                                                              curve[curve.count() - 3].toInt(),
9483                                                              curve[curve.count() - 2].toInt());
9484                         if (curve_loaded) {
9485                             QwtHistogram *h = (QwtHistogram *)ag->curve(curveID);
9486                             if (d_file_version <= 76)
9487                                 h->setBinning(curve[16].toInt(), curve[17].toDouble(),
9488                                               curve[18].toDouble(), curve[19].toDouble());
9489                             else if (curve.count() > 20 + s_offset)
9490                                 h->setBinning(curve[17 + s_offset].toInt(),
9491                                               curve[18 + s_offset].toDouble(),
9492                                               curve[19 + s_offset].toDouble(),
9493                                               curve[20 + s_offset].toDouble());
9494                             h->loadData();
9495                         }
9496                     } else {
9497                         if (d_file_version < 72)
9498                             curve_loaded = ag->insertCurve(w, curve[1].toInt(), curve[2], plotType);
9499                         else if (d_file_version < 90)
9500                             curve_loaded = ag->insertCurve(w, curve[1], curve[2], plotType);
9501                         else {
9502                             int startRow = curve[curve.count() - 3].toInt();
9503                             int endRow = curve[curve.count() - 2].toInt();
9504                             curve_loaded = ag->insertCurve(w, curve[1], curve[2], plotType,
9505                                                            startRow, endRow);
9506                         }
9507                     }
9508 
9509                     if (curve_loaded
9510                         && (plotType == Graph::VerticalBars || plotType == Graph::HorizontalBars
9511                             || plotType == Graph::Histogram)) {
9512                         if (d_file_version <= 76 && curve.count() > 15)
9513                             ag->setBarsGap(curveID, curve[15].toInt(), 0);
9514                         else if (curve.count() > (16 + s_offset))
9515                             ag->setBarsGap(curveID, curve[15 + s_offset].toInt(),
9516                                            curve[16 + s_offset].toInt());
9517                     }
9518                     if (curve_loaded)
9519                         ag->updateCurveLayout(curveID, &cl);
9520                     if (d_file_version >= 88) {
9521                         QwtPlotCurve *c = ag->curve(curveID);
9522                         if (c && c->rtti() == QwtPlotItem::Rtti_PlotCurve) {
9523                             if (d_file_version < 90)
9524                                 c->setAxis(curve[curve.count() - 2].toInt(),
9525                                            curve[curve.count() - 1].toInt());
9526                             else {
9527                                 c->setAxis(curve[curve.count() - 5].toInt(),
9528                                            curve[curve.count() - 4].toInt());
9529                                 c->setVisible(curve.last().toInt());
9530                             }
9531                         }
9532                     }
9533                 }
9534                 if (curve_loaded)
9535                     curveID++;
9536             }
9537         } else if (s.contains("FunctionCurve")) {
9538 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9539             QStringList curve = s.split("\t", Qt::KeepEmptyParts);
9540 #else
9541             QStringList curve = s.split("\t", QString::KeepEmptyParts);
9542 #endif
9543             CurveLayout cl;
9544             cl.connectType = curve[6].toInt();
9545             cl.lCol = COLORUINT(curve[7]);
9546             cl.lStyle = curve[8].toInt();
9547             cl.lWidth = curve[9].toInt();
9548             cl.sSize = curve[10].toInt();
9549             cl.sType = curve[11].toInt();
9550             cl.symCol = COLORUINT(curve[12]);
9551             if (curve[13] == "-1")
9552                 cl.symbolFill = false;
9553             else {
9554                 cl.symbolFill = true;
9555                 cl.fillCol = COLORUINT(curve[13]);
9556             }
9557             cl.filledArea = curve[14].toInt();
9558             cl.aCol = COLORUINT(curve[15]);
9559             cl.aStyle = curve[16].toInt();
9560             int current_index = 17;
9561             if (curve.count() < 16)
9562                 cl.penWidth = cl.lWidth;
9563             else if ((d_file_version >= 79) && (curve[5].toInt() == Graph::Box)) {
9564                 cl.penWidth = curve[17].toInt();
9565                 current_index++;
9566             } else if ((d_file_version >= 78) && (curve[5].toInt() <= Graph::LineSymbols)) {
9567                 cl.penWidth = curve[17].toInt();
9568                 current_index++;
9569             } else
9570                 cl.penWidth = cl.lWidth;
9571 
9572             if (d_file_version >= 0x011800) // 1.24.0
9573             {
9574                 // skeep capStyle, joinStyle and custom dash pattern values
9575                 current_index += 3;
9576             }
9577 
9578             QStringList func_spec;
9579             func_spec << curve[1];
9580 
9581             j++;
9582             while (list[j] == "<formula>") { // d_file_version >= 0x000105
9583                 QString formula;
9584                 for (j++; list[j] != "</formula>"; j++)
9585                     formula += list[j] + "\n";
9586                 func_spec << formula;
9587                 j++;
9588             }
9589             j--;
9590 
9591             if (ag->insertFunctionCurve(app, func_spec, curve[2].toInt(), d_file_version)) {
9592                 ag->setCurveType(curveID, (Graph::CurveType)curve[5].toInt(), false);
9593                 ag->updateCurveLayout(curveID, &cl);
9594                 if (d_file_version >= 88) {
9595                     QwtPlotCurve *c = ag->curve(curveID);
9596                     if (c) {
9597                         if (current_index + 1 < curve.size())
9598                             c->setAxis(curve[current_index].toInt(),
9599                                        curve[current_index + 1].toInt());
9600                         if (d_file_version >= 90 && current_index + 2 < curve.size())
9601                             c->setVisible(curve.last().toInt());
9602                         else
9603                             c->setVisible(true);
9604                     }
9605                 }
9606                 if (ag->curve(curveID))
9607                     curveID++;
9608             }
9609         } else if (s.contains("ErrorBars")) {
9610 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9611             QStringList curve = s.split("\t", Qt::SkipEmptyParts);
9612 #else
9613             QStringList curve = s.split("\t", QString::SkipEmptyParts);
9614 #endif
9615             Table *w = app->table(curve[3]);
9616             Table *errTable = app->table(curve[4]);
9617             if (w && errTable) {
9618                 ag->addErrorBars(curve[2], curve[3], errTable, curve[4], curve[1].toInt(),
9619                                  curve[5].toInt(), curve[6].toInt(), QColor(COLORVALUE(curve[7])),
9620                                  curve[8].toInt(), curve[10].toInt(), curve[9].toInt());
9621             }
9622             curveID++;
9623         } else if (s == "<spectrogram>") {
9624             curveID++;
9625             QStringList lst;
9626             while (s != "</spectrogram>") {
9627                 s = list[++j];
9628                 lst << s;
9629             }
9630             lst.pop_back();
9631             ag->restoreSpectrogram(app, lst);
9632         } else if (s.left(6) == "scale\t") {
9633             QStringList scl = s.split("\t");
9634             scl.pop_front();
9635             if (d_file_version < 88) {
9636                 double step = scl[2].toDouble();
9637                 if (scl[5] == "0")
9638                     step = 0.0;
9639                 ag->setScale(QwtPlot::xBottom, scl[0].toDouble(), scl[1].toDouble(), step,
9640                              scl[3].toInt(), scl[4].toInt(), scl[6].toInt(), bool(scl[7].toInt()));
9641                 ag->setScale(QwtPlot::xTop, scl[0].toDouble(), scl[1].toDouble(), step,
9642                              scl[3].toInt(), scl[4].toInt(), scl[6].toInt(), bool(scl[7].toInt()));
9643 
9644                 step = scl[10].toDouble();
9645                 if (scl[13] == "0")
9646                     step = 0.0;
9647                 ag->setScale(QwtPlot::yLeft, scl[8].toDouble(), scl[9].toDouble(), step,
9648                              scl[11].toInt(), scl[12].toInt(), scl[14].toInt(),
9649                              bool(scl[15].toInt()));
9650                 ag->setScale(QwtPlot::yRight, scl[8].toDouble(), scl[9].toDouble(), step,
9651                              scl[11].toInt(), scl[12].toInt(), scl[14].toInt(),
9652                              bool(scl[15].toInt()));
9653             } else
9654                 ag->setScale(scl[0].toInt(), scl[1].toDouble(), scl[2].toDouble(),
9655                              scl[3].toDouble(), scl[4].toInt(), scl[5].toInt(), scl[6].toInt(),
9656                              bool(scl[7].toInt()));
9657         } else if (s.contains("PlotTitle")) {
9658             QStringList fList = s.split("\t");
9659             ag->setTitle(fList[1]);
9660             ag->setTitleColor(QColor(COLORVALUE(fList[2])));
9661             ag->setTitleAlignment(fList[3].toInt());
9662         } else if (s.contains("TitleFont")) {
9663             QStringList fList = s.split("\t");
9664             QFont fnt = QFont(fList[1], fList[2].toInt(), fList[3].toInt(), fList[4].toInt());
9665             fnt.setUnderline(fList[5].toInt());
9666             fnt.setStrikeOut(fList[6].toInt());
9667             ag->setTitleFont(fnt);
9668         } else if (s.contains("AxesTitles")) {
9669             QStringList legend = s.split("\t");
9670             legend.pop_front();
9671             for (int i = 0; i < 4; i++) {
9672                 if (legend.count() > i)
9673                     ag->setAxisTitle(Graph::mapToQwtAxis(i), legend[i]);
9674             }
9675         } else if (s.contains("AxesTitleColors")) {
9676 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9677             QStringList colors = s.split("\t", Qt::SkipEmptyParts);
9678 #else
9679             QStringList colors = s.split("\t", QString::SkipEmptyParts);
9680 #endif
9681             ag->setAxesTitleColor(colors);
9682         } else if (s.contains("AxesTitleAlignment")) {
9683 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9684             QStringList align = s.split("\t", Qt::SkipEmptyParts);
9685 #else
9686             QStringList align = s.split("\t", QString::SkipEmptyParts);
9687 #endif
9688             ag->setAxesTitlesAlignment(align);
9689         } else if (s.contains("ScaleFont")) {
9690             QStringList fList = s.split("\t");
9691             QFont fnt = QFont(fList[1], fList[2].toInt(), fList[3].toInt(), fList[4].toInt());
9692             fnt.setUnderline(fList[5].toInt());
9693             fnt.setStrikeOut(fList[6].toInt());
9694 
9695             int axis = (fList[0].right(1)).toInt();
9696             ag->setAxisTitleFont(axis, fnt);
9697         } else if (s.contains("AxisFont")) {
9698             QStringList fList = s.split("\t");
9699             QFont fnt = QFont(fList[1], fList[2].toInt(), fList[3].toInt(), fList[4].toInt());
9700             fnt.setUnderline(fList[5].toInt());
9701             fnt.setStrikeOut(fList[6].toInt());
9702 
9703             int axis = (fList[0].right(1)).toInt();
9704             ag->setAxisFont(axis, fnt);
9705         } else if (s.contains("AxesFormulas")) {
9706             QStringList fList = s.split("\t");
9707             fList.removeAll(fList.first());
9708             ag->setAxesFormulas(fList);
9709         } else if (s.startsWith("<AxisFormula ")) {
9710             int pos = s.mid(18, s.length() - 20).toInt();
9711             QString formula;
9712             for (j++; j < (int)list.count() && list[j] != "</AxisFormula>"; j++)
9713                 formula += list[j] + "\n";
9714             formula.truncate(formula.length() - 1);
9715             ag->setAxisFormula(pos, formula);
9716         } else if (s.contains("LabelsFormat")) {
9717             QStringList fList = s.split("\t");
9718             fList.pop_front();
9719             ag->setLabelsNumericFormat(fList);
9720         } else if (s.contains("LabelsRotation")) {
9721             QStringList fList = s.split("\t");
9722             ag->setAxisLabelRotation(QwtPlot::xBottom, fList[1].toInt());
9723             ag->setAxisLabelRotation(QwtPlot::xTop, fList[2].toInt());
9724         } else if (s.contains("DrawAxesBackbone")) {
9725             QStringList fList = s.split("\t");
9726             ag->loadAxesOptions(fList[1]);
9727         } else if (s.contains("AxesLineWidth")) {
9728             QStringList fList = s.split("\t");
9729             ag->loadAxesLinewidth(fList[1].toInt());
9730         } else if (s.contains("CanvasFrame")) {
9731             QStringList list = s.split("\t");
9732             ag->drawCanvasFrame(list);
9733         } else if (s.contains("CanvasBackground")) {
9734             QStringList list = s.split("\t");
9735             QColor c = QColor(COLORVALUE(list[1]));
9736             if (list.count() == 3)
9737                 c.setAlpha(list[2].toInt());
9738             ag->setCanvasBackground(c);
9739         } else if (s.contains("Legend")) { // version <= 0.8.9
9740 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9741             QStringList fList = s.split("\t", Qt::KeepEmptyParts);
9742 #else
9743             QStringList fList = s.split("\t", QString::KeepEmptyParts);
9744 #endif
9745             ag->insertLegend(fList, d_file_version);
9746         } else if (s.startsWith("<legend>") && s.endsWith("</legend>")) {
9747 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9748             QStringList fList = s.remove("</legend>").split("\t", Qt::KeepEmptyParts);
9749 #else
9750             QStringList fList = s.remove("</legend>").split("\t", QString::KeepEmptyParts);
9751 #endif
9752             ag->insertLegend(fList, d_file_version);
9753         } else if (s.contains("textMarker")) { // version <= 0.8.9
9754 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9755             QStringList fList = s.split("\t", Qt::KeepEmptyParts);
9756 #else
9757             QStringList fList = s.split("\t", QString::KeepEmptyParts);
9758 #endif
9759             ag->insertTextMarker(fList, d_file_version);
9760         } else if (s.startsWith("<text>") && s.endsWith("</text>")) {
9761 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9762             QStringList fList = s.remove("</text>").split("\t", Qt::KeepEmptyParts);
9763 #else
9764             QStringList fList = s.remove("</text>").split("\t", QString::KeepEmptyParts);
9765 #endif
9766             ag->insertTextMarker(fList, d_file_version);
9767         } else if (s.contains("lineMarker")) { // version <= 0.8.9
9768             QStringList fList = s.split("\t");
9769             ag->addArrow(fList, d_file_version);
9770         } else if (s.startsWith("<line>") && s.endsWith("</line>")) {
9771             QStringList fList = s.remove("</line>").split("\t");
9772             ag->addArrow(fList, d_file_version);
9773         } else if (s.contains("ImageMarker")
9774                    || (s.startsWith("<image>") && s.endsWith("</image>"))) {
9775             QStringList fList = s.remove("</image>").split("\t");
9776             ag->insertImageMarker(fList, d_file_version);
9777         } else if (s.contains("AxisType")) {
9778             QStringList fList = s.split("\t");
9779             if (fList.size() >= 5)
9780                 for (int i = 0; i < 4; i++) {
9781 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9782                     QStringList lst = fList[i + 1].split(";", Qt::SkipEmptyParts);
9783 #else
9784                     QStringList lst = fList[i + 1].split(";", QString::SkipEmptyParts);
9785 #endif
9786                     if (lst.size() < 2)
9787                         continue;
9788                     Graph::AxisType format = static_cast<Graph::AxisType>(lst[0].toInt());
9789                     switch (format) {
9790                     case Graph::AxisType::Day:
9791                         ag->setLabelsDayFormat(i, lst[1].toInt());
9792                         break;
9793                     case Graph::AxisType::Month:
9794                         ag->setLabelsMonthFormat(i, lst[1].toInt());
9795                         break;
9796                     case Graph::AxisType::Time:
9797                     case Graph::AxisType::Date:
9798                     case Graph::AxisType::DateTime:
9799                         ag->setLabelsDateTimeFormat(i, format, lst[1] + ";" + lst[2]);
9800                         break;
9801                     case Graph::AxisType::Txt:
9802                         ag->setLabelsTextFormat(i, app->table(lst[1]), lst[1]);
9803                         break;
9804                     case Graph::AxisType::ColHeader:
9805                         ag->setLabelsColHeaderFormat(i, app->table(lst[1]));
9806                         break;
9807                     }
9808                 }
9809         } else if (d_file_version < 69 && s.contains("AxesTickLabelsCol")) {
9810             QStringList fList = s.split("\t");
9811             if (fList.size() >= 5) {
9812                 const QList<Graph::AxisType> &axesTypes = ag->axesType();
9813                 for (int i = 0; i < 4; i++) {
9814                     switch (axesTypes[i]) {
9815                     case Graph::AxisType::Txt:
9816                         ag->setLabelsTextFormat(i, app->table(fList[i + 1]), fList[i + 1]);
9817                         break;
9818                     case Graph::AxisType::ColHeader:
9819                         ag->setLabelsColHeaderFormat(i, app->table(fList[i + 1]));
9820                         break;
9821                     }
9822                 }
9823             }
9824         }
9825     }
9826     ag->replot();
9827     if (ag->isPiePlot()) {
9828         QwtPieCurve *c = (QwtPieCurve *)ag->curve(0);
9829         if (c)
9830             c->updateBoundingRect();
9831     }
9832 
9833     ag->blockSignals(false);
9834     ag->setIgnoreResizeEvents(!app->autoResizeLayers);
9835     ag->setAutoscaleFonts(app->autoScaleFonts);
9836     ag->setTextMarkerDefaults(app->legendFrameStyle, app->plotLegendFont, app->legendTextColor,
9837                               app->legendBackground);
9838     ag->setArrowDefaults(app->defaultArrowLineWidth, app->defaultArrowColor,
9839                          app->defaultArrowLineStyle, app->defaultArrowHeadLength,
9840                          app->defaultArrowHeadAngle, app->defaultArrowHeadFill);
9841     return ag;
9842 }
9843 
openSurfacePlot(ApplicationWindow * app,const QStringList & lst)9844 Graph3D *ApplicationWindow::openSurfacePlot(ApplicationWindow *app, const QStringList &lst)
9845 {
9846     QStringList fList = lst[0].split("\t");
9847     QString caption = fList[0];
9848     QString date = fList[1];
9849     if (date.isEmpty())
9850         date = QLocale().toString(QDateTime::currentDateTime());
9851 
9852 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9853     fList = lst[2].split("\t", Qt::SkipEmptyParts);
9854 #else
9855     fList = lst[2].split("\t", QString::SkipEmptyParts);
9856 #endif
9857     Graph3D *plot = 0;
9858 
9859     if (fList[1].endsWith("(Y)", Qt::CaseSensitive)) // Ribbon plot
9860         plot = app->dataPlot3D(caption, fList[1], fList[2].toDouble(), fList[3].toDouble(),
9861                                fList[4].toDouble(), fList[5].toDouble(), fList[6].toDouble(),
9862                                fList[7].toDouble());
9863     else if (fList[1].contains("(Z)", Qt::CaseSensitive))
9864         plot = app->dataPlotXYZ(caption, fList[1], fList[2].toDouble(), fList[3].toDouble(),
9865                                 fList[4].toDouble(), fList[5].toDouble(), fList[6].toDouble(),
9866                                 fList[7].toDouble());
9867     else if (fList[1].startsWith("matrix<", Qt::CaseSensitive)
9868              && fList[1].endsWith(">", Qt::CaseInsensitive))
9869         plot = app->openMatrixPlot3D(caption, fList[1], fList[2].toDouble(), fList[3].toDouble(),
9870                                      fList[4].toDouble(), fList[5].toDouble(), fList[6].toDouble(),
9871                                      fList[7].toDouble());
9872     else
9873         plot = app->newPlot3D(caption, fList[1], fList[2].toDouble(), fList[3].toDouble(),
9874                               fList[4].toDouble(), fList[5].toDouble(), fList[6].toDouble(),
9875                               fList[7].toDouble());
9876 
9877     if (!plot)
9878         return 0;
9879 
9880     app->setListViewDate(caption, date);
9881     plot->setBirthDate(date);
9882     plot->setIgnoreFonts(true);
9883     restoreWindowGeometry(app, plot, lst[1]);
9884 
9885 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
9886     fList = lst[3].split("\t", Qt::SkipEmptyParts);
9887     plot->setStyle(fList);
9888 
9889     fList = lst[4].split("\t", Qt::SkipEmptyParts);
9890     plot->setGrid(fList[1].toInt());
9891 
9892     fList = lst[5].split("\t");
9893     plot->setTitle(fList);
9894 
9895     fList = lst[6].split("\t", Qt::SkipEmptyParts);
9896     plot->setColors(fList);
9897 
9898     fList = lst[7].split("\t", Qt::SkipEmptyParts);
9899     fList.pop_front();
9900     plot->setAxesLabels(fList);
9901 
9902     fList = lst[8].split("\t", Qt::SkipEmptyParts);
9903     plot->setTicks(fList);
9904 
9905     fList = lst[9].split("\t", Qt::SkipEmptyParts);
9906     plot->setTickLengths(fList);
9907 
9908     fList = lst[10].split("\t", Qt::SkipEmptyParts);
9909     plot->setOptions(fList);
9910 
9911     fList = lst[11].split("\t", Qt::SkipEmptyParts);
9912     plot->setNumbersFont(fList);
9913 
9914     fList = lst[12].split("\t", Qt::SkipEmptyParts);
9915     plot->setXAxisLabelFont(fList);
9916 
9917     fList = lst[13].split("\t", Qt::SkipEmptyParts);
9918     plot->setYAxisLabelFont(fList);
9919 
9920     fList = lst[14].split("\t", Qt::SkipEmptyParts);
9921     plot->setZAxisLabelFont(fList);
9922 
9923     fList = lst[15].split("\t", Qt::SkipEmptyParts);
9924     plot->setRotation(fList[1].toDouble(), fList[2].toDouble(), fList[3].toDouble());
9925 
9926     fList = lst[16].split("\t", Qt::SkipEmptyParts);
9927     plot->setZoom(fList[1].toDouble());
9928 
9929     fList = lst[17].split("\t", Qt::SkipEmptyParts);
9930     plot->setScale(fList[1].toDouble(), fList[2].toDouble(), fList[3].toDouble());
9931 
9932     fList = lst[18].split("\t", Qt::SkipEmptyParts);
9933     plot->setShift(fList[1].toDouble(), fList[2].toDouble(), fList[3].toDouble());
9934 
9935     fList = lst[19].split("\t", Qt::SkipEmptyParts);
9936     plot->setMeshLineWidth(fList[1].toInt());
9937 #else
9938     fList = lst[3].split("\t", QString::SkipEmptyParts);
9939     plot->setStyle(fList);
9940 
9941     fList = lst[4].split("\t", QString::SkipEmptyParts);
9942     plot->setGrid(fList[1].toInt());
9943 
9944     fList = lst[5].split("\t");
9945     plot->setTitle(fList);
9946 
9947     fList = lst[6].split("\t", QString::SkipEmptyParts);
9948     plot->setColors(fList);
9949 
9950     fList = lst[7].split("\t", QString::SkipEmptyParts);
9951     fList.pop_front();
9952     plot->setAxesLabels(fList);
9953 
9954     fList = lst[8].split("\t", QString::SkipEmptyParts);
9955     plot->setTicks(fList);
9956 
9957     fList = lst[9].split("\t", QString::SkipEmptyParts);
9958     plot->setTickLengths(fList);
9959 
9960     fList = lst[10].split("\t", QString::SkipEmptyParts);
9961     plot->setOptions(fList);
9962 
9963     fList = lst[11].split("\t", QString::SkipEmptyParts);
9964     plot->setNumbersFont(fList);
9965 
9966     fList = lst[12].split("\t", QString::SkipEmptyParts);
9967     plot->setXAxisLabelFont(fList);
9968 
9969     fList = lst[13].split("\t", QString::SkipEmptyParts);
9970     plot->setYAxisLabelFont(fList);
9971 
9972     fList = lst[14].split("\t", QString::SkipEmptyParts);
9973     plot->setZAxisLabelFont(fList);
9974 
9975     fList = lst[15].split("\t", QString::SkipEmptyParts);
9976     plot->setRotation(fList[1].toDouble(), fList[2].toDouble(), fList[3].toDouble());
9977 
9978     fList = lst[16].split("\t", QString::SkipEmptyParts);
9979     plot->setZoom(fList[1].toDouble());
9980 
9981     fList = lst[17].split("\t", QString::SkipEmptyParts);
9982     plot->setScale(fList[1].toDouble(), fList[2].toDouble(), fList[3].toDouble());
9983 
9984     fList = lst[18].split("\t", QString::SkipEmptyParts);
9985     plot->setShift(fList[1].toDouble(), fList[2].toDouble(), fList[3].toDouble());
9986 
9987     fList = lst[19].split("\t", QString::SkipEmptyParts);
9988     plot->setMeshLineWidth(fList[1].toInt());
9989 #endif
9990 
9991     if (d_file_version > 71) {
9992         fList = lst[20].split(
9993                 "\t"); // using QString::SkipEmptyParts here causes a crash for empty window labels
9994         plot->setWindowLabel(fList[1]);
9995         plot->setCaptionPolicy((MyWidget::CaptionPolicy)fList[2].toInt());
9996         app->setListViewLabel(plot->name(), fList[1]);
9997     }
9998 
9999     if (d_file_version >= 88) {
10000 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
10001         fList = lst[21].split("\t", Qt::SkipEmptyParts);
10002 #else
10003         fList = lst[21].split("\t", QString::SkipEmptyParts);
10004 #endif
10005         plot->setOrtho(fList[1].toInt());
10006     }
10007 
10008     plot->update();
10009     plot->setIgnoreFonts(true);
10010     return plot;
10011 }
10012 
copyActiveLayer()10013 void ApplicationWindow::copyActiveLayer()
10014 {
10015     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
10016         return;
10017 
10018     copiedLayer = true;
10019 
10020     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
10021     delete lastCopiedLayer;
10022     lastCopiedLayer = new Graph(0, 0, Qt::Widget);
10023     lastCopiedLayer->setAttribute(Qt::WA_DeleteOnClose);
10024     lastCopiedLayer->setGeometry(0, 0, g->width(), g->height());
10025     lastCopiedLayer->copy(this, g);
10026     g->copyImage();
10027 }
10028 
showDataSetDialog(const QString & whichFit)10029 void ApplicationWindow::showDataSetDialog(const QString &whichFit)
10030 {
10031     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
10032         return;
10033 
10034     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
10035     if (!g)
10036         return;
10037 
10038     DataSetDialog *ad = new DataSetDialog(tr("Curve") + ": ", this);
10039     ad->setAttribute(Qt::WA_DeleteOnClose);
10040     ad->setGraph(g);
10041     ad->setOperationType(whichFit);
10042     ad->exec();
10043 }
10044 
analyzeCurve(Graph * g,const QString & whichFit,const QString & curveTitle)10045 void ApplicationWindow::analyzeCurve(Graph *g, const QString &whichFit, const QString &curveTitle)
10046 {
10047     if (whichFit == "fitLinear" || whichFit == "fitSigmoidal" || whichFit == "fitGauss"
10048         || whichFit == "fitLorentz") {
10049         Fit *fitter = 0;
10050         if (whichFit == "fitLinear")
10051             fitter = new LinearFit(this, g);
10052         else if (whichFit == "fitSigmoidal")
10053             fitter = new SigmoidalFit(this, g);
10054         else if (whichFit == "fitGauss")
10055             fitter = new GaussFit(this, g);
10056         else if (whichFit == "fitLorentz")
10057             fitter = new LorentzFit(this, g);
10058 
10059         if (fitter->setDataFromCurve(curveTitle)) {
10060             if (whichFit != "fitLinear")
10061                 fitter->guessInitialValues();
10062 
10063             fitter->scaleErrors(fit_scale_errors);
10064             fitter->setOutputPrecision(fit_output_precision);
10065 
10066             if (whichFit == "fitLinear" && d_2_linear_fit_points)
10067                 fitter->generateFunction(generateUniformFitPoints, 2);
10068             else
10069                 fitter->generateFunction(generateUniformFitPoints, fitPoints);
10070             fitter->fit();
10071             if (pasteFitResultsToPlot)
10072                 fitter->showLegend();
10073             delete fitter;
10074         }
10075     } else if (whichFit == "differentiate") {
10076         Differentiation *diff = new Differentiation(this, g, curveTitle);
10077         diff->run();
10078         delete diff;
10079     }
10080 }
10081 
analysis(const QString & whichFit)10082 void ApplicationWindow::analysis(const QString &whichFit)
10083 {
10084     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("MultiLayer"))
10085         return;
10086 
10087     Graph *g = ((MultiLayer *)d_workspace.activeSubWindow())->activeGraph();
10088     if (!g || !g->validCurvesDataSize())
10089         return;
10090 
10091     QString curve_title = g->selectedCurveTitle();
10092     if (!curve_title.isNull()) {
10093         analyzeCurve(g, whichFit, curve_title);
10094         return;
10095     }
10096 
10097     QStringList lst = g->analysableCurvesList();
10098     if (lst.count() == 1) {
10099         const QwtPlotCurve *c = g->curve(lst[0]);
10100         if (c)
10101             analyzeCurve(g, whichFit, lst[0]);
10102     } else
10103         showDataSetDialog(whichFit);
10104 }
10105 
pickPointerCursor()10106 void ApplicationWindow::pickPointerCursor()
10107 {
10108     btnPointer->setChecked(true);
10109 }
10110 
pickDataTool(QAction * action)10111 void ApplicationWindow::pickDataTool(QAction *action)
10112 {
10113     if (!action)
10114         return;
10115 
10116     MultiLayer *m = qobject_cast<MultiLayer *>(d_workspace.activeSubWindow());
10117     if (!m)
10118         return;
10119 
10120     Graph *g = m->activeGraph();
10121     if (!g)
10122         return;
10123 
10124     g->disableTools();
10125 
10126     if (action == btnCursor)
10127         showCursor();
10128     else if (action == btnSelect)
10129         showRangeSelectors();
10130     else if (action == btnPicker)
10131         showScreenReader();
10132     else if (action == btnMovePoints)
10133         movePoints();
10134     else if (action == btnRemovePoints)
10135         removePoints();
10136     else if (action == btnZoomIn)
10137         zoomIn();
10138     else if (action == btnZoomOut)
10139         zoomOut();
10140     else if (action == btnArrow)
10141         drawArrow();
10142     else if (action == btnLine)
10143         drawLine();
10144 }
10145 
connectSurfacePlot(Graph3D * plot)10146 void ApplicationWindow::connectSurfacePlot(Graph3D *plot)
10147 {
10148     connect(plot, SIGNAL(showTitleBarMenu()), this, SLOT(showWindowTitleBarMenu()));
10149     connect(plot, SIGNAL(showContextMenu()), this, SLOT(showWindowContextMenu()));
10150     connect(plot, SIGNAL(showOptionsDialog()), this, SLOT(showPlot3dDialog()));
10151     connect(plot, SIGNAL(closedWindow(MyWidget *)), this, SLOT(closeWindow(MyWidget *)));
10152     connect(plot, SIGNAL(hiddenWindow(MyWidget *)), this, SLOT(hideWindow(MyWidget *)));
10153     connect(plot, SIGNAL(statusChanged(MyWidget *)), this, SLOT(updateWindowStatus(MyWidget *)));
10154     connect(plot, SIGNAL(modified()), this, SIGNAL(modified()));
10155     connect(plot, SIGNAL(custom3DActions(MyWidget *)), this, SLOT(custom3DActions(MyWidget *)));
10156 
10157     plot->askOnCloseEvent(confirmClosePlot3D);
10158 }
10159 
connectMultilayerPlot(MultiLayer * g)10160 void ApplicationWindow::connectMultilayerPlot(MultiLayer *g)
10161 {
10162     connect(g, SIGNAL(showTitleBarMenu()), this, SLOT(showWindowTitleBarMenu()));
10163     connect(g, SIGNAL(showTextDialog()), this, SLOT(showTextDialog()));
10164     connect(g, SIGNAL(showPlotDialog(int)), this, SLOT(showPlotDialog(int)));
10165     connect(g, SIGNAL(showScaleDialog(int)), this, SLOT(showScalePageFromAxisDialog(int)));
10166     connect(g, SIGNAL(showAxisDialog(int)), this, SLOT(showAxisPageFromAxisDialog(int)));
10167     connect(g, SIGNAL(showCurveContextMenu(int)), this, SLOT(showCurveContextMenu(int)));
10168     connect(g, SIGNAL(showWindowContextMenu()), this, SLOT(showWindowContextMenu()));
10169     connect(g, SIGNAL(showCurvesDialog()), this, SLOT(showCurvesDialog()));
10170     connect(g, SIGNAL(drawLineEnded(bool)), btnPointer, SLOT(setChecked(bool)));
10171     connect(g, SIGNAL(drawTextOff()), this, SLOT(disableAddText()));
10172     connect(g, SIGNAL(showXAxisTitleDialog()), this, SLOT(showXAxisTitleDialog()));
10173     connect(g, SIGNAL(showYAxisTitleDialog()), this, SLOT(showYAxisTitleDialog()));
10174     connect(g, SIGNAL(showRightAxisTitleDialog()), this, SLOT(showRightAxisTitleDialog()));
10175     connect(g, SIGNAL(showTopAxisTitleDialog()), this, SLOT(showTopAxisTitleDialog()));
10176     connect(g, SIGNAL(showMarkerPopupMenu()), this, SLOT(showMarkerPopupMenu()));
10177     connect(g, SIGNAL(closedWindow(MyWidget *)), this, SLOT(closeWindow(MyWidget *)));
10178     connect(g, SIGNAL(hiddenWindow(MyWidget *)), this, SLOT(hideWindow(MyWidget *)));
10179     connect(g, SIGNAL(statusChanged(MyWidget *)), this, SLOT(updateWindowStatus(MyWidget *)));
10180     connect(g, SIGNAL(cursorInfo(const QString &)), d_status_info, SLOT(setText(const QString &)));
10181     connect(g, SIGNAL(showImageDialog()), this, SLOT(showImageDialog()));
10182     connect(g, SIGNAL(createTable(const QString &, const QString &, QList<Column *>)), this,
10183             SLOT(newTable(const QString &, const QString &, QList<Column *>)));
10184     connect(g, SIGNAL(viewTitleDialog()), this, SLOT(showTitleDialog()));
10185     connect(g, SIGNAL(modifiedWindow(MyWidget *)), this, SLOT(modifiedProject(MyWidget *)));
10186     connect(g, SIGNAL(modifiedPlot()), this, SLOT(modifiedProject()));
10187     connect(g, SIGNAL(showLineDialog()), this, SLOT(showLineDialog()));
10188     connect(g, SIGNAL(showGeometryDialog()), this, SLOT(showPlotGeometryDialog()));
10189     connect(g, SIGNAL(pasteMarker()), this, SLOT(pasteSelection()));
10190     connect(g, SIGNAL(showGraphContextMenu()), this, SLOT(showGraphContextMenu()));
10191     connect(g, SIGNAL(showLayerButtonContextMenu()), this, SLOT(showLayerButtonContextMenu()));
10192     connect(g, SIGNAL(createIntensityTable(const QString &)), this,
10193             SLOT(importImage(const QString &)));
10194     connect(g, SIGNAL(setPointerCursor()), this, SLOT(pickPointerCursor()));
10195 
10196     g->askOnCloseEvent(confirmClosePlot2D);
10197 }
10198 
connectTable(Table * w)10199 void ApplicationWindow::connectTable(Table *w)
10200 {
10201     connect(w, SIGNAL(showTitleBarMenu()), this, SLOT(showWindowTitleBarMenu()));
10202     connect(w, SIGNAL(statusChanged(MyWidget *)), this, SLOT(updateWindowStatus(MyWidget *)));
10203     connect(w, SIGNAL(hiddenWindow(MyWidget *)), this, SLOT(hideWindow(MyWidget *)));
10204     connect(w, SIGNAL(closedWindow(MyWidget *)), this, SLOT(closeWindow(MyWidget *)));
10205     connect(w, SIGNAL(aboutToRemoveCol(const QString &)), this,
10206             SLOT(removeCurves(const QString &)));
10207     connect(w, SIGNAL(modifiedData(Table *, const QString &)), this,
10208             SLOT(updateCurves(Table *, const QString &)));
10209     connect(w, SIGNAL(modifiedWindow(MyWidget *)), this, SLOT(modifiedProject(MyWidget *)));
10210     connect(w, SIGNAL(changedColHeader(const QString &, const QString &)), this,
10211             SLOT(updateColNames(const QString &, const QString &)));
10212 
10213 #ifdef LEGACY_CODE_0_2_x
10214     connect(w->d_future_table, SIGNAL(requestRowStatistics()), this, SLOT(showRowStatistics()));
10215     connect(w->d_future_table, SIGNAL(requestColumnStatistics()), this, SLOT(showColStatistics()));
10216 #endif
10217     w->askOnCloseEvent(confirmCloseTable);
10218 }
10219 
setAppColors(const QColor & wc,const QColor & pc,const QColor & tpc)10220 void ApplicationWindow::setAppColors(const QColor &wc, const QColor &pc, const QColor &tpc)
10221 {
10222     if (workspaceColor != wc) {
10223         workspaceColor = wc;
10224         d_workspace.setBackground(wc);
10225     }
10226 
10227     if (panelsColor == pc && panelsTextColor == tpc)
10228         return;
10229 
10230     panelsColor = pc;
10231     panelsTextColor = tpc;
10232 
10233     QPalette cg;
10234     cg.setColor(QPalette::Base, QColor(panelsColor));
10235     qApp->setPalette(cg);
10236 
10237     cg.setColor(QPalette::Text, QColor(panelsTextColor));
10238     cg.setColor(QPalette::WindowText, QColor(panelsTextColor));
10239     cg.setColor(QPalette::HighlightedText, QColor(panelsTextColor));
10240     lv.setPalette(cg);
10241     results->setPalette(cg);
10242 }
10243 
setPlot3DOptions()10244 void ApplicationWindow::setPlot3DOptions()
10245 {
10246     QList<MyWidget *> windows = windowsList();
10247     for (int i = 0; i < int(windows.count()); i++) {
10248         if (windows.at(i)->inherits("Graph3D")) {
10249             Graph3D *g = (Graph3D *)windows.at(i);
10250             g->setSmoothMesh(smooth3DMesh);
10251             g->setOrtho(orthogonal3DPlots);
10252             g->setAutoscale(autoscale3DPlots);
10253         }
10254     }
10255 }
10256 
createActions()10257 void ApplicationWindow::createActions()
10258 {
10259     actionNewProject = new QAction(QIcon(QPixmap(":/new.xpm")), tr("New &Project"), this);
10260     actionNewProject->setShortcut(tr("Ctrl+N"));
10261     connect(actionNewProject, SIGNAL(triggered()), this, SLOT(newProject()));
10262 
10263     actionNewGraph = new QAction(QIcon(QPixmap(":/new_graph.xpm")), tr("New &Graph"), this);
10264     actionNewGraph->setShortcut(tr("Ctrl+G"));
10265     connect(actionNewGraph, SIGNAL(triggered()), this, SLOT(newGraph()));
10266 
10267     actionNewNote = new QAction(QIcon(QPixmap(":/new_note.xpm")), tr("New &Note / Script"), this);
10268     actionNewNote->setShortcut(tr("Ctrl+ALT+N"));
10269     connect(actionNewNote, SIGNAL(triggered()), this, SLOT(newNote()));
10270 
10271     actionNewTable = new QAction(QIcon(QPixmap(":/table.xpm")), tr("New &Table"), this);
10272     actionNewTable->setShortcut(tr("Ctrl+T"));
10273     connect(actionNewTable, SIGNAL(triggered()), this, SLOT(newTable()));
10274 
10275     actionNewMatrix = new QAction(QIcon(QPixmap(":/new_matrix.xpm")), tr("New &Matrix"), this);
10276     actionNewMatrix->setShortcut(tr("Ctrl+M"));
10277     connect(actionNewMatrix, SIGNAL(triggered()), this, SLOT(newMatrix()));
10278 
10279     actionNewFunctionPlot =
10280             new QAction(QIcon(QPixmap(":/newF.xpm")), tr("New &Function Plot"), this);
10281     actionNewFunctionPlot->setShortcut(tr("Ctrl+F"));
10282     connect(actionNewFunctionPlot, SIGNAL(triggered()), this, SLOT(functionDialog()));
10283 
10284     actionNewSurfacePlot =
10285             new QAction(QIcon(QPixmap(":/newFxy.xpm")), tr("New 3D &Surface Plot"), this);
10286     actionNewSurfacePlot->setShortcut(tr("Ctrl+ALT+Z"));
10287     connect(actionNewSurfacePlot, SIGNAL(triggered()), this, SLOT(newSurfacePlot()));
10288 
10289     // FIXME: "..." should be added before translating, but this would break translations
10290     actionOpen = new QAction(QIcon(QPixmap(":/fileopen.xpm")), tr("&Open") + "...", this);
10291     actionOpen->setShortcut(tr("Ctrl+O"));
10292     connect(actionOpen, SIGNAL(triggered()), this, SLOT(open()));
10293 
10294     actionLoadImage = new QAction(tr("Open Image &File"), this);
10295     actionLoadImage->setShortcut(tr("Ctrl+I"));
10296     connect(actionLoadImage, SIGNAL(triggered()), this, SLOT(loadImage()));
10297 
10298     actionImportImage = new QAction(tr("Import I&mage..."), this);
10299     connect(actionImportImage, SIGNAL(triggered()), this, SLOT(importImage()));
10300 
10301     actionSaveProject = new QAction(QIcon(QPixmap(":/filesave.xpm")), tr("&Save Project"), this);
10302     actionSaveProject->setShortcut(tr("Ctrl+S"));
10303     connect(actionSaveProject, SIGNAL(triggered()), this, SLOT(saveProject()));
10304     savedProject();
10305 
10306     actionSaveProjectAs = new QAction(tr("Save Project &As..."), this);
10307     connect(actionSaveProjectAs, SIGNAL(triggered()), this, SLOT(saveProjectAs()));
10308 
10309     actionOpenTemplate =
10310             new QAction(QIcon(QPixmap(":/open_template.xpm")), tr("Open Temp&late..."), this);
10311     connect(actionOpenTemplate, SIGNAL(triggered()), this, SLOT(openTemplate()));
10312 
10313     actionSaveTemplate =
10314             new QAction(QIcon(QPixmap(":/save_template.xpm")), tr("Save As &Template..."), this);
10315     connect(actionSaveTemplate, SIGNAL(triggered()), this, SLOT(saveAsTemplate()));
10316 
10317     actionSaveNote = new QAction(tr("Save Note As..."), this);
10318     connect(actionSaveNote, SIGNAL(triggered()), this, SLOT(saveNoteAs()));
10319 
10320     actionLoad = new QAction(QIcon(QPixmap(":/import.xpm")), tr("&Import ASCII..."), this);
10321     connect(actionLoad, SIGNAL(triggered()), this, SLOT(importASCII()));
10322 
10323     actionUndo = new QAction(IconLoader::load("edit-undo"), tr("&Undo"), this);
10324     actionUndo->setShortcut(tr("Ctrl+Z"));
10325     connect(actionUndo, SIGNAL(triggered()), this, SLOT(undo()));
10326     actionUndo->setEnabled(false);
10327 
10328     actionRedo = new QAction(IconLoader::load("edit-redo"), tr("&Redo"), this);
10329     actionRedo->setShortcut(tr("Ctrl+R"));
10330     connect(actionRedo, SIGNAL(triggered()), this, SLOT(redo()));
10331     actionRedo->setEnabled(false);
10332 
10333     actionCopyWindow = new QAction(QIcon(QPixmap(":/duplicate.xpm")), tr("&Duplicate"), this);
10334     connect(actionCopyWindow, SIGNAL(triggered()), this, SLOT(clone()));
10335 
10336     actionCutSelection = new QAction(IconLoader::load("edit-cut"), tr("Cu&t Selection"), this);
10337     actionCutSelection->setShortcut(tr("Ctrl+X"));
10338     connect(actionCutSelection, SIGNAL(triggered()), this, SLOT(cutSelection()));
10339 
10340     actionCopySelection = new QAction(IconLoader::load("edit-copy"), tr("&Copy Selection"), this);
10341     actionCopySelection->setShortcut(tr("Ctrl+C"));
10342     connect(actionCopySelection, SIGNAL(triggered()), this, SLOT(copySelection()));
10343 
10344     actionPasteSelection =
10345             new QAction(IconLoader::load("edit-paste"), tr("&Paste Selection"), this);
10346     actionPasteSelection->setShortcut(tr("Ctrl+V"));
10347     connect(actionPasteSelection, SIGNAL(triggered()), this, SLOT(pasteSelection()));
10348 
10349     actionClearSelection =
10350             new QAction(QIcon(QPixmap(":/erase.xpm")), tr("&Delete Selection"), this);
10351     actionClearSelection->setShortcut(tr("Del", "delete key"));
10352     connect(actionClearSelection, SIGNAL(triggered()), this, SLOT(clearSelection()));
10353 
10354     locktoolbar = new QAction(QIcon(QPixmap(":/unlock.xpm")), tr("&Lock Toolbars"), this);
10355     locktoolbar->setCheckable(true);
10356     connect(locktoolbar, SIGNAL(toggled(bool)), this, SLOT(lockToolbar(bool)));
10357 
10358     actionShowExplorer = explorerWindow.toggleViewAction();
10359     actionShowExplorer->setIcon(QPixmap(":/folder.xpm"));
10360     actionShowExplorer->setShortcut(tr("Ctrl+E"));
10361 
10362     actionShowLog = logWindow.toggleViewAction();
10363     actionShowLog->setIcon(QPixmap(":/log.xpm"));
10364 
10365     actionShowHistory = new QAction(tr("Undo/Redo &History"), this);
10366     connect(actionShowHistory, SIGNAL(triggered(bool)), this, SLOT(showHistory()));
10367 
10368 #ifdef SCRIPTING_CONSOLE
10369     actionShowConsole = consoleWindow.toggleViewAction();
10370 #endif
10371 
10372     actionAddLayer = new QAction(QIcon(QPixmap(":/newLayer.xpm")), tr("Add La&yer"), this);
10373     actionAddLayer->setShortcut(tr("ALT+L"));
10374     connect(actionAddLayer, SIGNAL(triggered()), this, SLOT(addLayer()));
10375 
10376     // FIXME: "..." should be added before translating, but this would break translations
10377     actionShowLayerDialog =
10378             new QAction(QIcon(QPixmap(":/arrangeLayers.xpm")), tr("Arran&ge Layers") + "...", this);
10379     actionShowLayerDialog->setShortcut(tr("ALT+A"));
10380     connect(actionShowLayerDialog, SIGNAL(triggered()), this, SLOT(showLayerDialog()));
10381 
10382     actionAutomaticLayout =
10383             new QAction(QIcon(QPixmap(":/auto_layout.xpm")), tr("Automatic Layout"), this);
10384     connect(actionAutomaticLayout, SIGNAL(triggered()), this, SLOT(autoArrangeLayers()));
10385 
10386     // FIXME: "..." should be added before translating, but this would break translations
10387     actionExportGraph = new QAction(tr("&Current") + "...", this);
10388     actionExportGraph->setShortcut(tr("Alt+G"));
10389     connect(actionExportGraph, SIGNAL(triggered()), this, SLOT(exportGraph()));
10390 
10391     // FIXME: "..." should be added before translating, but this would break translations
10392     actionExportAllGraphs = new QAction(tr("&All") + "...", this);
10393     actionExportAllGraphs->setShortcut(tr("Alt+X"));
10394     connect(actionExportAllGraphs, SIGNAL(triggered()), this, SLOT(exportAllGraphs()));
10395 
10396     // FIXME: "..." should be added before translating, but this would break translations
10397     actionExportPDF = new QAction(QIcon(QPixmap(":/pdf.xpm")), tr("&Export PDF") + "...", this);
10398     actionExportPDF->setShortcut(tr("Ctrl+Alt+P"));
10399     connect(actionExportPDF, SIGNAL(triggered()), this, SLOT(exportPDF()));
10400 
10401     // FIXME: "..." should be added before translating, but this would break translations
10402     actionPrint = new QAction(QIcon(QPixmap(":/fileprint.xpm")), tr("&Print") + "...", this);
10403     actionPrint->setShortcut(tr("Ctrl+P"));
10404     connect(actionPrint, SIGNAL(triggered()), this, SLOT(print()));
10405 
10406     actionPrintAllPlots = new QAction(tr("Print All Plo&ts"), this);
10407     connect(actionPrintAllPlots, SIGNAL(triggered()), this, SLOT(printAllPlots()));
10408 
10409     // FIXME: "..." should be added before translating, but this would break translations
10410     actionShowExportASCIIDialog = new QAction(tr("E&xport ASCII") + "...", this);
10411     connect(actionShowExportASCIIDialog, SIGNAL(triggered()), this, SLOT(showExportASCIIDialog()));
10412 
10413     actionCloseAllWindows = new QAction(QIcon(QPixmap(":/quit.xpm")), tr("&Quit"), this);
10414     actionCloseAllWindows->setShortcut(tr("Ctrl+Q"));
10415     connect(actionCloseAllWindows, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
10416 
10417     actionClearLogInfo = new QAction(tr("Clear &Log Information"), this);
10418     connect(actionClearLogInfo, SIGNAL(triggered()), this, SLOT(clearLogInfo()));
10419 
10420     actionDeleteFitTables =
10421             new QAction(QIcon(QPixmap(":/close.xpm")), tr("Delete &Fit Tables"), this);
10422     connect(actionDeleteFitTables, SIGNAL(triggered()), this, SLOT(deleteFitTables()));
10423 
10424     // FIXME: "..." should be added before translating, but this would break translations
10425     actionShowPlotWizard =
10426             new QAction(QIcon(QPixmap(":/wizard.xpm")), tr("Plot &Wizard") + "...", this);
10427     actionShowPlotWizard->setShortcut(tr("Ctrl+Alt+W"));
10428     connect(actionShowPlotWizard, SIGNAL(triggered()), this, SLOT(showPlotWizard()));
10429 
10430     actionShowConfigureDialog = new QAction(tr("&Preferences..."), this);
10431     connect(actionShowConfigureDialog, SIGNAL(triggered()), this, SLOT(showPreferencesDialog()));
10432 
10433     actionShowCurvesDialog =
10434             new QAction(QIcon(QPixmap(":/curves.xpm")), tr("Add/Remove &Curve..."), this);
10435     actionShowCurvesDialog->setShortcut(tr("ALT+C"));
10436     connect(actionShowCurvesDialog, SIGNAL(triggered()), this, SLOT(showCurvesDialog()));
10437 
10438     actionAddErrorBars =
10439             new QAction(QIcon(QPixmap(":/yerror.xpm")), tr("Add &Error Bars..."), this);
10440     actionAddErrorBars->setShortcut(tr("Ctrl+B"));
10441     connect(actionAddErrorBars, SIGNAL(triggered()), this, SLOT(addErrorBars()));
10442 
10443     actionAddFunctionCurve = new QAction(QIcon(QPixmap(":/fx.xpm")), tr("Add &Function..."), this);
10444     actionAddFunctionCurve->setShortcut(tr("Ctrl+Alt+F"));
10445     connect(actionAddFunctionCurve, SIGNAL(triggered()), this, SLOT(addFunctionCurve()));
10446 
10447     actionUnzoom = new QAction(QIcon(QPixmap(":/unzoom.xpm")), tr("&Rescale to Show All"), this);
10448     actionUnzoom->setShortcut(tr("Ctrl+Shift+R"));
10449     connect(actionUnzoom, SIGNAL(triggered()), this, SLOT(setAutoScale()));
10450 
10451     actionNewLegend = new QAction(QIcon(QPixmap(":/legend.xpm")), tr("New &Legend"), this);
10452     actionNewLegend->setShortcut(tr("Ctrl+L"));
10453     connect(actionNewLegend, SIGNAL(triggered()), this, SLOT(newLegend()));
10454 
10455     actionTimeStamp = new QAction(QIcon(QPixmap(":/clock.xpm")), tr("Add Time Stamp"), this);
10456     actionTimeStamp->setShortcut(tr("Ctrl+ALT+T"));
10457     connect(actionTimeStamp, SIGNAL(triggered()), this, SLOT(addTimeStamp()));
10458 
10459     actionAddImage = new QAction(QIcon(QPixmap(":/monalisa.xpm")), tr("Add &Image"), this);
10460     actionAddImage->setShortcut(tr("ALT+I"));
10461     connect(actionAddImage, SIGNAL(triggered()), this, SLOT(addImage()));
10462 
10463     d_plot_mapper = new QSignalMapper;
10464     connect(d_plot_mapper, SIGNAL(mapped(int)), this, SLOT(selectPlotType(int)));
10465 
10466     actionPlotL = new QAction(QIcon(QPixmap(":/lPlot.xpm")), tr("&Line"), this);
10467     connect(actionPlotL, SIGNAL(triggered()), d_plot_mapper, SLOT(map()));
10468     d_plot_mapper->setMapping(actionPlotL, Graph::Line);
10469 
10470     actionPlotP = new QAction(QIcon(QPixmap(":/pPlot.xpm")), tr("&Scatter"), this);
10471     connect(actionPlotP, SIGNAL(triggered()), d_plot_mapper, SLOT(map()));
10472     d_plot_mapper->setMapping(actionPlotP, Graph::Scatter);
10473 
10474     actionPlotLP = new QAction(QIcon(QPixmap(":/lpPlot.xpm")), tr("Line + S&ymbol"), this);
10475     connect(actionPlotLP, SIGNAL(triggered()), d_plot_mapper, SLOT(map()));
10476     d_plot_mapper->setMapping(actionPlotLP, Graph::LineSymbols);
10477 
10478     actionPlotVerticalDropLines =
10479             new QAction(QIcon(QPixmap(":/dropLines.xpm")), tr("Vertical &Drop Lines"), this);
10480     connect(actionPlotVerticalDropLines, SIGNAL(triggered()), d_plot_mapper, SLOT(map()));
10481     d_plot_mapper->setMapping(actionPlotVerticalDropLines, Graph::VerticalDropLines);
10482 
10483     actionPlotSpline = new QAction(QIcon(QPixmap(":/spline.xpm")), tr("&Spline"), this);
10484     connect(actionPlotSpline, SIGNAL(triggered()), d_plot_mapper, SLOT(map()));
10485     d_plot_mapper->setMapping(actionPlotSpline, Graph::Spline);
10486 
10487     actionPlotHorSteps = new QAction(QPixmap(":/hor_steps.xpm"), tr("&Horizontal Steps"), this);
10488     connect(actionPlotHorSteps, SIGNAL(triggered()), d_plot_mapper, SLOT(map()));
10489     d_plot_mapper->setMapping(actionPlotHorSteps, Graph::HorizontalSteps);
10490 
10491     actionPlotVertSteps =
10492             new QAction(QIcon(QPixmap(":/vert_steps.xpm")), tr("&Vertical Steps"), this);
10493     connect(actionPlotVertSteps, SIGNAL(triggered()), d_plot_mapper, SLOT(map()));
10494     d_plot_mapper->setMapping(actionPlotVertSteps, Graph::VerticalSteps);
10495 
10496     actionPlotVerticalBars =
10497             new QAction(QIcon(QPixmap(":/vertBars.xpm")), tr("&Vertical Bars"), this);
10498     connect(actionPlotVerticalBars, SIGNAL(triggered()), d_plot_mapper, SLOT(map()));
10499     d_plot_mapper->setMapping(actionPlotVerticalBars, Graph::VerticalBars);
10500 
10501     actionPlotHorizontalBars =
10502             new QAction(QIcon(QPixmap(":/hBars.xpm")), tr("&Horizontal Bars"), this);
10503     connect(actionPlotHorizontalBars, SIGNAL(triggered()), d_plot_mapper, SLOT(map()));
10504     d_plot_mapper->setMapping(actionPlotHorizontalBars, Graph::HorizontalBars);
10505 
10506     actionPlotArea = new QAction(QIcon(QPixmap(":/area.xpm")), tr("&Area"), this);
10507     connect(actionPlotArea, SIGNAL(triggered()), d_plot_mapper, SLOT(map()));
10508     d_plot_mapper->setMapping(actionPlotArea, Graph::Area);
10509 
10510     actionPlotPie = new QAction(QIcon(QPixmap(":/pie.xpm")), tr("&Pie"), this);
10511     connect(actionPlotPie, SIGNAL(triggered()), this, SLOT(plotPie()));
10512 
10513     actionPlotVectXYAM = new QAction(QIcon(QPixmap(":/vectXYAM.xpm")), tr("Vectors XY&AM"), this);
10514     connect(actionPlotVectXYAM, SIGNAL(triggered()), this, SLOT(plotVectXYAM()));
10515 
10516     actionPlotVectXYXY = new QAction(QIcon(QPixmap(":/vectXYXY.xpm")), tr("Vectors &XYXY"), this);
10517     connect(actionPlotVectXYXY, SIGNAL(triggered()), this, SLOT(plotVectXYXY()));
10518 
10519     actionPlotHistogram = new QAction(QIcon(QPixmap(":/histogram.xpm")), tr("&Histogram"), this);
10520     connect(actionPlotHistogram, SIGNAL(triggered()), d_plot_mapper, SLOT(map()));
10521     d_plot_mapper->setMapping(actionPlotHistogram, Graph::Histogram);
10522 
10523     actionPlotStackedHistograms =
10524             new QAction(QIcon(QPixmap(":/stacked_hist.xpm")), tr("&Stacked Histogram"), this);
10525     connect(actionPlotStackedHistograms, SIGNAL(triggered()), this, SLOT(plotStackedHistograms()));
10526 
10527     actionPlot2VerticalLayers =
10528             new QAction(QIcon(QPixmap(":/panel_v2.xpm")), tr("&Vertical 2 Layers"), this);
10529     connect(actionPlot2VerticalLayers, SIGNAL(triggered()), this, SLOT(plot2VerticalLayers()));
10530 
10531     actionPlot2HorizontalLayers =
10532             new QAction(QIcon(QPixmap(":/panel_h2.xpm")), tr("&Horizontal 2 Layers"), this);
10533     connect(actionPlot2HorizontalLayers, SIGNAL(triggered()), this, SLOT(plot2HorizontalLayers()));
10534 
10535     actionPlot4Layers = new QAction(QIcon(QPixmap(":/panel_4.xpm")), tr("&4 Layers"), this);
10536     connect(actionPlot4Layers, SIGNAL(triggered()), this, SLOT(plot4Layers()));
10537 
10538     actionPlotStackedLayers =
10539             new QAction(QIcon(QPixmap(":/stacked.xpm")), tr("&Stacked Layers"), this);
10540     connect(actionPlotStackedLayers, SIGNAL(triggered()), this, SLOT(plotStackedLayers()));
10541 
10542     actionPlot3DRibbon = new QAction(QIcon(QPixmap(":/ribbon.xpm")), tr("&Ribbon"), this);
10543     connect(actionPlot3DRibbon, SIGNAL(triggered()), this, SLOT(plot3DRibbon()));
10544 
10545     actionPlot3DBars = new QAction(QIcon(QPixmap(":/bars.xpm")), tr("&Bars"), this);
10546     connect(actionPlot3DBars, SIGNAL(triggered()), this, SLOT(plot3DBars()));
10547 
10548     actionPlot3DScatter = new QAction(QIcon(QPixmap(":/scatter.xpm")), tr("&Scatter"), this);
10549     connect(actionPlot3DScatter, SIGNAL(triggered()), this, SLOT(plot3DScatter()));
10550 
10551     actionPlot3DTrajectory =
10552             new QAction(QIcon(QPixmap(":/trajectory.xpm")), tr("&Trajectory"), this);
10553     connect(actionPlot3DTrajectory, SIGNAL(triggered()), this, SLOT(plot3DTrajectory()));
10554 
10555     actionShowColStatistics =
10556             new QAction(QIcon(QPixmap(":/col_stat.xpm")), tr("Statistics on &Columns"), this);
10557     connect(actionShowColStatistics, SIGNAL(triggered()), this, SLOT(showColStatistics()));
10558 
10559     actionShowRowStatistics =
10560             new QAction(QIcon(QPixmap(":/stat_rows.xpm")), tr("Statistics on &Rows"), this);
10561     connect(actionShowRowStatistics, SIGNAL(triggered()), this, SLOT(showRowStatistics()));
10562 
10563     actionShowIntDialog = new QAction(tr("&Integrate ..."), this);
10564     connect(actionShowIntDialog, SIGNAL(triggered()), this, SLOT(showIntegrationDialog()));
10565 
10566     actionInterpolate = new QAction(tr("Inte&rpolate ..."), this);
10567     connect(actionInterpolate, SIGNAL(triggered()), this, SLOT(showInterpolationDialog()));
10568 
10569     actionLowPassFilter = new QAction(tr("&Low Pass..."), this);
10570     connect(actionLowPassFilter, SIGNAL(triggered()), this, SLOT(lowPassFilterDialog()));
10571 
10572     actionHighPassFilter = new QAction(tr("&High Pass..."), this);
10573     connect(actionHighPassFilter, SIGNAL(triggered()), this, SLOT(highPassFilterDialog()));
10574 
10575     actionBandPassFilter = new QAction(tr("&Band Pass..."), this);
10576     connect(actionBandPassFilter, SIGNAL(triggered()), this, SLOT(bandPassFilterDialog()));
10577 
10578     actionBandBlockFilter = new QAction(tr("&Band Block..."), this);
10579     connect(actionBandBlockFilter, SIGNAL(triggered()), this, SLOT(bandBlockFilterDialog()));
10580 
10581     actionFFT = new QAction(tr("&FFT..."), this);
10582     connect(actionFFT, SIGNAL(triggered()), this, SLOT(showFFTDialog()));
10583 
10584     actionSmoothSavGol = new QAction(tr("&Savitzky-Golay..."), this);
10585     connect(actionSmoothSavGol, SIGNAL(triggered()), this, SLOT(showSmoothSavGolDialog()));
10586 
10587     actionSmoothFFT = new QAction(tr("&FFT Filter..."), this);
10588     connect(actionSmoothFFT, SIGNAL(triggered()), this, SLOT(showSmoothFFTDialog()));
10589 
10590     actionSmoothAverage = new QAction(tr("Moving Window &Average..."), this);
10591     connect(actionSmoothAverage, SIGNAL(triggered()), this, SLOT(showSmoothAverageDialog()));
10592 
10593     actionDifferentiate = new QAction(tr("&Differentiate"), this);
10594     connect(actionDifferentiate, SIGNAL(triggered()), this, SLOT(differentiate()));
10595 
10596     actionFitLinear = new QAction(tr("Fit &Linear"), this);
10597     connect(actionFitLinear, SIGNAL(triggered()), this, SLOT(fitLinear()));
10598 
10599     actionShowFitPolynomDialog = new QAction(tr("Fit &Polynomial ..."), this);
10600     connect(actionShowFitPolynomDialog, SIGNAL(triggered()), this, SLOT(showFitPolynomDialog()));
10601 
10602     actionShowExpDecayDialog = new QAction(tr("&First Order ..."), this);
10603     connect(actionShowExpDecayDialog, SIGNAL(triggered()), this, SLOT(showExpDecayDialog()));
10604 
10605     actionShowTwoExpDecayDialog = new QAction(tr("&Second Order ..."), this);
10606     connect(actionShowTwoExpDecayDialog, SIGNAL(triggered()), this, SLOT(showTwoExpDecayDialog()));
10607 
10608     actionShowExpDecay3Dialog = new QAction(tr("&Third Order ..."), this);
10609     connect(actionShowExpDecay3Dialog, SIGNAL(triggered()), this, SLOT(showExpDecay3Dialog()));
10610 
10611     actionFitExpGrowth = new QAction(tr("Fit Exponential Gro&wth ..."), this);
10612     connect(actionFitExpGrowth, SIGNAL(triggered()), this, SLOT(showExpGrowthDialog()));
10613 
10614     actionFitSigmoidal = new QAction(tr("Fit &Boltzmann (Sigmoidal)"), this);
10615     connect(actionFitSigmoidal, SIGNAL(triggered()), this, SLOT(fitSigmoidal()));
10616 
10617     actionFitGauss = new QAction(tr("Fit &Gaussian"), this);
10618     connect(actionFitGauss, SIGNAL(triggered()), this, SLOT(fitGauss()));
10619 
10620     actionFitLorentz = new QAction(tr("Fit Lorent&zian"), this);
10621     connect(actionFitLorentz, SIGNAL(triggered()), this, SLOT(fitLorentz()));
10622 
10623     actionShowFitDialog = new QAction(tr("Fit &Wizard..."), this);
10624     actionShowFitDialog->setShortcut(tr("Ctrl+Y"));
10625     connect(actionShowFitDialog, SIGNAL(triggered()), this, SLOT(showFitDialog()));
10626 
10627     actionShowPlotDialog = new QAction(tr("&Plot ..."), this);
10628     connect(actionShowPlotDialog, SIGNAL(triggered()), this, SLOT(showGeneralPlotDialog()));
10629 
10630     actionShowScaleDialog = new QAction(tr("&Scales..."), this);
10631     connect(actionShowScaleDialog, SIGNAL(triggered()), this, SLOT(showScaleDialog()));
10632 
10633     actionShowAxisDialog = new QAction(tr("&Axes..."), this);
10634     connect(actionShowAxisDialog, SIGNAL(triggered()), this, SLOT(showAxisDialog()));
10635 
10636     actionShowGridDialog = new QAction(tr("&Grid ..."), this);
10637     connect(actionShowGridDialog, SIGNAL(triggered()), this, SLOT(showGridDialog()));
10638 
10639     actionShowTitleDialog = new QAction(tr("&Title ..."), this);
10640     connect(actionShowTitleDialog, SIGNAL(triggered()), this, SLOT(showTitleDialog()));
10641 
10642     actionAbout = new QAction(tr("&About SciDAVis"), this);
10643     actionAbout->setShortcut(tr("F1"));
10644     connect(actionAbout, SIGNAL(triggered()), this, SLOT(about()));
10645 
10646     actionShowHelp = new QAction(tr("&Help"), this);
10647     actionShowHelp->setShortcut(tr("Ctrl+H"));
10648     connect(actionShowHelp, SIGNAL(triggered()), this, SLOT(showHelp()));
10649 
10650 #ifdef DYNAMIC_MANUAL_PATH
10651     actionChooseHelpFolder = new QAction(tr("&Choose Help Folder..."), this);
10652     connect(actionChooseHelpFolder, SIGNAL(triggered()), this, SLOT(chooseHelpFolder()));
10653 #endif
10654 
10655     actionRename = new QAction(tr("&Rename Window"), this);
10656     connect(actionRename, SIGNAL(triggered()), this, SLOT(renameActiveWindow()));
10657 
10658     actionCloseWindow = new QAction(QIcon(QPixmap(":/close.xpm")), tr("Close &Window"), this);
10659     actionCloseWindow->setShortcut(tr("Ctrl+W"));
10660     connect(actionCloseWindow, SIGNAL(triggered()), this, SLOT(closeActiveWindow()));
10661 
10662     actionDeleteLayer = new QAction(QIcon(QPixmap(":/erase.xpm")), tr("&Remove Layer"), this);
10663     actionDeleteLayer->setShortcut(tr("Alt+R"));
10664     connect(actionDeleteLayer, SIGNAL(triggered()), this, SLOT(deleteLayer()));
10665 
10666     actionResizeActiveWindow =
10667             new QAction(QIcon(QPixmap(":/resize.xpm")), tr("Window &Geometry..."), this);
10668     connect(actionResizeActiveWindow, SIGNAL(triggered()), this, SLOT(resizeActiveWindow()));
10669 
10670     actionHideActiveWindow = new QAction(tr("&Hide Window"), this);
10671     connect(actionHideActiveWindow, SIGNAL(triggered()), this, SLOT(hideActiveWindow()));
10672 
10673     actionShowMoreWindows = new QAction(tr("More windows..."), this);
10674     connect(actionShowMoreWindows, SIGNAL(triggered()), this, SLOT(showMoreWindows()));
10675 
10676     actionPixelLineProfile =
10677             new QAction(QIcon(QPixmap(":/pixelProfile.xpm")), tr("&View Pixel Line Profile"), this);
10678     connect(actionPixelLineProfile, SIGNAL(triggered()), this, SLOT(pixelLineProfile()));
10679 
10680     actionIntensityTable = new QAction(tr("&Intensity Table"), this);
10681     connect(actionIntensityTable, SIGNAL(triggered()), this, SLOT(intensityTable()));
10682 
10683     actionShowLineDialog = new QAction(tr("&Properties"), this);
10684     connect(actionShowLineDialog, SIGNAL(triggered()), this, SLOT(showLineDialog()));
10685 
10686     actionShowImageDialog = new QAction(tr("&Properties"), this);
10687     connect(actionShowImageDialog, SIGNAL(triggered()), this, SLOT(showImageDialog()));
10688 
10689     actionShowTextDialog = new QAction(tr("&Properties"), this);
10690     connect(actionShowTextDialog, SIGNAL(triggered()), this, SLOT(showTextDialog()));
10691 
10692     actionActivateWindow = new QAction(tr("&Activate Window"), this);
10693     connect(actionActivateWindow, SIGNAL(triggered()), this, SLOT(activateSubWindow()));
10694 
10695     actionMinimizeWindow = new QAction(tr("Mi&nimize Window"), this);
10696     connect(actionMinimizeWindow, SIGNAL(triggered()), this, SLOT(minimizeWindow()));
10697 
10698     actionMaximizeWindow = new QAction(tr("Ma&ximize Window"), this);
10699     connect(actionMaximizeWindow, SIGNAL(triggered()), this, SLOT(maximizeWindow()));
10700 
10701     actionResizeWindow = new QAction(QIcon(QPixmap(":/resize.xpm")), tr("Re&size Window..."), this);
10702     connect(actionResizeWindow, SIGNAL(triggered()), this, SLOT(resizeWindow()));
10703 
10704     actionPrintWindow = new QAction(QIcon(QPixmap(":/fileprint.xpm")), tr("&Print Window"), this);
10705     connect(actionPrintWindow, SIGNAL(triggered()), this, SLOT(printWindow()));
10706 
10707     actionShowPlotGeometryDialog =
10708             new QAction(QIcon(QPixmap(":/resize.xpm")), tr("&Layer Geometry"), this);
10709     connect(actionShowPlotGeometryDialog, SIGNAL(triggered()), this,
10710             SLOT(showPlotGeometryDialog()));
10711 
10712     actionEditSurfacePlot = new QAction(tr("&Surface..."), this);
10713     connect(actionEditSurfacePlot, SIGNAL(triggered()), this, SLOT(editSurfacePlot()));
10714 
10715     actionAdd3DData = new QAction(tr("&Data Set..."), this);
10716     connect(actionAdd3DData, SIGNAL(triggered()), this, SLOT(add3DData()));
10717 
10718     actionInvertMatrix = new QAction(tr("&Invert"), this);
10719     connect(actionInvertMatrix, SIGNAL(triggered()), this, SLOT(invertMatrix()));
10720 
10721     actionMatrixDeterminant = new QAction(tr("&Determinant"), this);
10722     connect(actionMatrixDeterminant, SIGNAL(triggered()), this, SLOT(matrixDeterminant()));
10723 
10724     actionConvertMatrix = new QAction(tr("&Convert to Table"), this);
10725     connect(actionConvertMatrix, SIGNAL(triggered()), this, SLOT(convertMatrixToTable()));
10726 
10727     actionConvertTable = new QAction(tr("Convert to &Matrix"), this);
10728     connect(actionConvertTable, SIGNAL(triggered()), this, SLOT(convertTableToMatrix()));
10729 
10730     actionPlot3DWireFrame =
10731             new QAction(QIcon(QPixmap(":/lineMesh.xpm")), tr("3D &Wire Frame"), this);
10732     connect(actionPlot3DWireFrame, SIGNAL(triggered()), this, SLOT(plot3DWireframe()));
10733 
10734     actionPlot3DHiddenLine =
10735             new QAction(QIcon(QPixmap(":/grid_only.xpm")), tr("3D &Hidden Line"), this);
10736     connect(actionPlot3DHiddenLine, SIGNAL(triggered()), this, SLOT(plot3DHiddenLine()));
10737 
10738     actionPlot3DPolygons = new QAction(QIcon(QPixmap(":/no_grid.xpm")), tr("3D &Polygons"), this);
10739     connect(actionPlot3DPolygons, SIGNAL(triggered()), this, SLOT(plot3DPolygons()));
10740 
10741     actionPlot3DWireSurface =
10742             new QAction(QIcon(QPixmap(":/grid_poly.xpm")), tr("3D Wire &Surface"), this);
10743     connect(actionPlot3DWireSurface, SIGNAL(triggered()), this, SLOT(plot3DWireSurface()));
10744 
10745     actionColorMap =
10746             new QAction(QIcon(QPixmap(":/color_map.xpm")), tr("Contour - &Color Fill"), this);
10747     connect(actionColorMap, SIGNAL(triggered()), this, SLOT(plotColorMap()));
10748 
10749     actionContourMap = new QAction(QIcon(QPixmap(":/contour_map.xpm")), tr("Contour &Lines"), this);
10750     connect(actionContourMap, SIGNAL(triggered()), this, SLOT(plotContour()));
10751 
10752     actionGrayMap = new QAction(QIcon(QPixmap(":/gray_map.xpm")), tr("&Gray Scale Map"), this);
10753     connect(actionGrayMap, SIGNAL(triggered()), this, SLOT(plotGrayScale()));
10754 
10755     actionCorrelate = new QAction(tr("Co&rrelate"), this);
10756     connect(actionCorrelate, SIGNAL(triggered()), this, SLOT(correlate()));
10757 
10758     actionAutoCorrelate = new QAction(tr("&Autocorrelate"), this);
10759     connect(actionAutoCorrelate, SIGNAL(triggered()), this, SLOT(autoCorrelate()));
10760 
10761     actionConvolute = new QAction(tr("&Convolute"), this);
10762     connect(actionConvolute, SIGNAL(triggered()), this, SLOT(convolute()));
10763 
10764     actionDeconvolute = new QAction(tr("&Deconvolute"), this);
10765     connect(actionDeconvolute, SIGNAL(triggered()), this, SLOT(deconvolute()));
10766 
10767     actionTranslateHor = new QAction(tr("&Horizontal"), this);
10768     connect(actionTranslateHor, SIGNAL(triggered()), this, SLOT(translateCurveHor()));
10769 
10770     actionTranslateVert = new QAction(tr("&Vertical"), this);
10771     connect(actionTranslateVert, SIGNAL(triggered()), this, SLOT(translateCurveVert()));
10772 
10773     actionBoxPlot = new QAction(QIcon(QPixmap(":/boxPlot.xpm")), tr("&Box Plot"), this);
10774     connect(actionBoxPlot, SIGNAL(triggered()), d_plot_mapper, SLOT(map()));
10775     d_plot_mapper->setMapping(actionBoxPlot, Graph::Box);
10776 
10777     actionMultiPeakGauss = new QAction(tr("&Gaussian..."), this);
10778     connect(actionMultiPeakGauss, SIGNAL(triggered()), this, SLOT(fitMultiPeakGauss()));
10779 
10780     actionMultiPeakLorentz = new QAction(tr("&Lorentzian..."), this);
10781     connect(actionMultiPeakLorentz, SIGNAL(triggered()), this, SLOT(fitMultiPeakLorentz()));
10782 
10783 #ifdef SEARCH_FOR_UPDATES
10784     actionCheckUpdates = new QAction(tr("Search for &Updates"), this);
10785     connect(actionCheckUpdates, SIGNAL(triggered()), this, SLOT(searchForUpdates()));
10786 #endif // defined SEARCH_FOR_UPDATES
10787 
10788     actionHomePage = new QAction(tr("&SciDAVis Homepage"), this);
10789     connect(actionHomePage, SIGNAL(triggered()), this, SLOT(showHomePage()));
10790 
10791     actionHelpForums = new QAction(tr("SciDAVis &Forums"), this);
10792     connect(actionHelpForums, SIGNAL(triggered()), this, SLOT(showForums()));
10793 
10794     actionHelpBugReports = new QAction(tr("Report a &Bug"), this);
10795     connect(actionHelpBugReports, SIGNAL(triggered()), this, SLOT(showBugTracker()));
10796 
10797 #ifdef DOWNLOAD_LINKS
10798     actionDownloadManual = new QAction(tr("Download &Manual"), this);
10799     connect(actionDownloadManual, SIGNAL(triggered()), this, SLOT(downloadManual()));
10800 #endif
10801 
10802 #ifdef SCRIPTING_DIALOG
10803     actionScriptingLang = new QAction(tr("Scripting &Language"), this);
10804     connect(actionScriptingLang, SIGNAL(triggered()), this, SLOT(showScriptingLangDialog()));
10805 #endif
10806 
10807     actionRestartScripting = new QAction(tr("&Restart Scripting"), this);
10808     connect(actionRestartScripting, SIGNAL(triggered()), this, SLOT(restartScriptingEnv()));
10809 
10810     actionNoteExecute = new QAction(tr("E&xecute"), this);
10811     actionNoteExecute->setShortcut(tr("Ctrl+J"));
10812 
10813     actionNoteExecuteAll = new QAction(tr("Execute &All"), this);
10814     actionNoteExecuteAll->setShortcut(tr("Ctrl+Shift+J"));
10815 
10816     actionNoteEvaluate = new QAction(tr("&Evaluate Expression"), this);
10817     actionNoteEvaluate->setShortcut(tr("Ctrl+Return"));
10818 
10819     actionShowCurvePlotDialog = new QAction(tr("&Plot details..."), this);
10820     connect(actionShowCurvePlotDialog, SIGNAL(triggered()), this, SLOT(showCurvePlotDialog()));
10821 
10822     actionShowCurveWorksheet = new QAction(tr("&Worksheet"), this);
10823     connect(actionShowCurveWorksheet, SIGNAL(triggered()), this, SLOT(showCurveWorksheet()));
10824 
10825     actionCurveFullRange = new QAction(tr("&Reset to Full Range"), this);
10826     connect(actionCurveFullRange, SIGNAL(triggered()), this, SLOT(setCurveFullRange()));
10827 
10828     actionEditCurveRange = new QAction(tr("Edit &Range..."), this);
10829     connect(actionEditCurveRange, SIGNAL(triggered()), this, SLOT(showCurveRangeDialog()));
10830 
10831     actionRemoveCurve = new QAction(QPixmap(":/close.xpm"), tr("&Delete"), this);
10832     connect(actionRemoveCurve, SIGNAL(triggered()), this, SLOT(removeCurve()));
10833 
10834     actionHideCurve = new QAction(tr("&Hide"), this);
10835     connect(actionHideCurve, SIGNAL(triggered()), this, SLOT(hideCurve()));
10836 
10837     actionHideOtherCurves = new QAction(tr("Hide &Other Curves"), this);
10838     connect(actionHideOtherCurves, SIGNAL(triggered()), this, SLOT(hideOtherCurves()));
10839 
10840     actionShowAllCurves = new QAction(tr("&Show All Curves"), this);
10841     connect(actionShowAllCurves, SIGNAL(triggered()), this, SLOT(showAllCurves()));
10842 
10843     actionEditFunction = new QAction(tr("&Edit Function..."), this);
10844     connect(actionEditFunction, SIGNAL(triggered()), this, SLOT(showFunctionDialog()));
10845 
10846     actionCopyStatusBarText = new QAction(tr("&Copy status bar text"), this);
10847     connect(actionCopyStatusBarText, SIGNAL(triggered()), this, SLOT(copyStatusBarText()));
10848 }
10849 
translateActionsStrings()10850 void ApplicationWindow::translateActionsStrings()
10851 {
10852     actionShowCurvePlotDialog->setText(tr("&Plot details..."));
10853     actionShowCurveWorksheet->setText(tr("&Worksheet"));
10854     actionRemoveCurve->setText(tr("&Delete"));
10855     actionEditFunction->setText(tr("&Edit Function..."));
10856     actionCopyStatusBarText->setText(tr("&Copy status bar text"));
10857 
10858     actionCurveFullRange->setText(tr("&Reset to Full Range"));
10859     actionEditCurveRange->setText(tr("Edit &Range..."));
10860     actionHideCurve->setText(tr("&Hide"));
10861     actionHideOtherCurves->setText(tr("Hide &Other Curves"));
10862     actionShowAllCurves->setText(tr("&Show All Curves"));
10863 
10864     actionNewProject->setText(tr("New &Project"));
10865     actionNewProject->setToolTip(tr("Open a new project"));
10866     actionNewProject->setShortcut(tr("Ctrl+N"));
10867 
10868     actionNewGraph->setText(tr("New &Graph"));
10869     actionNewGraph->setToolTip(tr("Create an empty 2D plot"));
10870     actionNewGraph->setShortcut(tr("Ctrl+G"));
10871 
10872     actionNewNote->setText(tr("New &Note / Script"));
10873     actionNewNote->setShortcut(tr("Ctrl+ALT+N"));
10874     actionNewNote->setToolTip(tr("Create an empty note / script window"));
10875 
10876     actionNewTable->setText(tr("New &Table"));
10877     actionNewTable->setShortcut(tr("Ctrl+T"));
10878     actionNewTable->setToolTip(tr("New table"));
10879 
10880     actionNewMatrix->setText(tr("New &Matrix"));
10881     actionNewMatrix->setShortcut(tr("Ctrl+M"));
10882     actionNewMatrix->setToolTip(tr("New matrix"));
10883 
10884     actionNewFunctionPlot->setText(tr("New &Function Plot"));
10885     actionNewFunctionPlot->setToolTip(tr("Create a new 2D function plot"));
10886     actionNewFunctionPlot->setShortcut(tr("Ctrl+F"));
10887 
10888     actionNewSurfacePlot->setText(tr("New 3D &Surface Plot"));
10889     actionNewSurfacePlot->setToolTip(tr("Create a new 3D surface plot"));
10890     actionNewSurfacePlot->setShortcut(tr("Ctrl+ALT+Z"));
10891 
10892     // FIXME: "..." should be added before translating, but this would break translations
10893     actionOpen->setText(tr("&Open") + "...");
10894     actionOpen->setShortcut(tr("Ctrl+O"));
10895     actionOpen->setToolTip(tr("Open project"));
10896 
10897     // FIXME: "..." should be added before translating, but this would break translations
10898     actionLoadImage->setText(tr("Open Image &File") + "...");
10899     actionLoadImage->setShortcut(tr("Ctrl+I"));
10900 
10901     actionImportImage->setText(tr("Import I&mage..."));
10902 
10903     actionSaveProject->setText(tr("&Save Project"));
10904     actionSaveProject->setToolTip(tr("Save project"));
10905     actionSaveProject->setShortcut(tr("Ctrl+S"));
10906 
10907     actionSaveProjectAs->setText(tr("Save Project &As..."));
10908 
10909     actionOpenTemplate->setText(tr("Open Te&mplate..."));
10910     actionOpenTemplate->setToolTip(tr("Open template"));
10911 
10912     actionSaveTemplate->setText(tr("Save As &Template..."));
10913     actionSaveTemplate->setToolTip(tr("Save window as template"));
10914 
10915     actionLoad->setText(tr("&Import ASCII..."));
10916     actionLoad->setToolTip(tr("Import data file(s)"));
10917     actionLoad->setShortcut(tr("Ctrl+K"));
10918 
10919     actionUndo->setText(tr("&Undo"));
10920     actionUndo->setToolTip(tr("Undo changes"));
10921     actionUndo->setShortcut(tr("Ctrl+Z"));
10922 
10923     actionRedo->setText(tr("&Redo"));
10924     actionRedo->setToolTip(tr("Redo changes"));
10925     actionRedo->setShortcut(tr("Ctrl+R"));
10926 
10927     actionCopyWindow->setText(tr("&Duplicate"));
10928     actionCopyWindow->setToolTip(tr("Duplicate window"));
10929 
10930     actionCutSelection->setText(tr("Cu&t Selection"));
10931     actionCutSelection->setToolTip(tr("Cut selection"));
10932     actionCutSelection->setShortcut(tr("Ctrl+X"));
10933 
10934     actionCopySelection->setText(tr("&Copy Selection"));
10935     actionCopySelection->setToolTip(tr("Copy selection"));
10936     actionCopySelection->setShortcut(tr("Ctrl+C"));
10937 
10938     actionPasteSelection->setText(tr("&Paste Selection"));
10939     actionPasteSelection->setToolTip(tr("Paste selection"));
10940     actionPasteSelection->setShortcut(tr("Ctrl+V"));
10941 
10942     actionClearSelection->setText(tr("&Delete Selection"));
10943     actionClearSelection->setToolTip(tr("Delete selection"));
10944     actionClearSelection->setShortcut(tr("Del", "delete key"));
10945 
10946     actionShowExplorer->setText(tr("Project &Explorer"));
10947     actionShowExplorer->setShortcut(tr("Ctrl+E"));
10948     actionShowExplorer->setToolTip(tr("Show project explorer"));
10949 
10950     actionShowLog->setText(tr("Results &Log"));
10951     actionShowLog->setToolTip(tr("Show analysis results"));
10952 
10953 #ifdef SCRIPTING_CONSOLE
10954     actionShowConsole->setText(tr("&Console"));
10955     actionShowConsole->setToolTip(tr("Show Scripting console"));
10956 #endif
10957 
10958     actionAddLayer->setText(tr("Add La&yer"));
10959     actionAddLayer->setToolTip(tr("Add Layer"));
10960     actionAddLayer->setShortcut(tr("ALT+L"));
10961 
10962     // FIXME: "..." should be added before translating, but this would break translations
10963     actionShowLayerDialog->setText(tr("Arran&ge Layers") + "...");
10964     actionShowLayerDialog->setToolTip(tr("Arrange Layers"));
10965     actionShowLayerDialog->setShortcut(tr("ALT+A"));
10966 
10967     actionAutomaticLayout->setText(tr("Automatic Layout"));
10968     actionAutomaticLayout->setToolTip(tr("Automatic Layout"));
10969 
10970     // FIXME: "..." should be added before translating, but this would break translations
10971     actionExportGraph->setText(tr("&Current") + "...");
10972     actionExportGraph->setShortcut(tr("Alt+G"));
10973     actionExportGraph->setToolTip(tr("Export current graph"));
10974 
10975     // FIXME: "..." should be added before translating, but this would break translations
10976     actionExportAllGraphs->setText(tr("&All") + "...");
10977     actionExportAllGraphs->setShortcut(tr("Alt+X"));
10978     actionExportAllGraphs->setToolTip(tr("Export all graphs"));
10979 
10980     // FIXME: "..." should be added before translating, but this would break translations
10981     actionExportPDF->setText(tr("&Export PDF") + "...");
10982     actionExportPDF->setShortcut(tr("Ctrl+Alt+P"));
10983     actionExportPDF->setToolTip(tr("Export to PDF"));
10984 
10985     // FIXME: "..." should be added before translating, but this would break translations
10986     actionPrint->setText(tr("&Print") + "...");
10987     actionPrint->setShortcut(tr("Ctrl+P"));
10988     actionPrint->setToolTip(tr("Print window"));
10989 
10990     // FIXME: "..." should be added before translating, but this would break translations
10991     actionPrintAllPlots->setText(tr("Print All Plo&ts") + "...");
10992     // FIXME: "..." should be added before translating, but this would break translations
10993     actionShowExportASCIIDialog->setText(tr("E&xport ASCII") + "...");
10994 
10995     actionCloseAllWindows->setText(tr("&Quit"));
10996     actionCloseAllWindows->setShortcut(tr("Ctrl+Q"));
10997 
10998     actionClearLogInfo->setText(tr("Clear &Log Information"));
10999     actionDeleteFitTables->setText(tr("Delete &Fit Tables"));
11000 
11001     actionShowPlotWizard->setText(tr("Plot &Wizard"));
11002     actionShowPlotWizard->setShortcut(tr("Ctrl+Alt+W"));
11003     toolbarsMenu->setTitle(tr("Toolbars"));
11004 
11005     actionShowConfigureDialog->setText(tr("&Preferences..."));
11006 
11007     actionShowCurvesDialog->setText(tr("Add/Remove &Curve..."));
11008     actionShowCurvesDialog->setShortcut(tr("ALT+C"));
11009     actionShowCurvesDialog->setToolTip(tr("Add curve to graph"));
11010 
11011     actionAddErrorBars->setText(tr("Add &Error Bars..."));
11012     actionAddErrorBars->setToolTip(tr("Add Error Bars..."));
11013     actionAddErrorBars->setShortcut(tr("Ctrl+B"));
11014 
11015     actionAddFunctionCurve->setText(tr("Add &Function..."));
11016     actionAddFunctionCurve->setToolTip(tr("Add Function..."));
11017     actionAddFunctionCurve->setShortcut(tr("Ctrl+Alt+F"));
11018 
11019     actionUnzoom->setText(tr("&Rescale to Show All"));
11020     actionUnzoom->setShortcut(tr("Ctrl+Shift+R"));
11021     actionUnzoom->setToolTip(tr("Best fit"));
11022 
11023     actionNewLegend->setText(tr("New &Legend"));
11024     actionNewLegend->setShortcut(tr("Ctrl+L"));
11025     actionNewLegend->setToolTip(tr("Add new legend"));
11026 
11027     actionTimeStamp->setText(tr("Add Time Stamp"));
11028     actionTimeStamp->setShortcut(tr("Ctrl+ALT+T"));
11029     actionTimeStamp->setToolTip(tr("Date & time "));
11030 
11031     actionAddImage->setText(tr("Add &Image"));
11032     actionAddImage->setToolTip(tr("Add Image"));
11033     actionAddImage->setShortcut(tr("ALT+I"));
11034 
11035     actionPlotL->setText(tr("&Line"));
11036     actionPlotL->setToolTip(tr("Plot as line"));
11037 
11038     actionPlotP->setText(tr("&Scatter"));
11039     actionPlotP->setToolTip(tr("Plot as symbols"));
11040 
11041     actionPlotLP->setText(tr("Line + S&ymbol"));
11042     actionPlotLP->setToolTip(tr("Plot as line + symbols"));
11043 
11044     actionPlotVerticalDropLines->setText(tr("Vertical &Drop Lines"));
11045 
11046     actionPlotSpline->setText(tr("&Spline"));
11047     actionPlotVertSteps->setText(tr("&Vertical Steps"));
11048     actionPlotHorSteps->setText(tr("&Horizontal Steps"));
11049 
11050     actionPlotVerticalBars->setText(tr("&Vertical Bars"));
11051     actionPlotVerticalBars->setToolTip(tr("Plot with vertical bars"));
11052 
11053     actionPlotHorizontalBars->setText(tr("&Horizontal Bars"));
11054     actionPlotHorizontalBars->setToolTip(tr("Plot with horizontal bars"));
11055 
11056     actionPlotArea->setText(tr("&Area"));
11057     actionPlotArea->setToolTip(tr("Plot area"));
11058 
11059     actionPlotPie->setText(tr("&Pie"));
11060     actionPlotPie->setToolTip(tr("Plot pie"));
11061 
11062     actionPlotVectXYXY->setText(tr("Vectors &XYXY"));
11063     actionPlotVectXYXY->setToolTip(tr("Vectors XYXY"));
11064 
11065     actionPlotVectXYAM->setText(tr("Vectors XY&AM"));
11066     actionPlotVectXYAM->setToolTip(tr("Vectors XYAM"));
11067 
11068     actionPlotHistogram->setText(tr("&Histogram"));
11069     actionPlotStackedHistograms->setText(tr("&Stacked Histogram"));
11070     actionPlot2VerticalLayers->setText(tr("&Vertical 2 Layers"));
11071     actionPlot2HorizontalLayers->setText(tr("&Horizontal 2 Layers"));
11072     actionPlot4Layers->setText(tr("&4 Layers"));
11073     actionPlotStackedLayers->setText(tr("&Stacked Layers"));
11074 
11075     actionPlot3DRibbon->setText(tr("&Ribbon"));
11076     actionPlot3DRibbon->setToolTip(tr("Plot 3D ribbon"));
11077 
11078     actionPlot3DBars->setText(tr("&Bars"));
11079     actionPlot3DBars->setToolTip(tr("Plot 3D bars"));
11080 
11081     actionPlot3DScatter->setText(tr("&Scatter"));
11082     actionPlot3DScatter->setToolTip(tr("Plot 3D scatter"));
11083 
11084     actionPlot3DTrajectory->setText(tr("&Trajectory"));
11085     actionPlot3DTrajectory->setToolTip(tr("Plot 3D trajectory"));
11086 
11087     actionColorMap->setText(tr("Contour + &Color Fill"));
11088     actionColorMap->setToolTip(tr("Contour Lines + Color Fill"));
11089 
11090     actionContourMap->setText(tr("Contour &Lines"));
11091     actionContourMap->setToolTip(tr("Contour Lines"));
11092 
11093     actionGrayMap->setText(tr("&Gray Scale Map"));
11094     actionGrayMap->setToolTip(tr("Gray Scale Map"));
11095 
11096     actionShowColStatistics->setText(tr("Statistics on &Columns"));
11097     actionShowColStatistics->setToolTip(tr("Selected columns statistics"));
11098 
11099     actionShowRowStatistics->setText(tr("Statistics on &Rows"));
11100     actionShowRowStatistics->setToolTip(tr("Selected rows statistics"));
11101     actionShowIntDialog->setText(tr("&Integrate ..."));
11102     actionInterpolate->setText(tr("Inte&rpolate ..."));
11103     actionLowPassFilter->setText(tr("&Low Pass..."));
11104     actionHighPassFilter->setText(tr("&High Pass..."));
11105     actionBandPassFilter->setText(tr("&Band Pass..."));
11106     actionBandBlockFilter->setText(tr("&Band Block..."));
11107     actionFFT->setText(tr("&FFT..."));
11108     actionSmoothSavGol->setText(tr("&Savitzky-Golay..."));
11109     actionSmoothFFT->setText(tr("&FFT Filter..."));
11110     actionSmoothAverage->setText(tr("Moving Window &Average..."));
11111     actionDifferentiate->setText(tr("&Differentiate"));
11112     actionFitLinear->setText(tr("Fit &Linear"));
11113     actionShowFitPolynomDialog->setText(tr("Fit &Polynomial ..."));
11114     actionShowExpDecayDialog->setText(tr("&First Order ..."));
11115     actionShowTwoExpDecayDialog->setText(tr("&Second Order ..."));
11116     actionShowExpDecay3Dialog->setText(tr("&Third Order ..."));
11117     actionFitExpGrowth->setText(tr("Fit Exponential Gro&wth ..."));
11118     actionFitSigmoidal->setText(tr("Fit &Boltzmann (Sigmoidal)"));
11119     actionFitGauss->setText(tr("Fit &Gaussian"));
11120     actionFitLorentz->setText(tr("Fit Lorent&zian"));
11121 
11122     actionShowFitDialog->setText(tr("Fit &Wizard..."));
11123     actionShowFitDialog->setShortcut(tr("Ctrl+Y"));
11124 
11125     actionShowPlotDialog->setText(tr("&Plot ..."));
11126     actionShowScaleDialog->setText(tr("&Scales..."));
11127     actionShowAxisDialog->setText(tr("&Axes..."));
11128     actionShowGridDialog->setText(tr("&Grid ..."));
11129     actionShowTitleDialog->setText(tr("&Title ..."));
11130 
11131     actionAbout->setText(tr("&About SciDAVis"));
11132     actionAbout->setShortcut(tr("F1"));
11133 
11134     actionShowHelp->setText(tr("&Help"));
11135     actionShowHelp->setShortcut(tr("Ctrl+H"));
11136 
11137 #ifdef DYNAMIC_MANUAL_PATH
11138     actionChooseHelpFolder->setText(tr("&Choose Help Folder..."));
11139 #endif
11140 
11141     actionRename->setText(tr("&Rename Window"));
11142 
11143     actionCloseWindow->setText(tr("Close &Window"));
11144     actionCloseWindow->setShortcut(tr("Ctrl+W"));
11145 
11146     actionDeleteLayer->setText(tr("&Remove Layer"));
11147     actionDeleteLayer->setShortcut(tr("Alt+R"));
11148 
11149     actionResizeActiveWindow->setText(tr("Window &Geometry..."));
11150     actionHideActiveWindow->setText(tr("&Hide Window"));
11151     actionShowMoreWindows->setText(tr("More Windows..."));
11152     actionPixelLineProfile->setText(tr("&View Pixel Line Profile"));
11153     actionIntensityTable->setText(tr("&Intensity Table"));
11154     actionShowLineDialog->setText(tr("&Properties"));
11155     actionShowImageDialog->setText(tr("&Properties"));
11156     actionShowTextDialog->setText(tr("&Properties"));
11157     actionActivateWindow->setText(tr("&Activate Window"));
11158     actionMinimizeWindow->setText(tr("Mi&nimize Window"));
11159     actionMaximizeWindow->setText(tr("Ma&ximize Window"));
11160     actionResizeWindow->setText(tr("Re&size Window..."));
11161     actionPrintWindow->setText(tr("&Print Window"));
11162     actionShowPlotGeometryDialog->setText(tr("&Layer Geometry"));
11163     actionEditSurfacePlot->setText(tr("&Surface..."));
11164     actionAdd3DData->setText(tr("&Data Set..."));
11165     actionInvertMatrix->setText(tr("&Invert"));
11166     actionMatrixDeterminant->setText(tr("&Determinant"));
11167     actionConvertMatrix->setText(tr("&Convert to Table"));
11168     actionConvertTable->setText(tr("Convert to &Matrix"));
11169     actionPlot3DWireFrame->setText(tr("3D &Wire Frame"));
11170     actionPlot3DHiddenLine->setText(tr("3D &Hidden Line"));
11171     actionPlot3DPolygons->setText(tr("3D &Polygons"));
11172     actionPlot3DWireSurface->setText(tr("3D Wire &Surface"));
11173     actionCorrelate->setText(tr("Co&rrelate"));
11174     actionAutoCorrelate->setText(tr("&Autocorrelate"));
11175     actionConvolute->setText(tr("&Convolute"));
11176     actionDeconvolute->setText(tr("&Deconvolute"));
11177     actionTranslateHor->setText(tr("&Horizontal"));
11178     actionTranslateVert->setText(tr("&Vertical"));
11179 
11180     actionBoxPlot->setText(tr("&Box Plot"));
11181     actionBoxPlot->setToolTip(tr("Box and whiskers plot"));
11182 
11183     actionMultiPeakGauss->setText(tr("&Gaussian..."));
11184     actionMultiPeakLorentz->setText(tr("&Lorentzian..."));
11185     actionHomePage->setText(tr("&SciDAVis Homepage"));
11186 #ifdef SEARCH_FOR_UPDATES
11187     actionCheckUpdates->setText(tr("Search for &Updates"));
11188 #endif
11189     actionHelpForums->setText(tr("Visit SciDAVis &Forums"));
11190     actionHelpBugReports->setText(tr("Report a &Bug"));
11191 #ifdef DOWNLOAD_LINKS
11192     actionDownloadManual->setText(tr("Download &Manual"));
11193 #endif
11194 
11195 #ifdef SCRIPTING_DIALOG
11196     actionScriptingLang->setText(tr("Scripting &Language"));
11197 #endif
11198     actionRestartScripting->setText(tr("&Restart Scripting"));
11199 
11200     actionNoteExecute->setText(tr("E&xecute"));
11201     actionNoteExecute->setShortcut(tr("Ctrl+J"));
11202 
11203     actionNoteExecuteAll->setText(tr("Execute &All"));
11204     actionNoteExecuteAll->setShortcut(tr("Ctrl+Shift+J"));
11205 
11206     actionNoteEvaluate->setText(tr("&Evaluate Expression"));
11207     actionNoteEvaluate->setShortcut(tr("Ctrl+Return"));
11208 
11209     btnPointer->setText(tr("Disable &tools"));
11210     btnPointer->setToolTip(tr("Pointer"));
11211 
11212     btnZoomIn->setText(tr("&Zoom In"));
11213     btnZoomIn->setShortcut(tr("Ctrl++"));
11214     btnZoomIn->setToolTip(tr("Zoom In"));
11215 
11216     btnZoomOut->setText(tr("Zoom &Out"));
11217     btnZoomOut->setShortcut(tr("Ctrl+-"));
11218     btnZoomOut->setToolTip(tr("Zoom Out"));
11219 
11220     btnCursor->setText(tr("&Data Reader"));
11221     btnCursor->setShortcut(tr("CTRL+D"));
11222     btnCursor->setToolTip(tr("Data reader"));
11223 
11224     btnSelect->setText(tr("&Select Data Range"));
11225     btnSelect->setShortcut(tr("ALT+S"));
11226     btnSelect->setToolTip(tr("Select data range"));
11227 
11228     btnPicker->setText(tr("S&creen Reader"));
11229     btnPicker->setToolTip(tr("Screen reader"));
11230 
11231     btnMovePoints->setText(tr("&Move Data Points..."));
11232     btnMovePoints->setShortcut(tr("Ctrl+ALT+M"));
11233     btnMovePoints->setToolTip(tr("Move data points"));
11234 
11235     btnRemovePoints->setText(tr("Remove &Bad Data Points..."));
11236     btnRemovePoints->setShortcut(tr("Alt+B"));
11237     btnRemovePoints->setToolTip(tr("Remove data points"));
11238 
11239     actionAddText->setText(tr("Add &Text"));
11240     actionAddText->setToolTip(tr("Add Text"));
11241     actionAddText->setShortcut(tr("ALT+T"));
11242 
11243     actionNextWindow->setText(tr("&Next", "next window"));
11244     actionPrevWindow->setText(tr("&Previous", "previous window"));
11245 
11246     btnArrow->setText(tr("Draw &Arrow"));
11247     btnArrow->setShortcut(tr("CTRL+ALT+A"));
11248     btnArrow->setToolTip(tr("Draw arrow"));
11249 
11250     btnLine->setText(tr("Draw &Line"));
11251     btnLine->setShortcut(tr("CTRL+ALT+L"));
11252     btnLine->setToolTip(tr("Draw line"));
11253 
11254     // FIXME: is setText necessary for action groups?
11255     //	coord->setText( tr( "Coordinates" ) );
11256     //	coord->setIconText( tr( "&Coord" ) );
11257     //  coord->setStatusTip( tr( "Coordinates" ) );
11258     Box->setText(tr("Box"));
11259     Box->setIconText(tr("Box"));
11260     Box->setToolTip(tr("Box"));
11261     Box->setStatusTip(tr("Box"));
11262     Frame->setText(tr("Frame"));
11263     Frame->setIconText(tr("&Frame"));
11264     Frame->setToolTip(tr("Frame"));
11265     Frame->setStatusTip(tr("Frame"));
11266     None->setText(tr("No Axes"));
11267     None->setIconText(tr("No Axes"));
11268     None->setToolTip(tr("No axes"));
11269     None->setStatusTip(tr("No axes"));
11270 
11271     front->setToolTip(tr("Front grid"));
11272     back->setToolTip(tr("Back grid"));
11273     right->setToolTip(tr("Right grid"));
11274     left->setToolTip(tr("Left grid"));
11275     ceil->setToolTip(tr("Ceiling grid"));
11276     floor->setToolTip(tr("Floor grid"));
11277 
11278     wireframe->setText(tr("Wireframe"));
11279     wireframe->setIconText(tr("Wireframe"));
11280     wireframe->setToolTip(tr("Wireframe"));
11281     wireframe->setStatusTip(tr("Wireframe"));
11282     hiddenline->setText(tr("Hidden Line"));
11283     hiddenline->setIconText(tr("Hidden Line"));
11284     hiddenline->setToolTip(tr("Hidden line"));
11285     hiddenline->setStatusTip(tr("Hidden line"));
11286     polygon->setText(tr("Polygon Only"));
11287     polygon->setIconText(tr("Polygon Only"));
11288     polygon->setToolTip(tr("Polygon only"));
11289     polygon->setStatusTip(tr("Polygon only"));
11290     filledmesh->setText(tr("Mesh & Filled Polygons"));
11291     filledmesh->setIconText(tr("Mesh & Filled Polygons"));
11292     filledmesh->setToolTip(tr("Mesh & filled Polygons"));
11293     filledmesh->setStatusTip(tr("Mesh & filled Polygons"));
11294     pointstyle->setText(tr("Dots"));
11295     pointstyle->setIconText(tr("Dots"));
11296     pointstyle->setToolTip(tr("Dots"));
11297     pointstyle->setStatusTip(tr("Dots"));
11298     barstyle->setText(tr("Bars"));
11299     barstyle->setIconText(tr("Bars"));
11300     barstyle->setToolTip(tr("Bars"));
11301     barstyle->setStatusTip(tr("Bars"));
11302     conestyle->setText(tr("Cones"));
11303     conestyle->setIconText(tr("Cones"));
11304     conestyle->setToolTip(tr("Cones"));
11305     conestyle->setStatusTip(tr("Cones"));
11306     crossHairStyle->setText(tr("Crosshairs"));
11307     crossHairStyle->setIconText(tr("Crosshairs"));
11308     crossHairStyle->setToolTip(tr("Crosshairs"));
11309     crossHairStyle->setStatusTip(tr("Crosshairs"));
11310 
11311     // floorstyle->setText( tr( "Floor Style" ) );
11312     // floorstyle->setIconText( tr( "Floor Style" ) );
11313     // floorstyle->setStatusTip( tr( "Floor Style" ) );
11314     floordata->setText(tr("Floor Data Projection"));
11315     floordata->setIconText(tr("Floor Data Projection"));
11316     floordata->setToolTip(tr("Floor data projection"));
11317     floordata->setStatusTip(tr("Floor data projection"));
11318     flooriso->setText(tr("Floor Isolines"));
11319     flooriso->setIconText(tr("Floor Isolines"));
11320     flooriso->setToolTip(tr("Floor isolines"));
11321     flooriso->setStatusTip(tr("Floor isolines"));
11322     floornone->setText(tr("Empty Floor"));
11323     floornone->setIconText(tr("Empty Floor"));
11324     floornone->setToolTip(tr("Empty floor"));
11325     floornone->setStatusTip(tr("Empty floor"));
11326 
11327     actionAnimate->setText(tr("Animation"));
11328     actionAnimate->setIconText(tr("Animation"));
11329     actionAnimate->setToolTip(tr("Animation"));
11330     actionAnimate->setStatusTip(tr("Animation"));
11331 
11332     actionPerspective->setText(tr("Enable perspective"));
11333     actionPerspective->setIconText(tr("Enable perspective"));
11334     actionPerspective->setToolTip(tr("Enable perspective"));
11335     actionPerspective->setStatusTip(tr("Enable perspective"));
11336 
11337     actionResetRotation->setText(tr("Reset rotation"));
11338     actionResetRotation->setIconText(tr("Reset rotation"));
11339     actionResetRotation->setToolTip(tr("Reset rotation"));
11340     actionResetRotation->setStatusTip(tr("Reset rotation"));
11341 
11342     actionFitFrame->setText(tr("Fit frame to window"));
11343     actionFitFrame->setIconText(tr("Fit frame to window"));
11344     actionFitFrame->setToolTip(tr("Fit frame to window"));
11345     actionFitFrame->setStatusTip(tr("Fit frame to window"));
11346 }
11347 
openMatrixPlot3D(const QString & caption,const QString & matrix_name,double xl,double xr,double yl,double yr,double zl,double zr)11348 Graph3D *ApplicationWindow::openMatrixPlot3D(const QString &caption, const QString &matrix_name,
11349                                              double xl, double xr, double yl, double yr, double zl,
11350                                              double zr)
11351 {
11352     QString name = matrix_name;
11353     name.remove("matrix<", Qt::CaseSensitive);
11354     name.remove(">");
11355     Matrix *m = matrix(name);
11356     if (!m)
11357         return 0;
11358 
11359     Graph3D *plot = new Graph3D("", &d_workspace, 0, Qt::Widget);
11360     plot->setAttribute(Qt::WA_DeleteOnClose);
11361     plot->setWindowTitle(caption);
11362     plot->setName(caption);
11363     plot->addMatrixData(m, xl, xr, yl, yr, zl, zr);
11364     plot->update();
11365 
11366     initPlot3D(plot);
11367     return plot;
11368 }
11369 
plot3DMatrix(int style)11370 void ApplicationWindow::plot3DMatrix(int style)
11371 {
11372     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Matrix"))
11373         return;
11374 
11375     QApplication::setOverrideCursor(Qt::WaitCursor);
11376     QString label = generateUniqueName(tr("Graph"));
11377 
11378     Graph3D *plot = new Graph3D("", &d_workspace, 0);
11379     plot->setAttribute(Qt::WA_DeleteOnClose);
11380     plot->addMatrixData((Matrix *)d_workspace.activeSubWindow());
11381     plot->customPlotStyle(style);
11382     customPlot3D(plot);
11383     plot->update();
11384 
11385     plot->resize(500, 400);
11386     plot->setWindowTitle(label);
11387     plot->setName(label);
11388     initPlot3D(plot);
11389 
11390     emit modified();
11391     QApplication::restoreOverrideCursor();
11392 }
11393 
plotGrayScale()11394 void ApplicationWindow::plotGrayScale()
11395 {
11396     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Matrix"))
11397         return;
11398 
11399     plotSpectrogram((Matrix *)d_workspace.activeSubWindow(), Graph::GrayMap);
11400 }
11401 
plotGrayScale(Matrix * m)11402 MultiLayer *ApplicationWindow::plotGrayScale(Matrix *m)
11403 {
11404     if (!m)
11405         return 0;
11406 
11407     return plotSpectrogram(m, Graph::GrayMap);
11408 }
11409 
plotContour()11410 void ApplicationWindow::plotContour()
11411 {
11412     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Matrix"))
11413         return;
11414 
11415     plotSpectrogram((Matrix *)d_workspace.activeSubWindow(), Graph::ContourMap);
11416 }
11417 
plotContour(Matrix * m)11418 MultiLayer *ApplicationWindow::plotContour(Matrix *m)
11419 {
11420     if (!m)
11421         return 0;
11422 
11423     return plotSpectrogram(m, Graph::ContourMap);
11424 }
11425 
plotColorMap()11426 void ApplicationWindow::plotColorMap()
11427 {
11428     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Matrix"))
11429         return;
11430 
11431     plotSpectrogram((Matrix *)d_workspace.activeSubWindow(), Graph::ColorMap);
11432 }
11433 
plotColorMap(Matrix * m)11434 MultiLayer *ApplicationWindow::plotColorMap(Matrix *m)
11435 {
11436     if (!m)
11437         return 0;
11438 
11439     return plotSpectrogram(m, Graph::ColorMap);
11440 }
11441 
plotSpectrogram(Matrix * m,Graph::CurveType type)11442 MultiLayer *ApplicationWindow::plotSpectrogram(Matrix *m, Graph::CurveType type)
11443 {
11444     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
11445 
11446     MultiLayer *g = multilayerPlot(generateUniqueName(tr("Graph")));
11447     Graph *plot = g->addLayer();
11448     setPreferences(plot);
11449 
11450     plot->plotSpectrogram(m, type);
11451     g->showNormal();
11452 
11453     emit modified();
11454     QApplication::restoreOverrideCursor();
11455     return g;
11456 }
11457 
importOPJ(const QString & filename)11458 ApplicationWindow *ApplicationWindow::importOPJ(const QString &filename [[maybe_unused]])
11459 {
11460 #ifdef ORIGIN_IMPORT
11461     auto codec = getSettings().value("/General/Dialogs/LastUsedOriginLocale", "").toString();
11462     if (filename.endsWith(".opj", Qt::CaseInsensitive)
11463         || filename.endsWith(".ogg", Qt::CaseInsensitive)
11464         || filename.endsWith(".org", Qt::CaseInsensitive)) {
11465         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
11466 
11467         ApplicationWindow *app = new ApplicationWindow();
11468         app->applyUserSettings();
11469         app->setWindowTitle("SciDAVis - " + filename);
11470         app->showMaximized();
11471         app->projectname = filename;
11472         app->recentProjects.removeAll(filename);
11473         app->recentProjects.push_front(filename);
11474         app->updateRecentProjectsList();
11475 
11476         ImportOPJ(app, filename, codec);
11477 
11478         QApplication::restoreOverrideCursor();
11479         return app;
11480     } else if (filename.endsWith(".ogm", Qt::CaseInsensitive)
11481                || filename.endsWith(".ogw", Qt::CaseInsensitive)) {
11482         ImportOPJ(this, filename, codec);
11483         recentProjects.removeAll(filename);
11484         recentProjects.push_front(filename);
11485         updateRecentProjectsList();
11486         return this;
11487     } else
11488         return 0;
11489 #else
11490     return NULL;
11491 #endif
11492 }
11493 
deleteFitTables()11494 void ApplicationWindow::deleteFitTables()
11495 {
11496     QList<MyWidget *> *mLst = new QList<MyWidget *>();
11497     QList<MyWidget *> windows = windowsList();
11498     for (int i = 0; i < int(windows.count()); i++) {
11499         if (windows.at(i)->inherits("MultiLayer"))
11500             mLst->append(windows.at(i));
11501     }
11502 
11503     foreach (MyWidget *ml, *mLst) {
11504         if (ml->inherits("MultiLayer")) {
11505             QWidgetList lst = ((MultiLayer *)ml)->graphPtrs();
11506             foreach (QWidget *widget, lst) {
11507                 QList<QwtPlotCurve *> curves = ((Graph *)widget)->fitCurvesList();
11508                 foreach (QwtPlotCurve *c, curves) {
11509                     if (((PlotCurve *)c)->type() != Graph::Function) {
11510                         Table *t = ((DataCurve *)c)->table();
11511                         if (!t)
11512                             continue;
11513 
11514                         t->askOnCloseEvent(false);
11515                         t->close();
11516                     }
11517                 }
11518             }
11519         }
11520     }
11521     delete mLst;
11522 }
11523 
windowsList()11524 QList<MyWidget *> ApplicationWindow::windowsList()
11525 {
11526     QList<MyWidget *> lst = QList<MyWidget *>();
11527 
11528     Folder *project_folder = projectFolder();
11529     FolderListItem *item = project_folder->folderListItem();
11530     int initial_depth = item->depth();
11531     QTreeWidgetItemIterator it(item);
11532     while (item && item->depth() >= initial_depth) {
11533         QList<MyWidget *> folderWindows = item->folder()->windowsList();
11534         foreach (MyWidget *w, folderWindows)
11535             lst.append(w);
11536         it++;
11537         item = (FolderListItem *)(*it);
11538     }
11539 
11540     for (MyWidget *w : hiddenWindows)
11541         lst.append(w);
11542     for (MyWidget *w : outWindows)
11543         lst.append(w);
11544 
11545     return lst;
11546 }
11547 
updateRecentProjectsList()11548 void ApplicationWindow::updateRecentProjectsList()
11549 {
11550     if (recentProjects.isEmpty())
11551         return;
11552 
11553     while ((int)recentProjects.size() > MaxRecentProjects)
11554         recentProjects.pop_back();
11555 
11556     foreach (QAction *action, recent->actions())
11557         action->deleteLater();
11558 
11559     for (int i = 0; i < (int)recentProjects.size(); i++)
11560         connect(recent->addAction("&" + QString::number(i + 1) + " " + recentProjects[i]),
11561                 SIGNAL(triggered()), this, SLOT(openRecentProject()));
11562 }
11563 
translateCurveHor()11564 void ApplicationWindow::translateCurveHor()
11565 {
11566     QWidget *w = d_workspace.activeSubWindow();
11567     if (!w || !w->inherits("MultiLayer"))
11568         return;
11569 
11570     MultiLayer *plot = (MultiLayer *)w;
11571     if (plot->isEmpty()) {
11572         QMessageBox::warning(this, tr("Warning"),
11573                              tr("<h4>There are no plot layers available in this window.</h4>"
11574                                 "<p><h4>Please add a layer and try again!</h4>"));
11575         btnPointer->setChecked(true);
11576         return;
11577     }
11578 
11579     Graph *g = (Graph *)plot->activeGraph();
11580     if (!g)
11581         return;
11582 
11583     if (g->isPiePlot()) {
11584         QMessageBox::warning(this, tr("Warning"),
11585                              tr("This functionality is not available for pie plots!"));
11586 
11587         btnPointer->setChecked(true);
11588         return;
11589     } else if (g->validCurvesDataSize()) {
11590         btnPointer->setChecked(true);
11591         g->setActiveTool(new TranslateCurveTool(g, this, TranslateCurveTool::Horizontal,
11592                                                 d_status_info, SLOT(setText(const QString &))));
11593     }
11594 }
11595 
translateCurveVert()11596 void ApplicationWindow::translateCurveVert()
11597 {
11598     QWidget *w = d_workspace.activeSubWindow();
11599     if (!w || !w->inherits("MultiLayer"))
11600         return;
11601 
11602     MultiLayer *plot = (MultiLayer *)w;
11603     if (plot->isEmpty()) {
11604         QMessageBox::warning(this, tr("Warning"),
11605                              tr("<h4>There are no plot layers available in this window.</h4>"
11606                                 "<p><h4>Please add a layer and try again!</h4>"));
11607         btnPointer->setChecked(true);
11608         return;
11609     }
11610 
11611     Graph *g = (Graph *)plot->activeGraph();
11612     if (!g)
11613         return;
11614 
11615     if (g->isPiePlot()) {
11616         QMessageBox::warning(this, tr("Warning"),
11617                              tr("This functionality is not available for pie plots!"));
11618 
11619         btnPointer->setChecked(true);
11620         return;
11621     } else if (g->validCurvesDataSize()) {
11622         btnPointer->setChecked(true);
11623         g->setActiveTool(new TranslateCurveTool(g, this, TranslateCurveTool::Vertical,
11624                                                 d_status_info, SLOT(setText(const QString &))));
11625     }
11626 }
11627 
fitMultiPeakGauss()11628 void ApplicationWindow::fitMultiPeakGauss()
11629 {
11630     fitMultiPeak((int)MultiPeakFit::Gauss);
11631 }
11632 
fitMultiPeakLorentz()11633 void ApplicationWindow::fitMultiPeakLorentz()
11634 {
11635     fitMultiPeak((int)MultiPeakFit::Lorentz);
11636 }
11637 
fitMultiPeak(int profile)11638 void ApplicationWindow::fitMultiPeak(int profile)
11639 {
11640     QWidget *w = d_workspace.activeSubWindow();
11641     if (!w || !w->inherits("MultiLayer"))
11642         return;
11643 
11644     MultiLayer *plot = (MultiLayer *)w;
11645     if (plot->isEmpty()) {
11646         QMessageBox::warning(this, tr("Warning"),
11647                              tr("<h4>There are no plot layers available in this window.</h4>"
11648                                 "<p><h4>Please add a layer and try again!</h4>"));
11649         btnPointer->setChecked(true);
11650         return;
11651     }
11652 
11653     Graph *g = (Graph *)plot->activeGraph();
11654     if (!g || !g->validCurvesDataSize())
11655         return;
11656 
11657     if (g->isPiePlot()) {
11658         QMessageBox::warning(this, tr("Warning"),
11659                              tr("This functionality is not available for pie plots!"));
11660         return;
11661     } else {
11662         bool ok;
11663         int peaks = QInputDialog::getInt(this, tr("Enter the number of peaks"), tr("Peaks"), 2, 2,
11664                                          1000000, 1, &ok);
11665         if (ok && peaks) {
11666             g->setActiveTool(new MultiPeakFitTool(g, this, (MultiPeakFit::PeakProfile)profile,
11667                                                   peaks, d_status_info,
11668                                                   SLOT(setText(const QString &))));
11669         }
11670     }
11671 }
11672 
11673 #ifdef DOWNLOAD_LINKS
downloadManual()11674 void ApplicationWindow::downloadManual()
11675 {
11676     QDesktopServices::openUrl(QUrl(MANUAL_URI));
11677 }
11678 #endif // defined DOWNLOAD_LINKS
11679 
showHomePage()11680 void ApplicationWindow::showHomePage()
11681 {
11682     QDesktopServices::openUrl(QUrl(HOMEPAGE_URI));
11683 }
11684 
showForums()11685 void ApplicationWindow::showForums()
11686 {
11687     QDesktopServices::openUrl(QUrl(FORUM_URI));
11688 }
11689 
showBugTracker()11690 void ApplicationWindow::showBugTracker()
11691 {
11692     QDesktopServices::openUrl(QUrl(BUGREPORT_URI));
11693 }
11694 
parseCommandLineArguments(const QStringList & args)11695 void ApplicationWindow::parseCommandLineArguments(const QStringList &args)
11696 {
11697     int num_args = args.count();
11698     if (num_args == 0)
11699         return;
11700 
11701     QString str;
11702     bool exec = false;
11703     int scriptArg = 0;
11704     //	foreach(str, args){
11705     for (int i = 0; i < num_args; ++i) {
11706         str = args[i];
11707         if ((str == "-a" || str == "--about") || (str == "-m" || str == "--manual")) {
11708             QMessageBox::critical(this, tr("Error"),
11709                                   tr("<b> %1 </b>: This command line option must be used without "
11710                                      "other arguments!")
11711                                           .arg(str));
11712         } else if (str == "-v" || str == "--version") {
11713             QString s = SciDAVis::versionString() + SciDAVis::extraVersion() + "\n";
11714             s += QObject::tr("Released") + ": " + SciDAVis::releaseDateString() + "\n";
11715             s += SciDAVis::copyrightString() + "\n";
11716 
11717 #ifdef Q_OS_WIN
11718             hide();
11719             QMessageBox::information(this, tr("SciDAVis") + " - " + tr("Version"), s);
11720 #else
11721             std::cout << s.toStdString();
11722 #endif
11723             ::exit(0);
11724         } else if (str == "-h" || str == "--help") {
11725             QString s = "\n" + tr("Usage") + ": ";
11726             s += "scidavis [" + tr("options") + "] [" + tr("file") + "_" + tr("name") + "]\n\n";
11727             s += tr("Valid options are") + ":\n";
11728             s += "-a " + tr("or") + " --about: " + tr("show about dialog and exit") + "\n";
11729             s += "-h " + tr("or") + " --help: " + tr("show command line options") + "\n";
11730             s += "-l=XX " + tr("or") + " --lang=XX: " + tr("start SciDAVis in language")
11731                     + " XX ('en', 'fr', 'de', ...)\n";
11732             s += "-m " + tr("or")
11733                     + " --manual: " + tr("show SciDAVis manual in a standalone window") + "\n";
11734             s += "-v " + tr("or") + " --version: " + tr("print SciDAVis version and release date")
11735                     + "\n";
11736             s += "-x " + tr("or") + " --execute: " + tr("execute the script file given as argument")
11737                     + "\n\n";
11738 #ifdef ORIGIN_IMPORT
11739             s += "'" + tr("file") + "_" + tr("name") + "' "
11740                     + tr("can be any .sciprj, .sciprj.gz, .qti, qti.gz, .opj, .ogm, .ogw, .ogg, "
11741                          ".org, .py or ASCII file")
11742                     + "\n";
11743 #else
11744             s += "'" + tr("file") + "_" + tr("name") + "' "
11745                     + tr("can be any .sciprj, .sciprj.gz, .qti, qti.gz, .py or ASCII file") + "\n";
11746 #endif
11747 #ifdef Q_OS_WIN
11748             hide();
11749             QMessageBox::information(this, tr("SciDAVis - Help"), s);
11750 #else
11751             std::cout << s.toStdString();
11752 #endif
11753             ::exit(0);
11754         } else if (str.startsWith("--lang=") || str.startsWith("-l=")) {
11755             QString locale = str.mid(str.indexOf('=') + 1);
11756             if (locales.contains(locale))
11757                 switchToLanguage(locale);
11758 
11759             if (!locales.contains(locale))
11760                 QMessageBox::critical(
11761                         this, tr("Error"),
11762                         tr("<b> %1 </b>: Wrong locale option or no translation available!")
11763                                 .arg(locale));
11764         } else if (str.startsWith("--execute") || str.startsWith("-x"))
11765             exec = true;
11766         else if (str.startsWith("-") || str.startsWith("--")) {
11767             QMessageBox::critical(this, tr("Error"),
11768                                   tr("<b> %1 </b> unknown command line option!").arg(str) + "\n"
11769                                           + tr("Type %1 to see the list of the valid options.")
11770                                                     .arg("'scidavis -h'"));
11771         }
11772         if (str.startsWith("-"))
11773             scriptArg = i; // save last flag
11774     }
11775 
11776     if (scriptArg < num_args - 1)
11777         scriptArg++;
11778     QString file_name = args[scriptArg]; // last argument
11779 
11780     QStringList scriptArgs;
11781     for (auto i = scriptArg + 1; i < num_args; ++i)
11782         scriptArgs << args[i];
11783 
11784     if (file_name.startsWith("-"))
11785         return; // no file name given
11786 
11787     if (!file_name.isEmpty()) {
11788         QFileInfo fi(file_name);
11789         if (fi.isDir()) {
11790             QMessageBox::critical(
11791                     this, tr("File opening error"),
11792                     tr("<b>%1</b> is a directory, please specify a file name!").arg(file_name));
11793             return;
11794         } else if (!fi.isReadable()) {
11795             QMessageBox::critical(this, tr("File opening error"),
11796                                   tr("You don't have the permission to open this file: <b>%1</b>")
11797                                           .arg(file_name));
11798             return;
11799         } else if (!fi.exists()) {
11800             QMessageBox::critical(this, tr("File opening error"),
11801                                   tr("The file: <b>%1</b> doesn't exist!").arg(file_name));
11802             return;
11803         }
11804 
11805         workingDir = fi.absolutePath();
11806         saveSettings(); // the recent projects must be saved
11807 
11808         ApplicationWindow *a;
11809         if (exec)
11810             a = loadScript(file_name, scriptArgs, exec);
11811         else
11812             a = open(file_name, scriptArgs);
11813 
11814         if (a) {
11815             a->workingDir = workingDir;
11816             close();
11817         }
11818     }
11819 }
11820 
createLanguagesList()11821 void ApplicationWindow::createLanguagesList()
11822 {
11823     appTranslator = new QTranslator(this);
11824     qtTranslator = new QTranslator(this);
11825     qApp->installTranslator(appTranslator);
11826     qApp->installTranslator(qtTranslator);
11827 
11828     qmPath = TS_PATH;
11829 
11830     QString lng; // lang, as en_GB
11831     QString slng; // short lang, as en
11832     lng = QLocale().name();
11833     {
11834         if (lng == "C")
11835             lng = "en";
11836         int i = lng.indexOf(QString("."));
11837         if (i >= 0)
11838             lng = lng.left(i);
11839         i = lng.indexOf(QString("_"));
11840         if (i >= 0)
11841             slng = lng.left(i);
11842         else
11843             slng = lng;
11844     }
11845     if (slng.size() > 2)
11846         slng = slng.left(2);
11847 
11848     QDir dir(qmPath);
11849     QStringList fileNames = dir.entryList(QStringList("scidavis_*.qm"));
11850     if (fileNames.size() == 0) {
11851         // fall back to looking in the executable's directory
11852         qmPath = QFileInfo(QCoreApplication::applicationFilePath()).path() + "/translations";
11853         dir.setPath(qmPath);
11854         fileNames = dir.entryList(QStringList("scidavis_*.qm"));
11855     }
11856     for (int i = 0; i < (int)fileNames.size(); i++) {
11857         QString locale = fileNames[i];
11858         locale = locale.mid(locale.indexOf('_') + 1);
11859         locale.truncate(locale.indexOf('.'));
11860         locales.push_back(locale);
11861     }
11862     locales.push_back("en");
11863     locales.sort();
11864 
11865     if (appLanguage != "en") {
11866         if (!appTranslator->load("scidavis_" + appLanguage, qmPath))
11867             if (!appTranslator->load("scidavis_" + appLanguage))
11868                 if (!appTranslator->load("scidavis_" + lng, qmPath))
11869                     if (!appTranslator->load("scidavis_" + lng))
11870                         if (!appTranslator->load("scidavis_" + slng, qmPath))
11871                             appTranslator->load("scidavis_" + slng);
11872         if (!qtTranslator->load("qt_" + appLanguage, qmPath + "/qt"))
11873             if (!qtTranslator->load("qt_" + appLanguage))
11874                 if (!qtTranslator->load("qt_" + lng, qmPath + "/qt"))
11875                     if (!qtTranslator->load("qt_" + lng))
11876                         if (!qtTranslator->load("qt_" + slng, qmPath + "/qt"))
11877                             qtTranslator->load("qt_" + slng);
11878     }
11879 }
11880 
switchToLanguage(int param)11881 void ApplicationWindow::switchToLanguage(int param)
11882 {
11883     if (param < (int)locales.size())
11884         switchToLanguage(locales[param]);
11885 }
11886 
switchToLanguage(const QString & locale)11887 void ApplicationWindow::switchToLanguage(const QString &locale)
11888 {
11889     if (!locales.contains(locale) || appLanguage == locale)
11890         return;
11891 
11892     appLanguage = locale;
11893     if (locale == "en") {
11894         qApp->removeTranslator(appTranslator);
11895         qApp->removeTranslator(qtTranslator);
11896         delete appTranslator;
11897         delete qtTranslator;
11898         appTranslator = new QTranslator(this);
11899         qtTranslator = new QTranslator(this);
11900         qApp->installTranslator(appTranslator);
11901         qApp->installTranslator(qtTranslator);
11902     } else {
11903         if (!appTranslator->load("scidavis_" + appLanguage, qmPath))
11904             appTranslator->load("scidavis_" + appLanguage);
11905         if (!qtTranslator->load("qt_" + appLanguage, qmPath + "/qt"))
11906             qtTranslator->load("qt_" + appLanguage);
11907     }
11908     insertTranslatedStrings();
11909 }
11910 
matrixNames()11911 QStringList ApplicationWindow::matrixNames()
11912 {
11913     QStringList names;
11914     QList<MyWidget *> windows = windowsList();
11915     foreach (MyWidget *w, windows) {
11916         if (w->inherits("Matrix"))
11917             names << static_cast<Matrix *>(w)->name();
11918     }
11919     return names;
11920 }
11921 
alreadyUsedName(const QString & label)11922 bool ApplicationWindow::alreadyUsedName(const QString &label)
11923 {
11924     QList<MyWidget *> windows = windowsList();
11925     bool used = false;
11926     foreach (MyWidget *widget, windows) {
11927         if (widget && widget->name() == label) {
11928             used = true;
11929             break;
11930         }
11931     }
11932     return used;
11933 }
11934 
projectHasMatrices()11935 bool ApplicationWindow::projectHasMatrices()
11936 {
11937     QList<MyWidget *> windows = windowsList();
11938     bool has = false;
11939     foreach (MyWidget *w, windows) {
11940         if (w->inherits("Matrix")) {
11941             has = true;
11942             break;
11943         }
11944     }
11945     return has;
11946 }
11947 
projectHas2DPlots()11948 bool ApplicationWindow::projectHas2DPlots()
11949 {
11950     QList<MyWidget *> windows = windowsList();
11951     bool hasPlots = false;
11952     foreach (MyWidget *w, windows) {
11953         if (w->inherits("MultiLayer")) {
11954             hasPlots = true;
11955             break;
11956         }
11957     }
11958     return hasPlots;
11959 }
11960 
projectHas3DPlots()11961 bool ApplicationWindow::projectHas3DPlots()
11962 {
11963     QList<MyWidget *> windows = windowsList();
11964     bool has3DPlots = false;
11965     foreach (MyWidget *w, windows) {
11966         if (w->inherits("Graph3D")) {
11967             has3DPlots = true;
11968             break;
11969         }
11970     }
11971     return has3DPlots;
11972 }
11973 
appendProject()11974 void ApplicationWindow::appendProject()
11975 {
11976     OpenProjectDialog *open_dialog = new OpenProjectDialog(this, false);
11977     open_dialog->setDirectory(workingDir);
11978     open_dialog->setExtensionWidget(0);
11979     if (open_dialog->exec() != QDialog::Accepted || open_dialog->selectedFiles().isEmpty())
11980         return;
11981     workingDir = open_dialog->directory().path();
11982     appendProject(open_dialog->selectedFiles()[0]);
11983 }
11984 
appendProject(const QString & fn)11985 void ApplicationWindow::appendProject(const QString &fn)
11986 {
11987     if (fn.isEmpty())
11988         return;
11989 
11990     QFile *file;
11991 
11992     QFileInfo fi(fn);
11993     workingDir = fi.absolutePath();
11994 
11995     if (fn.contains(".sciprj") || fn.contains(".qti") || fn.contains(".opj", Qt::CaseInsensitive)
11996         || fn.contains(".ogm", Qt::CaseInsensitive) || fn.contains(".ogw", Qt::CaseInsensitive)
11997         || fn.contains(".ogg", Qt::CaseInsensitive) || fn.contains(".org", Qt::CaseInsensitive)) {
11998         QFileInfo f(fn);
11999         if (!f.exists()) {
12000             QMessageBox::critical(this, tr("File opening error"),
12001                                   tr("The file: <b>%1</b> doesn't exist!").arg(fn));
12002             return;
12003         }
12004     } else {
12005         QMessageBox::critical(
12006                 this, tr("File opening error"),
12007                 tr("The file: <b>%1</b> is not a SciDAVis or Origin project file!").arg(fn));
12008         return;
12009     }
12010 
12011     if (fn.endsWith(".gz", Qt::CaseInsensitive) || fn.endsWith(".gz~", Qt::CaseInsensitive)) {
12012         file = openCompressedFile(fn);
12013         if (!file)
12014             return;
12015     } else {
12016         file = new QFile(fn);
12017         file->open(QIODevice::ReadOnly);
12018     }
12019 
12020     recentProjects.removeAll(fn);
12021     recentProjects.push_front(fn);
12022     updateRecentProjectsList();
12023 
12024     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
12025 
12026     Folder *cf = current_folder;
12027     FolderListItem *item = (FolderListItem *)current_folder->folderListItem();
12028     folders.blockSignals(true);
12029     blockSignals(true);
12030 
12031     QString baseName = fi.baseName();
12032     QStringList lst = current_folder->subfolders();
12033     int n = lst.count(baseName);
12034     if (n) { // avoid identical subfolder names
12035         while (lst.count(baseName + QString::number(n)))
12036             n++;
12037         baseName += QString::number(n);
12038     }
12039 
12040     current_folder = &current_folder->addChild<Folder>(baseName);
12041     FolderListItem *fli = new FolderListItem(item, current_folder);
12042     current_folder->setFolderListItem(fli);
12043 
12044     if (fn.contains(".opj", Qt::CaseInsensitive) || fn.contains(".ogm", Qt::CaseInsensitive)
12045         || fn.contains(".ogw", Qt::CaseInsensitive) || fn.contains(".ogg", Qt::CaseInsensitive)
12046         || fn.contains(".org", Qt::CaseInsensitive))
12047 #ifdef ORIGIN_IMPORT
12048     {
12049         auto codec = getSettings().value("/General/Dialogs/LastUsedOriginLocale", "").toString();
12050         ImportOPJ(this, fn, codec);
12051     }
12052 #else
12053     {
12054         QMessageBox::critical(
12055                 this, tr("File opening error"),
12056                 tr("SciDAVis currently does not support Origin import. If you are interested in "
12057                    "reviving and maintaining an Origin import filter, contact the developers.")
12058                         .arg(fn));
12059         return;
12060     }
12061 #endif
12062     else {
12063         QTextStream t(file);
12064         t.setCodec(QTextCodec::codecForName("UTF-8"));
12065 
12066         QString s = t.readLine();
12067 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
12068         lst = s.split(QRegExp("\\s"), Qt::SkipEmptyParts);
12069         QString version = lst[1];
12070         lst = version.split(".", Qt::SkipEmptyParts);
12071 #else
12072         lst = s.split(QRegExp("\\s"), QString::SkipEmptyParts);
12073         QString version = lst[1];
12074         lst = version.split(".", QString::SkipEmptyParts);
12075 #endif
12076         if (fn.endsWith(".qti", Qt::CaseInsensitive) || fn.endsWith(".qti.gz", Qt::CaseInsensitive))
12077             d_file_version = 100 * (lst[0]).toInt() + 10 * (lst[1]).toInt() + (lst[2]).toInt();
12078         else
12079             d_file_version = ((lst[0]).toInt() << 16) + ((lst[1]).toInt() << 8) + (lst[2]).toInt();
12080 
12081         t.readLine();
12082         if (d_file_version < 73)
12083             t.readLine();
12084 
12085         // process tables and matrix information
12086         while (!t.atEnd()) {
12087             s = t.readLine(4096); // workaround for safely reading very big lines
12088             lst.clear();
12089             if (s.left(8) == "<folder>") {
12090                 lst = s.split("\t");
12091                 Folder &f = current_folder->addChild<Folder>(lst[1]);
12092                 f.setBirthDate(lst[2]);
12093                 f.setModificationDate(lst[3]);
12094                 if (lst.count() > 4)
12095                     if (lst[4] == "current")
12096                         cf = &f;
12097 
12098                 FolderListItem *fli = new FolderListItem(current_folder->folderListItem(), &f);
12099                 fli->setText(0, lst[1]);
12100                 f.setFolderListItem(fli);
12101 
12102                 current_folder = &f;
12103             } else if (s == "<table>") {
12104                 openTable(this, t);
12105             } else if (s == "<matrix>") {
12106                 while (s != "</matrix>") {
12107                     s = t.readLine();
12108                     lst << s;
12109                 }
12110                 lst.pop_back();
12111                 openMatrix(this, lst);
12112             } else if (s == "<note>") {
12113                 for (int i = 0; i < 3; i++) {
12114                     s = t.readLine();
12115                     lst << s;
12116                 }
12117                 Note *m = openNote(this, lst);
12118                 QStringList cont;
12119                 while (s != "</note>") {
12120                     s = t.readLine();
12121                     cont << s;
12122                 }
12123                 cont.pop_back();
12124                 m->restore(cont);
12125             } else if (s == "</folder>") {
12126                 Folder *parent = (Folder *)current_folder->parent();
12127                 if (!parent)
12128                     current_folder = projectFolder();
12129                 else
12130                     current_folder = parent;
12131             }
12132         }
12133 
12134         // process the rest
12135         t.seek(0);
12136 
12137         MultiLayer *plot = 0;
12138         while (!t.atEnd()) {
12139             s = t.readLine(4096); // workaround for safely reading very big lines
12140             if (s.left(8) == "<folder>") {
12141                 lst = s.split("\t");
12142                 current_folder = current_folder->findSubfolder(lst[1]);
12143             } else if (s == "<multiLayer>") { // process multilayers information
12144                 s = t.readLine();
12145                 QStringList graph = s.split("\t");
12146                 QString caption = graph[0];
12147                 plot = multilayerPlot(caption);
12148                 plot->setCols(graph[1].toInt());
12149                 plot->setRows(graph[2].toInt());
12150                 setListViewDate(caption, graph[3]);
12151                 plot->setBirthDate(graph[3]);
12152                 plot->blockSignals(true);
12153 
12154                 restoreWindowGeometry(this, plot, t.readLine());
12155 
12156                 if (d_file_version > 71) {
12157                     QStringList lst = t.readLine().split("\t");
12158                     plot->setWindowLabel(lst[1]);
12159                     setListViewLabel(plot->name(), lst[1]);
12160                     plot->setCaptionPolicy((MyWidget::CaptionPolicy)lst[2].toInt());
12161                 }
12162 
12163                 if (d_file_version > 83) {
12164 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
12165                     QStringList lst = t.readLine().split("\t", Qt::SkipEmptyParts);
12166                     plot->setMargins(lst[1].toInt(), lst[2].toInt(), lst[3].toInt(),
12167                                      lst[4].toInt());
12168                     lst = t.readLine().split("\t", Qt::SkipEmptyParts);
12169                     plot->setSpacing(lst[1].toInt(), lst[2].toInt());
12170                     lst = t.readLine().split("\t", Qt::SkipEmptyParts);
12171                     plot->setLayerCanvasSize(lst[1].toInt(), lst[2].toInt());
12172                     lst = t.readLine().split("\t", Qt::SkipEmptyParts);
12173                     plot->setAlignement(lst[1].toInt(), lst[2].toInt());
12174 #else
12175                     QStringList lst = t.readLine().split("\t", QString::SkipEmptyParts);
12176                     plot->setMargins(lst[1].toInt(), lst[2].toInt(), lst[3].toInt(),
12177                                      lst[4].toInt());
12178                     lst = t.readLine().split("\t", QString::SkipEmptyParts);
12179                     plot->setSpacing(lst[1].toInt(), lst[2].toInt());
12180                     lst = t.readLine().split("\t", QString::SkipEmptyParts);
12181                     plot->setLayerCanvasSize(lst[1].toInt(), lst[2].toInt());
12182                     lst = t.readLine().split("\t", QString::SkipEmptyParts);
12183                     plot->setAlignement(lst[1].toInt(), lst[2].toInt());
12184 #endif
12185                 }
12186 
12187                 while (s != "</multiLayer>") { // open layers
12188                     s = t.readLine();
12189                     if (s.left(7) == "<graph>") {
12190                         lst.clear();
12191                         while (s != "</graph>") {
12192                             s = t.readLine();
12193                             lst << s;
12194                         }
12195                         openGraph(this, plot, lst);
12196                     }
12197                 }
12198                 plot->blockSignals(false);
12199             } else if (s == "<SurfacePlot>") { // process 3D plots information
12200                 lst.clear();
12201                 while (s != "</SurfacePlot>") {
12202                     s = t.readLine();
12203                     lst << s;
12204                 }
12205                 openSurfacePlot(this, lst);
12206             } else if (s == "</folder>") {
12207                 Folder *parent = (Folder *)current_folder->parent();
12208                 if (!parent)
12209                     current_folder = projectFolder();
12210                 else
12211                     current_folder = parent;
12212             }
12213         }
12214         file->close();
12215         delete file;
12216     }
12217 
12218     folders.blockSignals(false);
12219     // change folder to user defined current folder
12220     changeFolder(cf);
12221     blockSignals(false);
12222     renamedTables = QStringList();
12223     QApplication::restoreOverrideCursor();
12224 }
12225 
rawSaveFolder(Folder * folder,QIODevice * device)12226 void ApplicationWindow::rawSaveFolder(Folder *folder, QIODevice *device)
12227 {
12228     QTextStream stream(device);
12229     stream.setCodec(QTextCodec::codecForName("UTF-8"));
12230     foreach (MyWidget *w, folder->windowsList()) {
12231         Table *t = qobject_cast<Table *>(w);
12232         if (t)
12233             t->saveToDevice(device, windowGeometryInfo(w));
12234         else
12235             stream << w->saveToString(windowGeometryInfo(w));
12236     }
12237     foreach (Folder *subfolder, folder->folders()) {
12238         stream << "<folder>\t" + QString(subfolder->name()) + "\t" + subfolder->birthDate() + "\t"
12239                         + subfolder->modificationDate();
12240         if (subfolder == current_folder)
12241             stream << "\tcurrent\n";
12242         else
12243             stream << "\n"; // FIXME: Having no 5th string here is not a good idea
12244         stream.flush();
12245         rawSaveFolder(subfolder, device);
12246         stream << "</folder>\n";
12247     }
12248 }
12249 
saveFolder(Folder * folder,const QString & fn)12250 void ApplicationWindow::saveFolder(Folder *folder, const QString &fn)
12251 {
12252     // file saving procedure follows
12253     // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/317781/comments/54
12254     QFile f(fn + ".new");
12255     while (!f.open(QIODevice::WriteOnly)) {
12256         if (f.isOpen())
12257             f.close();
12258         // The following message is slightly misleading, since it may be that fn.new can't be opened
12259         // _at_all_. However, changing this would break translations, in a bugfix release.
12260         // TODO: rephrase message for next minor release
12261         switch (QMessageBox::critical(
12262                 this, tr("File save error"),
12263                 tr("The file: <br><b>%1</b> is opened in read-only mode").arg(fn + ".new"),
12264                 QMessageBox::Retry | QMessageBox::Default,
12265                 QMessageBox::Abort | QMessageBox::Escape)) {
12266         case QMessageBox::Abort:
12267             return;
12268         }
12269     }
12270 
12271     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
12272 
12273     QTextStream t(&f);
12274     t.setCodec(QTextCodec::codecForName("UTF-8"));
12275     t << SciDAVis::schemaVersion() + " project file\n";
12276     t << "<scripting-lang>\t" + QString(scriptEnv->objectName()) + "\n";
12277     t << "<windows>\t" + QString::number(folder->windowCount(true)) + "\n";
12278     t.flush();
12279     rawSaveFolder(folder, &f);
12280     t << "<log>\n" + logInfo + "</log>";
12281 
12282     // second part of secure file saving (see comment at the start of this method)
12283 #ifdef Q_OS_WIN
12284     // this one was taken from
12285     // http://support.microsoft.com/kb/148505/en-us
12286     // http://msdn.microsoft.com/en-us/library/17618685(VS.80).aspx
12287     if (!f.flush() || _commit(f.handle()) != 0) {
12288 #else
12289     if (!f.flush() || fsync(f.handle()) != 0) {
12290 #endif
12291         QApplication::restoreOverrideCursor();
12292         QMessageBox::critical(
12293                 this, tr("Error writing data to disk"),
12294                 tr("<html>%1<br><br>Your data may or may not have ended up in <em>%2</em> (%3). \
12295 					If there already was a version of this project on disk, it has not been touched.</html>")
12296                         .arg(QString::fromLocal8Bit(strerror(errno)))
12297                         .arg(fn + ".new")
12298                         .arg(f.handle()));
12299         f.close();
12300         return;
12301     }
12302     f.close();
12303 #ifdef Q_OS_WIN
12304     // unfortunately, Windows doesn't support atomic renames; so Windows users will have to live
12305     // with the risk of losing the file in case of a crash between remove and rename
12306     if ((QFile::exists(fn)
12307          && ((QFile::exists(fn + "~") && !QFile::remove(fn + "~")) || !QFile::rename(fn, fn + "~")))
12308         || !QFile::rename(fn + ".new", fn)) {
12309 #else
12310     // we want to atomically replace existing files, so we can't use QFile::rename()
12311     if ((QFile::exists(fn) && rename(QFile::encodeName(fn), QFile::encodeName(fn + "~")) != 0)
12312         || rename(QFile::encodeName(fn + ".new"), QFile::encodeName(fn)) != 0) {
12313 #endif
12314         QApplication::restoreOverrideCursor();
12315         QMessageBox::critical(
12316                 this, tr("Error renaming backup files"),
12317                 tr("<html>%1<br><br>Data was written to <em>%2</em>, but saving the original file as <em>%3</em>\
12318 					and moving the new file to <em>%4</em> failed. In case you wonder why the original file hasn't\
12319 					been simply replaced, see here:\
12320 					<a href=\"http://bugs.launchpad.net/ubuntu/+source/linux/+bug/317781/comments/54\">\
12321 					http://bugs.launchpad.net/ubuntu/+source/linux/+bug/317781/comments/54</a>.</html>")
12322                         .arg(QString::fromLocal8Bit(strerror(errno)))
12323                         .arg(fn + ".new")
12324                         .arg(fn + "~")
12325                         .arg(fn));
12326         return;
12327     }
12328 
12329     QApplication::restoreOverrideCursor();
12330 }
12331 
12332 void ApplicationWindow::saveAsProject()
12333 {
12334     saveFolderAsProject(current_folder);
12335 }
12336 
12337 void ApplicationWindow::saveFolderAsProject(Folder *f)
12338 {
12339     QString filter = tr("SciDAVis project") + " (*.sciprj);;";
12340     filter += tr("Compressed SciDAVis project") + " (*.sciprj.gz)";
12341 
12342     QString selectedFilter;
12343     QString fn = QFileDialog::getSaveFileName(this, tr("Save project as"), workingDir, filter,
12344                                               &selectedFilter);
12345     if (!fn.isEmpty()) {
12346         QFileInfo fi(fn);
12347         workingDir = fi.absolutePath();
12348         QString baseName = fi.fileName();
12349         if (!baseName.endsWith(".sciprj") && !baseName.endsWith(".sciprj.gz")) {
12350             fn.append(".sciprj");
12351         }
12352         bool compress = false;
12353         if (fn.endsWith(".gz")) {
12354             fn = fn.left(fn.length() - 3);
12355             compress = true;
12356         }
12357 
12358         saveFolder(f, fn);
12359         if (selectedFilter.contains(".gz") || compress)
12360             file_compress(QFile::encodeName(fn).constData(), "wb9");
12361     }
12362 }
12363 
12364 void ApplicationWindow::showFolderPopupMenu(const QPoint &p, bool fromFolders)
12365 {
12366     QMenu *cm = nullptr;
12367     if (fromFolders) {
12368         cm = showFolderPopupMenuImpl(folders.itemAt(p), fromFolders);
12369         if (cm)
12370             cm->exec(folders.mapToGlobal(p));
12371     } else {
12372         cm = showFolderPopupMenuImpl(lv.itemAt(p), fromFolders);
12373         if (cm)
12374             cm->exec(lv.mapToGlobal(p));
12375     }
12376 }
12377 
12378 QMenu *ApplicationWindow::showFolderPopupMenuImpl(QTreeWidgetItem *it, bool fromFolders)
12379 {
12380     if (!it || folders.isRenaming())
12381         return nullptr;
12382 
12383     QMenu *cm = new QMenu(this);
12384     cm->addAction(tr("&Find..."), this, SLOT(showFindDialogue()));
12385     cm->addSeparator();
12386     cm->addAction(tr("App&end Project..."), this, SLOT(appendProject()));
12387     if (((FolderListItem *)it)->folder()->parent())
12388         cm->addAction(tr("Save &As Project..."), this, SLOT(saveAsProject()));
12389     else
12390         cm->addAction(tr("Save Project &As..."), this, SLOT(saveProjectAs()));
12391     cm->addSeparator();
12392 
12393     if (fromFolders && show_windows_policy != HideAll) {
12394         cm->addAction(tr("&Show All Windows"), this, SLOT(showAllFolderWindows()));
12395         cm->addAction(tr("&Hide All Windows"), this, SLOT(hideAllFolderWindows()));
12396         cm->addSeparator();
12397     }
12398 
12399     if (((FolderListItem *)it)->folder()->parent()) {
12400         cm->addAction(QPixmap(":/close.xpm"), tr("&Delete Folder"), this, SLOT(deleteFolder()),
12401                       Qt::Key_F8);
12402         cm->addAction(tr("&Rename"), this, SLOT(startRenameFolder()), Qt::Key_F2);
12403         cm->addSeparator();
12404     }
12405 
12406     if (fromFolders) {
12407         QMenu *window = cm->addMenu(tr("New &Window"));
12408         window->addAction(actionNewTable);
12409         window->addAction(actionNewMatrix);
12410         window->addAction(actionNewNote);
12411         window->addAction(actionNewGraph);
12412         window->addAction(actionNewFunctionPlot);
12413         window->addAction(actionNewSurfacePlot);
12414     }
12415 
12416     cm->addAction(QPixmap(":/newfolder.xpm"), tr("New F&older"), this, SLOT(addFolder()),
12417                   Qt::Key_F7);
12418     cm->addSeparator();
12419 
12420     QMenu *viewWindowsMenu = cm->addMenu(tr("&View Windows"));
12421     QStringList lst;
12422     lst << tr("&None") << tr("&Windows in Active Folder")
12423         << tr("Windows in &Active Folder && Subfolders");
12424     for (int i = 0; i < 3; ++i) {
12425         QAction *actId = viewWindowsMenu->addAction(lst[i], this, SLOT(setShowWindowsPolicy(bool)));
12426         actId->setData(i);
12427         actId->setCheckable(true);
12428         actId->setChecked(show_windows_policy == i);
12429     }
12430     cm->addSeparator();
12431     cm->addAction(tr("&Properties..."), this, SLOT(folderProperties()));
12432     return cm;
12433 }
12434 
12435 void ApplicationWindow::setShowWindowsPolicy(bool checked)
12436 {
12437     Q_UNUSED(checked)
12438 
12439     QAction *act = qobject_cast<QAction *>(sender());
12440     if (!act)
12441         return;
12442     int p = act->data().toInt();
12443 
12444     if (show_windows_policy == (ShowWindowsPolicy)p)
12445         return;
12446 
12447     show_windows_policy = (ShowWindowsPolicy)p;
12448     if (show_windows_policy == HideAll) {
12449         QList<MyWidget *> lst = windowsList();
12450         foreach (MyWidget *widget, lst) {
12451             if (!widget)
12452                 continue;
12453             hiddenWindows.append(widget);
12454             widget->hide();
12455             setListView(widget->name(), tr("Hidden"));
12456         }
12457     } else
12458         showAllFolderWindows();
12459 }
12460 
12461 void ApplicationWindow::showFindDialogue()
12462 {
12463     FindDialog *fd = new FindDialog(this);
12464     fd->setAttribute(Qt::WA_DeleteOnClose);
12465     fd->exec();
12466 }
12467 
12468 void ApplicationWindow::startRenameFolder()
12469 {
12470     FolderListItem *fi = current_folder->folderListItem();
12471     if (!fi)
12472         return;
12473 
12474     disconnect(&folders, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this,
12475                SLOT(folderItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
12476     fi->setFlags(fi->flags() | Qt::ItemIsEditable);
12477     fi->treeWidget()->editItem(fi, 0);
12478 }
12479 
12480 void ApplicationWindow::startRenameFolder(QTreeWidgetItem *item, int column)
12481 {
12482     if (!item || item == folders.topLevelItem(0))
12483         return;
12484 
12485     if (item->treeWidget() == &lv && item->type() == FolderListItem::FolderType) {
12486         disconnect(
12487                 &folders,
12488                 SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *, QTreeWidgetItem *)),
12489                 this, SLOT(folderItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
12490         current_folder = ((FolderListItem *)item)->folder();
12491         FolderListItem *it = current_folder->folderListItem();
12492         it->treeWidget()->setCurrentItem(it, 0);
12493         it->setFlags(it->flags() | Qt::ItemIsEditable);
12494         it->treeWidget()->editItem(it, column);
12495     } else {
12496         item->setFlags(item->flags() | Qt::ItemIsEditable);
12497         item->treeWidget()->editItem(item, 0);
12498         item->setFlags(item->flags() & ~Qt::ItemIsEditable);
12499     }
12500 }
12501 
12502 void ApplicationWindow::renameFolder(QTreeWidgetItem *it, int col, const QString &text)
12503 {
12504     Q_UNUSED(col)
12505 
12506     if (!it)
12507         return;
12508 
12509     if (it->text(0) == text)
12510         return;
12511 
12512     Folder *parent = (Folder *)current_folder->parent();
12513     if (!parent) // the parent folder is the project folder (it always exists)
12514         parent = projectFolder();
12515 
12516     if (text.isEmpty()) {
12517         QMessageBox::critical(this, tr("Error"), tr("Please enter a valid name!"));
12518         it->setFlags(it->flags() | Qt::ItemIsEditable);
12519         return;
12520     }
12521 
12522     QStringList lst = parent->subfolders();
12523     lst.removeAll(current_folder->name());
12524     while (lst.contains(text)) {
12525         QMessageBox::critical(this, tr("Error"),
12526                               tr("Name already exists!") + "\n"
12527                                       + tr("Please choose another name!"));
12528 
12529         it->setFlags(it->flags() | Qt::ItemIsEditable);
12530         it->setText(0, current_folder->name());
12531         it->treeWidget()->editItem(it, 0);
12532         return;
12533     }
12534 
12535     current_folder->setName(text);
12536     it->setText(0, text);
12537     it->setFlags(it->flags() & ~Qt::ItemIsEditable);
12538     connect(&folders, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this,
12539             SLOT(folderItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
12540     folders.scrollToItem(parent->folderListItem(), QAbstractItemView::EnsureVisible);
12541     folders.setCurrentItem(parent->folderListItem()); // update the list views
12542 }
12543 
12544 void ApplicationWindow::showAllFolderWindows()
12545 {
12546     QList<MyWidget *> lst = current_folder->windowsList();
12547     foreach (MyWidget *w, lst) { // force show all windows in current folder
12548         if (w) {
12549             updateWindowLists(w);
12550             switch (w->status()) {
12551             case MyWidget::Hidden:
12552                 w->showNormal();
12553                 break;
12554 
12555             case MyWidget::Normal:
12556                 w->showNormal();
12557                 break;
12558 
12559             case MyWidget::Minimized:
12560                 w->showMinimized();
12561                 break;
12562 
12563             case MyWidget::Maximized:
12564                 w->showMaximized();
12565                 break;
12566             }
12567         }
12568     }
12569 
12570     if ((current_folder->children()).isEmpty())
12571         return;
12572 
12573     FolderListItem *fi = current_folder->folderListItem();
12574     FolderListItem *item = (FolderListItem *)fi->child(0);
12575     int initial_depth = item->depth();
12576     QTreeWidgetItemIterator it(item);
12577     while (item && item->depth() >= initial_depth) { // show/hide windows in all subfolders
12578         lst = ((Folder *)item->folder())->windowsList();
12579         foreach (MyWidget *w, lst) {
12580             if (w && show_windows_policy == SubFolders) {
12581                 updateWindowLists(w);
12582                 switch (w->status()) {
12583                 case MyWidget::Hidden:
12584                     w->showNormal();
12585                     break;
12586 
12587                 case MyWidget::Normal:
12588                     w->showNormal();
12589                     break;
12590 
12591                 case MyWidget::Minimized:
12592                     w->showMinimized();
12593                     break;
12594 
12595                 case MyWidget::Maximized:
12596                     w->showMaximized();
12597                     break;
12598                 }
12599             } else
12600                 w->hide();
12601         }
12602 
12603         it++;
12604         item = (FolderListItem *)(*it);
12605     }
12606 }
12607 
12608 void ApplicationWindow::hideAllFolderWindows()
12609 {
12610     QList<MyWidget *> lst = current_folder->windowsList();
12611     foreach (MyWidget *w, lst)
12612         hideWindow(w);
12613 
12614     if ((current_folder->children()).isEmpty())
12615         return;
12616 
12617     if (show_windows_policy == SubFolders) {
12618         FolderListItem *fi = current_folder->folderListItem();
12619         FolderListItem *item = (FolderListItem *)fi->child(0);
12620         int initial_depth = item->depth();
12621         QTreeWidgetItemIterator it(item);
12622         while (item && item->depth() >= initial_depth) {
12623             lst = item->folder()->windowsList();
12624             foreach (MyWidget *w, lst)
12625                 hideWindow(w);
12626 
12627             it++;
12628             item = (FolderListItem *)(*it);
12629         }
12630     }
12631 }
12632 
12633 void ApplicationWindow::projectProperties()
12634 {
12635     QString s = QString(current_folder->name()) + "\n\n";
12636     s += "\n\n\n";
12637     s += tr("Type") + ": " + tr("Project") + "\n\n";
12638     if (projectname != "untitled") {
12639         s += tr("Path") + ": " + projectname + "\n\n";
12640 
12641         QFileInfo fi(projectname);
12642         s += tr("Size") + ": " + QString::number(fi.size()) + " " + tr("bytes") + "\n\n";
12643     }
12644 
12645     s += tr("Contents") + ": " + QString::number(windowsList().count()) + " " + tr("windows");
12646 
12647     s += ", " + QString::number(current_folder->subfolders().count()) + " " + tr("folders")
12648             + "\n\n";
12649     s += "\n\n\n";
12650 
12651     if (projectname != "untitled") {
12652         QFileInfo fi(projectname);
12653 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
12654         s += tr("Created") + ": " + QLocale().toString(fi.created()) + "\n\n";
12655 #else
12656         s += tr("Created") + ": " + QLocale().toString(fi.birthTime()) + "\n\n";
12657 #endif
12658         s += tr("Modified") + ": " + QLocale().toString(fi.lastModified()) + "\n\n";
12659     } else
12660         s += tr("Created") + ": " + current_folder->birthDate() + "\n\n";
12661 
12662     QMessageBox *mbox = new QMessageBox(tr("Properties"), s, QMessageBox::NoIcon, QMessageBox::Ok,
12663                                         QMessageBox::NoButton, QMessageBox::NoButton, this);
12664 
12665     mbox->setIconPixmap(QPixmap(":/appicon"));
12666     mbox->show();
12667 }
12668 
12669 void ApplicationWindow::folderProperties()
12670 {
12671     if (!current_folder->parent()) {
12672         projectProperties();
12673         return;
12674     }
12675 
12676     QString s = current_folder->name() + "\n\n";
12677     s += "\n\n\n";
12678     s += tr("Type") + ": " + tr("Folder") + "\n\n";
12679     s += tr("Path") + ": " + current_folder->path() + "\n\n";
12680     s += tr("Contents") + ": " + QString::number(current_folder->windowsList().count()) + " "
12681             + tr("windows");
12682     s += ", " + QString::number(current_folder->subfolders().count()) + " " + tr("folders")
12683             + "\n\n";
12684     // s += "\n\n\n";
12685     s += tr("Created") + ": " + current_folder->birthDate() + "\n\n";
12686     // s += tr("Modified") + ": " + current_folder->modificationDate() + "\n\n";
12687 
12688     QMessageBox *mbox = new QMessageBox(tr("Properties"), s, QMessageBox::NoIcon, QMessageBox::Ok,
12689                                         QMessageBox::NoButton, QMessageBox::NoButton, this);
12690 
12691     mbox->setIconPixmap(QPixmap(":/folder_open.xpm"));
12692     mbox->show();
12693 }
12694 
12695 void ApplicationWindow::addFolder()
12696 {
12697     QStringList lst = current_folder->subfolders();
12698     QString name = tr("New Folder");
12699     lst = lst.filter(name);
12700     if (!lst.isEmpty())
12701         name += " (" + QString::number(lst.size() + 1) + ")";
12702 
12703     Folder &f = current_folder->addChild<Folder>(name);
12704     addFolderListViewItem(&f);
12705 
12706     FolderListItem *fi = new FolderListItem(current_folder->folderListItem(), &f);
12707     f.setFolderListItem(fi);
12708     fi->setFlags(fi->flags() | Qt::ItemIsEditable);
12709     fi->treeWidget()->setCurrentItem(fi, 0);
12710     fi->treeWidget()->editItem(fi, 0);
12711     fi->treeWidget()->resizeColumnToContents(0);
12712 }
12713 
12714 bool ApplicationWindow::deleteFolder(Folder *f)
12715 {
12716     if (confirmCloseFolder
12717         && QMessageBox::information(
12718                 this, tr("Delete folder?"),
12719                 tr("Delete folder '%1' and all the windows it contains?").arg(f->name()), tr("Yes"),
12720                 tr("No"), 0, 0)) {
12721         return false;
12722     } else {
12723         FolderListItem *fi = f->folderListItem();
12724         foreach (MyWidget *w, f->windowsList())
12725             closeWindow(w);
12726 
12727         if (!(f->children()).isEmpty()) {
12728             FolderListItem *item = (FolderListItem *)fi->child(0);
12729             int initial_depth = item->depth();
12730             QTreeWidgetItemIterator it(item);
12731             while (item && item->depth() >= initial_depth) {
12732                 Folder *subFolder = (Folder *)item->folder();
12733                 if (subFolder) {
12734                     foreach (MyWidget *w, subFolder->windowsList()) {
12735                         removeWindowFromLists(w);
12736                         subFolder->removeWindow(w);
12737                         delete w;
12738                     }
12739 
12740                     FolderListItem *old_item = item;
12741                     it++;
12742                     item = (FolderListItem *)(*it);
12743                     delete subFolder;
12744                     delete old_item;
12745                 }
12746             }
12747         }
12748 
12749         delete f;
12750         delete fi;
12751         return true;
12752     }
12753 }
12754 
12755 void ApplicationWindow::deleteFolder()
12756 {
12757     Folder *parent = (Folder *)current_folder->parent();
12758     if (!parent)
12759         parent = projectFolder();
12760 
12761     folders.blockSignals(true);
12762 
12763     if (deleteFolder(current_folder)) {
12764         current_folder = parent;
12765         folders.setCurrentItem(parent->folderListItem());
12766         changeFolder(parent, true);
12767     }
12768 
12769     folders.blockSignals(false);
12770     folders.setFocus();
12771 }
12772 
12773 void ApplicationWindow::folderItemDoubleClicked(QTreeWidgetItem *it, int column)
12774 {
12775     Q_UNUSED(column)
12776     if (!it)
12777         return;
12778 
12779     if (it->type() == FolderListItem::FolderType) {
12780         FolderListItem *item = ((FolderListItem *)it)->folder()->folderListItem();
12781         folders.setCurrentItem(item);
12782     } else if (it->type() == WindowListItem::WindowType) {
12783         MyWidget *w = ((WindowListItem *)it)->window();
12784         if (!w)
12785             return;
12786         if (d_workspace.activeSubWindow() != w)
12787             activateSubWindow(w);
12788         else {
12789             if (!w->isMaximized())
12790                 w->setMaximized();
12791             else
12792                 w->setNormal();
12793         }
12794     }
12795 }
12796 
12797 void ApplicationWindow::folderItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
12798 {
12799     Q_UNUSED(previous)
12800 
12801     if (!current)
12802         return;
12803 
12804     if (current == previous)
12805         return;
12806 
12807     current->setExpanded(true);
12808     changeFolder(((FolderListItem *)current)->folder());
12809     folders.scrollToItem(folders.currentItem(), QAbstractItemView::EnsureVisible);
12810     folders.setFocus();
12811 }
12812 
12813 void ApplicationWindow::hideFolderWindows(Folder *f)
12814 {
12815     QList<MyWidget *> lst = f->windowsList();
12816     foreach (MyWidget *w, lst)
12817         w->hide();
12818 
12819     if ((f->children()).isEmpty())
12820         return;
12821 
12822     FolderListItem *fi = f->folderListItem();
12823     FolderListItem *item = (FolderListItem *)fi->child(0);
12824     if (!item)
12825         return;
12826     int initial_depth = item->depth();
12827     QTreeWidgetItemIterator it(item);
12828     while (item && item->depth() >= initial_depth) {
12829         lst = item->folder()->windowsList();
12830         foreach (MyWidget *w, lst)
12831             w->hide();
12832         it++;
12833         item = (FolderListItem *)(*it);
12834     }
12835 }
12836 
12837 bool ApplicationWindow::changeFolder(Folder *newFolder, bool force)
12838 {
12839     if (current_folder == newFolder && !force)
12840         return false;
12841 
12842     deactivateFolders();
12843     newFolder->folderListItem()->setActive(true);
12844 
12845     Folder *oldFolder = current_folder;
12846     MyWidget::Status old_active_window_state = MyWidget::Normal;
12847     MyWidget *old_active_window = oldFolder->activeWindow();
12848     if (old_active_window)
12849         old_active_window_state = old_active_window->status();
12850 
12851     MyWidget::Status active_window_state = MyWidget::Normal;
12852     MyWidget *active_window = newFolder->activeWindow();
12853     if (active_window)
12854         active_window_state = active_window->status();
12855 
12856     d_workspace.blockSignals(true);
12857     hideFolderWindows(oldFolder);
12858     current_folder = newFolder;
12859 
12860     lv.clear();
12861 
12862     QObjectList folderLst = newFolder->children();
12863     if (!folderLst.isEmpty()) {
12864         foreach (QObject *f, folderLst)
12865             addFolderListViewItem(static_cast<Folder *>(f));
12866     }
12867 
12868     QList<MyWidget *> lst = newFolder->windowsList();
12869     foreach (MyWidget *w, lst) {
12870         w->blockSignals(true);
12871         if (!hiddenWindows.contains(w) && !outWindows.contains(w)
12872             && show_windows_policy != HideAll) {
12873             // show only windows in the current folder which are not hidden by the user
12874             if (w->status() == MyWidget::Normal)
12875                 w->showNormal();
12876             else if (w->status() == MyWidget::Minimized)
12877                 w->showMinimized();
12878         } else
12879             w->setStatus(MyWidget::Hidden);
12880 
12881         addListViewItem(w);
12882     }
12883 
12884     if (!(newFolder->children()).isEmpty()) {
12885         FolderListItem *fi = newFolder->folderListItem();
12886         FolderListItem *item = (FolderListItem *)fi->child(0);
12887         if (!item)
12888             return false;
12889         int initial_depth = item->depth();
12890         QTreeWidgetItemIterator it(item);
12891         while (item && item->depth() >= initial_depth) { // show/hide windows in subfolders
12892             lst = ((Folder *)item->folder())->windowsList();
12893             foreach (MyWidget *w, lst) {
12894                 if (!hiddenWindows.contains(w) && !outWindows.contains(w)) {
12895                     if (show_windows_policy == SubFolders) {
12896                         if (w->status() == MyWidget::Normal || w->status() == MyWidget::Maximized)
12897                             w->showNormal();
12898                         else if (w->status() == MyWidget::Minimized)
12899                             w->showMinimized();
12900                     } else if (w->isVisible())
12901                         w->hide();
12902                 }
12903             }
12904             it++;
12905             item = (FolderListItem *)(*it);
12906         }
12907     }
12908 
12909     d_workspace.blockSignals(false);
12910 
12911     if (active_window) {
12912         d_workspace.setActiveSubWindow(active_window);
12913         if (active_window_state == MyWidget::Minimized)
12914             active_window->showMinimized(); // d_workspace.setActiveWindow() makes minimized windows
12915                                             // to be shown normally
12916         else if (active_window_state == MyWidget::Maximized) {
12917             if (active_window->inherits("Graph3D"))
12918                 ((Graph3D *)active_window)->setIgnoreFonts(true);
12919             active_window->showMaximized();
12920             if (active_window->inherits("Graph3D"))
12921                 ((Graph3D *)active_window)->setIgnoreFonts(false);
12922         }
12923         current_folder->setActiveWindow(active_window);
12924         customMenu(active_window);
12925         customToolBars(active_window);
12926     }
12927 
12928     if (old_active_window) {
12929         old_active_window->setStatus(old_active_window_state);
12930         oldFolder->setActiveWindow(old_active_window);
12931     }
12932 
12933     foreach (MyWidget *w, newFolder->windowsList())
12934         w->blockSignals(false);
12935 
12936     return true;
12937 }
12938 
12939 void ApplicationWindow::deactivateFolders()
12940 {
12941     QTreeWidgetItemIterator it(&folders);
12942     while (*it) {
12943         ((FolderListItem *)(*it))->setActive(false);
12944         it++;
12945     }
12946 }
12947 
12948 void ApplicationWindow::addListViewItem(MyWidget *w)
12949 {
12950     if (!w)
12951         return;
12952 
12953     WindowListItem *it = new WindowListItem(&lv, w);
12954     if (w->inherits("Matrix")) {
12955         it->setIcon(0, QIcon(QPixmap(":/matrix.xpm")));
12956         it->setText(1, tr("Matrix"));
12957     } else if (w->inherits("Table")) {
12958         it->setIcon(0, QIcon(QPixmap(":/worksheet.xpm")));
12959         it->setText(1, tr("Table"));
12960     } else if (w->inherits("Note")) {
12961         it->setIcon(0, QIcon(QPixmap(":/note.xpm")));
12962         it->setText(1, tr("Note"));
12963     } else if (w->inherits("MultiLayer")) {
12964         it->setIcon(0, QIcon(QPixmap(":/graph.xpm")));
12965         it->setText(1, tr("Graph"));
12966     } else if (w->inherits("Graph3D")) {
12967         it->setIcon(0, QIcon(QPixmap(":/trajectory.xpm")));
12968         it->setText(1, tr("3D Graph"));
12969     }
12970 
12971     it->setText(0, w->name());
12972     it->setText(2, w->aspect());
12973     it->setText(3, w->birthDate());
12974     it->setText(4, w->windowLabel());
12975 }
12976 
12977 void ApplicationWindow::windowProperties()
12978 {
12979     WindowListItem *it = (WindowListItem *)lv.currentItem();
12980     MyWidget *w = it->window();
12981     if (!w)
12982         return;
12983 
12984     QMessageBox *mbox =
12985             new QMessageBox(tr("Properties"), QString(), QMessageBox::NoIcon, QMessageBox::Ok,
12986                             QMessageBox::NoButton, QMessageBox::NoButton, this);
12987 
12988     QString s = QString(w->name()) + "\n\n";
12989     s += "\n\n\n";
12990 
12991     s += tr("Label") + ": " + ((MyWidget *)w)->windowLabel() + "\n\n";
12992 
12993     if (w->inherits("Matrix")) {
12994         mbox->setIconPixmap(QPixmap(":/matrix.xpm"));
12995         s += tr("Type") + ": " + tr("Matrix") + "\n\n";
12996     } else if (w->inherits("Table")) {
12997         mbox->setIconPixmap(QPixmap(":/worksheet.xpm"));
12998         s += tr("Type") + ": " + tr("Table") + "\n\n";
12999     } else if (w->inherits("Note")) {
13000         mbox->setIconPixmap(QPixmap(":/note.xpm"));
13001         s += tr("Type") + ": " + tr("Note") + "\n\n";
13002     } else if (w->inherits("MultiLayer")) {
13003         mbox->setIconPixmap(QPixmap(":/graph.xpm"));
13004         s += tr("Type") + ": " + tr("Graph") + "\n\n";
13005     } else if (w->inherits("Graph3D")) {
13006         mbox->setIconPixmap(QPixmap(":/trajectory.xpm"));
13007         s += tr("Type") + ": " + tr("3D Graph") + "\n\n";
13008     }
13009     s += tr("Path") + ": " + current_folder->path() + "\n\n";
13010     s += tr("Created") + ": " + w->birthDate() + "\n\n";
13011     s += tr("Status") + ": " + it->text(2) + "\n\n";
13012     mbox->setText(s);
13013     mbox->show();
13014 }
13015 
13016 void ApplicationWindow::addFolderListViewItem(Folder *f)
13017 {
13018     if (!f)
13019         return;
13020 
13021     FolderListItem *it = new FolderListItem(&lv, f);
13022     it->setActive(false);
13023     it->setText(0, f->name());
13024     it->setText(1, tr("Folder"));
13025     it->setText(3, f->birthDate());
13026 }
13027 
13028 void ApplicationWindow::find(const QString &s, bool windowNames, bool labels, bool folderNames,
13029                              bool caseSensitive, bool partialMatch, bool subfolders)
13030 {
13031     if (windowNames || labels) {
13032         MyWidget *w =
13033                 current_folder->findWindow(s, windowNames, labels, caseSensitive, partialMatch);
13034         if (w) {
13035             activateSubWindow(w);
13036             return;
13037         }
13038 
13039         if (subfolders) {
13040             FolderListItem *item = (FolderListItem *)folders.currentItem()->child(0);
13041             QTreeWidgetItemIterator it(item);
13042             while (item) {
13043                 Folder *f = item->folder();
13044                 MyWidget *w = f->findWindow(s, windowNames, labels, caseSensitive, partialMatch);
13045                 if (w) {
13046                     folders.setCurrentItem(f->folderListItem());
13047                     activateSubWindow(w);
13048                     return;
13049                 }
13050                 it++;
13051                 item = (FolderListItem *)(*it);
13052             }
13053         }
13054     }
13055 
13056     if (folderNames) {
13057         Folder *f = current_folder->findSubfolder(s, caseSensitive, partialMatch);
13058         if (f) {
13059             folders.setCurrentItem(f->folderListItem());
13060             return;
13061         }
13062 
13063         if (subfolders) {
13064             FolderListItem *item = (FolderListItem *)folders.currentItem()->child(0);
13065             QTreeWidgetItemIterator it(item);
13066             while (item) {
13067                 Folder *f = item->folder()->findSubfolder(s, caseSensitive, partialMatch);
13068                 if (f) {
13069                     folders.setCurrentItem(f->folderListItem());
13070                     return;
13071                 }
13072 
13073                 it++;
13074                 item = (FolderListItem *)(*it);
13075             }
13076         }
13077     }
13078 
13079     QMessageBox::warning(this, tr("No match found"),
13080                          tr("Sorry, no match found for string: '%1'").arg(s));
13081 }
13082 
13083 void ApplicationWindow::dropFolderItems(QTreeWidgetItem *dest)
13084 {
13085     if (!dest || draggedItems.isEmpty())
13086         return;
13087 
13088     Folder *dest_f = ((FolderListItem *)dest)->folder();
13089 
13090     QTreeWidgetItem *it;
13091     QStringList subfolders = dest_f->subfolders();
13092 
13093     foreach (it, draggedItems) {
13094         if (it->type() == FolderListItem::FolderType) {
13095             Folder *f = ((FolderListItem *)it)->folder();
13096             FolderListItem *src = f->folderListItem();
13097             if (dest_f == f) {
13098                 QMessageBox::critical(this, "Error", tr("Cannot move an object to itself!"));
13099                 return;
13100             }
13101 
13102             if (((FolderListItem *)dest)->isChildOf(src)) {
13103                 QMessageBox::critical(this, "Error",
13104                                       tr("Cannot move a parent folder into a child folder!"));
13105                 draggedItems.clear();
13106                 folders.setCurrentItem(current_folder->folderListItem());
13107                 return;
13108             }
13109 
13110             Folder *parent = (Folder *)f->parent();
13111             if (!parent)
13112                 parent = projectFolder();
13113             if (dest_f == parent)
13114                 return;
13115 
13116             if (subfolders.contains(f->name())) {
13117                 QMessageBox::critical(this, tr("SciDAVis") + " - " + tr("Skipped moving folder"),
13118                                       tr("The destination folder already contains a folder called "
13119                                          "'%1'! Folder skipped!")
13120                                               .arg(f->name()));
13121             } else
13122                 moveFolder(src, (FolderListItem *)dest);
13123         } else {
13124             if (dest_f == current_folder)
13125                 return;
13126 
13127             MyWidget *w = ((WindowListItem *)it)->window();
13128             if (w) {
13129                 current_folder->removeWindow(w);
13130                 w->hide();
13131                 dest_f->addWindow(w);
13132                 delete it;
13133             }
13134         }
13135     }
13136 
13137     draggedItems.clear();
13138     current_folder = dest_f;
13139     folders.setCurrentItem(dest_f->folderListItem());
13140     changeFolder(dest_f, true);
13141     folders.setFocus();
13142     modifiedProject();
13143 }
13144 
13145 void ApplicationWindow::moveFolder(FolderListItem *src, FolderListItem *dest)
13146 {
13147     folders.blockSignals(true);
13148 
13149     Folder *dest_f = dest->folder();
13150     Folder *src_f = src->folder();
13151 
13152     dest_f = &dest_f->addChild<Folder>(src_f->name());
13153     dest_f->setBirthDate(src_f->birthDate());
13154     dest_f->setModificationDate(src_f->modificationDate());
13155 
13156     FolderListItem *copy_item = new FolderListItem(dest, dest_f);
13157     copy_item->setText(0, src_f->name());
13158     dest_f->setFolderListItem(copy_item);
13159 
13160     QList<MyWidget *> lst = src_f->windowsList();
13161     foreach (MyWidget *w, lst) {
13162         src_f->removeWindow(w);
13163         w->hide();
13164         dest_f->addWindow(w);
13165     }
13166 
13167     if (!(src_f->children()).isEmpty()) {
13168         FolderListItem *item = (FolderListItem *)src->child(0);
13169         int initial_depth = item->depth();
13170         QTreeWidgetItemIterator it(item);
13171         while (item && item->depth() >= initial_depth) {
13172             src_f = (Folder *)item->folder();
13173 
13174             dest_f = &dest_f->addChild<Folder>(src_f->name());
13175             dest_f->setBirthDate(src_f->birthDate());
13176             dest_f->setModificationDate(src_f->modificationDate());
13177 
13178             copy_item = new FolderListItem(copy_item, dest_f);
13179             copy_item->setText(0, src_f->name());
13180             dest_f->setFolderListItem(copy_item);
13181 
13182             lst = QList<MyWidget *>(src_f->windowsList());
13183             foreach (MyWidget *w, lst) {
13184                 src_f->removeWindow(w);
13185                 w->hide();
13186                 dest_f->addWindow(w);
13187             }
13188 
13189             it++;
13190             item = (FolderListItem *)(*it);
13191         }
13192     }
13193 
13194     src_f = src->folder();
13195     delete src_f;
13196     delete src;
13197     folders.blockSignals(false);
13198 }
13199 
13200 #ifdef SEARCH_FOR_UPDATES
13201 
13202 void ApplicationWindow::searchForUpdates()
13203 {
13204     int choice = QMessageBox::question(
13205             this, versionString(),
13206             tr("SciDAVis will now try to determine whether a new version of SciDAVis is available. "
13207                "Please modify your firewall settings in order to allow SciDAVis to connect to the "
13208                "internet.")
13209                     + "\n" + tr("Do you wish to continue?"),
13210             QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape);
13211 
13212     if (choice == QMessageBox::Yes) {
13213         // http.get(QNetworkRequest(QUrl("http://scidavis.sourceforge.net/current_version.txt")));
13214         http.get(QNetworkRequest(QUrl("https://raw.githubusercontent.com/highperformancecoder/"
13215                                       "scidavis/master/libscidavis/src/version.cpp")));
13216     }
13217 }
13218 
13219 void ApplicationWindow::receivedVersionFile(QNetworkReply *netreply)
13220 {
13221     if (netreply->error() != QNetworkReply::NoError) {
13222         QMessageBox::warning(
13223                 this, tr("HTTP get version file"),
13224                 tr("Error while fetching version file with HTTP: %1.").arg(netreply->error()));
13225         return;
13226     }
13227 
13228     version_buffer = netreply->readAll();
13229 
13230     if (version_buffer.size() > 0) {
13231         QString available_versionString = QString();
13232         int available_version = 0;
13233         bool intok = false;
13234         QTextStream t(version_buffer);
13235         t.setCodec(QTextCodec::codecForName("UTF-8"));
13236         QStringList version_lines = t.readAll().split('\n');
13237 
13238         if (version_lines.count() == 1) {
13239             QStringList list = version_lines.at(0).split(".");
13240             if (list.count() > 2)
13241                 available_version = (list.at(0).toInt() << 16) + (list.at(1).toInt() << 8)
13242                         + list.at(2).toInt(&intok);
13243             available_versionString = version_lines.at(0);
13244         } else if (version_lines.count() > 2) {
13245             available_version = version_lines.at(1).split('=').at(1).split(';').at(0).toInt(&intok);
13246             available_versionString = version_lines.at(2).split('=').at(1).split('"').at(1);
13247         }
13248 
13249         if (intok) {
13250             if (available_version > SciDAVis::version()) {
13251                 if (QMessageBox::question(this, tr("Updates Available"),
13252                                           tr("There is a newer version of SciDAVis (%1) available "
13253                                              "for download. Would you like to download it now?")
13254                                                   .arg(available_versionString),
13255                                           QMessageBox::Yes | QMessageBox::Default,
13256                                           QMessageBox::No | QMessageBox::Escape)
13257                     == QMessageBox::Yes)
13258                     QDesktopServices::openUrl(QUrl(DOWNLOAD_URI));
13259             } else {
13260                 QMessageBox::information(
13261                         this, versionString(),
13262                         tr("No updates available. You are already running the latest version."));
13263             }
13264         } else
13265             QMessageBox::information(this, tr("Invalid version file"),
13266                                      tr("The version file (contents: \"%1\") could not be decoded "
13267                                         "into a valid version number.")
13268                                              .arg(version_lines.join("\n")));
13269         autoSearchUpdatesRequest = false;
13270     }
13271 }
13272 
13273 #endif // defined SEARCH_FOR_UPDATES
13274 
13275 /*!
13276   Turns 3D animation on or off
13277   */
13278 void ApplicationWindow::toggle3DAnimation(bool on)
13279 {
13280     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D"))
13281         ((Graph3D *)d_workspace.activeSubWindow())->animate(on);
13282 }
13283 
13284 QString ApplicationWindow::generateUniqueName(const QString &name, bool increment)
13285 {
13286     int index = 0;
13287     QList<MyWidget *> windows = windowsList();
13288     QStringList lst;
13289 
13290     for (int i = 0; i < windows.count(); i++) {
13291         MyWidget *widget = windows.at(i);
13292         if (!widget)
13293             continue;
13294         lst << widget->name();
13295         if (widget->name().startsWith(name))
13296             index++;
13297     }
13298 
13299     QString newName = name;
13300     if (increment) // force return of a different name
13301         newName += QString::number(++index);
13302     else {
13303         if (index > 0)
13304             newName += QString::number(index);
13305     }
13306 
13307     while (lst.contains(newName))
13308         newName = name + QString::number(++index);
13309     return newName;
13310 }
13311 
13312 void ApplicationWindow::clearTable()
13313 {
13314     Table *t = (Table *)d_workspace.activeSubWindow();
13315     if (!t || !t->inherits("Table"))
13316         return;
13317 
13318     if (QMessageBox::question(this, tr("Warning"),
13319                               tr("This will clear the contents of all the data associated with the "
13320                                  "table. Are you sure?"),
13321                               tr("&Yes"), tr("&No"), QString(), 0, 1))
13322         return;
13323     else
13324         t->clear();
13325 }
13326 
13327 /*!
13328   Turns perspective mode on or off
13329   */
13330 void ApplicationWindow::togglePerspective(bool on)
13331 {
13332     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D")) {
13333         ((Graph3D *)d_workspace.activeSubWindow())->setOrtho(!on);
13334     }
13335 }
13336 
13337 /*!
13338   Resets rotation of 3D plots to default values
13339   */
13340 void ApplicationWindow::resetRotation()
13341 {
13342     if (d_workspace.activeSubWindow() && d_workspace.activeSubWindow()->inherits("Graph3D")) {
13343         ((Graph3D *)d_workspace.activeSubWindow())->setRotation(30, 0, 15);
13344     }
13345 }
13346 
13347 /*!
13348   Finds best layout for the 3D plot
13349   */
13350 void ApplicationWindow::fitFrameToLayer()
13351 {
13352     if (!d_workspace.activeSubWindow() || !d_workspace.activeSubWindow()->inherits("Graph3D"))
13353         return;
13354 
13355     ((Graph3D *)d_workspace.activeSubWindow())->findBestLayout();
13356 }
13357 
13358 ApplicationWindow::~ApplicationWindow()
13359 {
13360     if (lastCopiedLayer)
13361         delete lastCopiedLayer;
13362 
13363     QApplication::clipboard()->clear(QClipboard::Clipboard);
13364 }
13365 
13366 QString ApplicationWindow::versionString()
13367 {
13368     return SciDAVis::versionString();
13369 }
13370 
13371 unsigned int ApplicationWindow::convertOldToNewColorIndex(unsigned int cindex)
13372 {
13373     if ((cindex == 13) || (cindex == 14)) // white and light gray
13374         return cindex + 4;
13375 
13376     if (cindex == 15) // dark gray
13377         return cindex + 8;
13378 
13379     return cindex;
13380 }
13381 
13382 void ApplicationWindow::cascade()
13383 {
13384     QList<QMdiSubWindow *> windows = d_workspace.subWindowList(QMdiArea::StackingOrder);
13385 
13386     const int xoffset = 13;
13387     const int yoffset = 20;
13388 
13389     int x = 0;
13390     int y = 0;
13391 
13392     foreach (QWidget *w, windows) {
13393         w->activateWindow();
13394         w->showNormal();
13395         ((MyWidget *)w)->setStatus(MyWidget::Normal);
13396         updateWindowStatus((MyWidget *)w);
13397 
13398         w->setGeometry(x, y, w->width(), w->height());
13399         w->raise();
13400         x += xoffset;
13401         y += yoffset;
13402     }
13403     modifiedProject();
13404 }
13405 
13406 ApplicationWindow *ApplicationWindow::loadScript(const QString &fn, const QStringList &args,
13407                                                  bool execute)
13408 {
13409     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
13410     ApplicationWindow *app = new ApplicationWindow();
13411     app->applyUserSettings();
13412     bool isPython = fn.endsWith(".py", Qt::CaseInsensitive);
13413     app->m_batch = true;
13414     if (isPython)
13415         app->setScriptingLangForBatch("Python");
13416     else
13417         app->setScriptingLangForBatch("muParser");
13418     app->showMaximized();
13419     Note *script_note = app->newNote(fn);
13420     if (isPython) {
13421         // copy any arguments into the sys.argv array
13422         script_note->insert("import sys\n");
13423         QString prologue = "sys.argv=['" + fn + "'";
13424         for (auto &a : args)
13425             prologue += ",'" + a + "'";
13426         prologue += "]\n";
13427         script_note->insert(prologue);
13428     }
13429     script_note->importASCII(fn);
13430     QApplication::restoreOverrideCursor();
13431     if (execute) {
13432         // we need to disable the redirect of stdio, as this is batch processing
13433         Script *script = nullptr;
13434         if (auto scriptEdit = script_note->findChild<ScriptEdit *>())
13435             if ((script = scriptEdit->findChild<Script *>()))
13436                 script->batchMode = true;
13437         if (!script_note->executeAll())
13438             exit(1);
13439         if (script)
13440             script->batchMode = false;
13441     }
13442     app->m_batch = false;
13443     return app;
13444 }
13445 
13446 QMenu *ApplicationWindow::createToolbarsMenu()
13447 {
13448     QMenu *menu = 0;
13449     QList<QToolBar *> toolbars = this->findChildren<QToolBar *>();
13450     if (toolbars.size()) {
13451         menu = new QMenu(this);
13452         foreach (QToolBar *toolbar, toolbars) {
13453             if (toolbar->parentWidget() == this)
13454                 menu->addAction(toolbar->toggleViewAction());
13455         }
13456     }
13457     return menu;
13458 }
13459 
13460 void ApplicationWindow::setStatusBarText(const QString &text)
13461 {
13462     d_status_info->setText(text);
13463     QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
13464 }
13465 
13466 void ApplicationWindow::copyStatusBarText()
13467 {
13468     QApplication::clipboard()->setText(d_status_info->text());
13469 }
13470 
13471 void ApplicationWindow::showStatusBarContextMenu(const QPoint &pos)
13472 {
13473     QMenu cm(this);
13474     cm.addAction(actionCopyStatusBarText);
13475     cm.exec(d_status_info->mapToGlobal(pos));
13476 }
13477 
13478 QMenu *ApplicationWindow::showWindowMenuImpl(MyWidget *widget)
13479 {
13480     d_workspace.setActiveSubWindow(widget); // FIXME not user-friendly, but can't be simply removed
13481 
13482     QMenu *cm = new QMenu(this);
13483     QMenu *depend_menu = new QMenu(this);
13484 
13485     if (widget->inherits("Table"))
13486         cm->addAction(actionShowExportASCIIDialog);
13487     else if (widget->inherits("Note"))
13488         cm->addAction(actionSaveNote);
13489     else
13490         cm->addAction(actionSaveTemplate);
13491     cm->addAction(actionPrint);
13492     cm->addAction(actionCopyWindow);
13493     cm->addSeparator();
13494     cm->addAction(actionRename);
13495     cm->addAction(actionCloseWindow);
13496     if (!hidden(widget))
13497         cm->addAction(actionHideActiveWindow);
13498     cm->addAction(actionActivateWindow);
13499     cm->addAction(actionMinimizeWindow);
13500     cm->addAction(actionMaximizeWindow);
13501     cm->addAction(actionResizeWindow);
13502     cm->addSeparator();
13503     cm->addAction(tr("&Properties..."), this, SLOT(windowProperties()));
13504 
13505     int n;
13506     if (widget->inherits("Table")) {
13507         QStringList graphs = dependingPlots(widget->name());
13508         n = graphs.count();
13509         if (n > 0) {
13510             cm->addSeparator();
13511             for (int i = 0; i < n; i++)
13512                 depend_menu->addAction(graphs[i], this, SLOT(setActiveWindowFromAction()));
13513 
13514             depend_menu->setTitle(tr("D&epending Graphs"));
13515             cm->addMenu(depend_menu);
13516         }
13517     } else if (widget->inherits("Matrix")) {
13518         QStringList graphs = depending3DPlots((Matrix *)widget);
13519         n = graphs.count();
13520         if (n > 0) {
13521             cm->addSeparator();
13522             for (int i = 0; i < n; i++)
13523                 depend_menu->addAction(graphs[i], this, SLOT(setActiveWindowFromAction()));
13524 
13525             depend_menu->setTitle(tr("D&epending 3D Graphs"));
13526             cm->addMenu(depend_menu);
13527         }
13528     } else if (widget->inherits("MultiLayer")) {
13529         QStringList tbls = multilayerDependencies(widget);
13530         n = tbls.count();
13531         if (n > 0) {
13532             cm->addSeparator();
13533             for (int i = 0; i < n; i++)
13534                 depend_menu->addAction(tbls[i], this, SLOT(setActiveWindowFromAction()));
13535 
13536             depend_menu->setTitle(tr("D&epends on"));
13537             cm->addMenu(depend_menu);
13538         }
13539     } else if (widget->inherits("Graph3D")) {
13540         Graph3D *sp = (Graph3D *)widget;
13541         Matrix *m = sp->matrix();
13542         QString formula = sp->formula();
13543         if (!formula.isEmpty()) {
13544             cm->addSeparator();
13545             if (formula.contains("_")) {
13546 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
13547                 QStringList tl = formula.split("_", Qt::SkipEmptyParts);
13548 #else
13549                 QStringList tl = formula.split("_", QString::SkipEmptyParts);
13550 #endif
13551 
13552                 depend_menu->addAction(tl[0], this, SLOT(setActiveWindowFromAction()));
13553 
13554                 depend_menu->setTitle(tr("D&epends on"));
13555                 cm->addMenu(depend_menu);
13556             } else if (m) {
13557                 depend_menu->addAction(m->name(), this, SLOT(setActiveWindowFromAction()));
13558                 depend_menu->setTitle(tr("D&epends on"));
13559                 cm->addMenu(depend_menu);
13560             }
13561         }
13562     }
13563 
13564     return cm;
13565 }
13566 
13567 void ApplicationWindow::setActiveWindowFromAction()
13568 {
13569     QAction *action = qobject_cast<QAction *>(sender());
13570     if (action)
13571         activateSubWindow(qobject_cast<MyWidget *>(window(action->text())));
13572 }
13573 
13574 bool ApplicationWindow::validFor3DPlot(Table *table)
13575 {
13576     if (table->numCols() < 2) {
13577         QMessageBox::critical(0, tr("Error"),
13578                               tr("You need at least two columns for this operation!"));
13579         return false;
13580     }
13581     if (table->firstSelectedColumn() < 0
13582         || table->colPlotDesignation(table->firstSelectedColumn()) != SciDAVis::Z) {
13583         QMessageBox::critical(0, tr("Error"), tr("Please select a Z column for this operation!"));
13584         return false;
13585     }
13586     if (table->noXColumn()) {
13587         QMessageBox::critical(0, tr("Error"), tr("You need to define a X column first!"));
13588         return false;
13589     }
13590     if (table->noYColumn()) {
13591         QMessageBox::critical(0, tr("Error"), tr("You need to define a Y column first!"));
13592         return false;
13593     }
13594     return true;
13595 }
13596 
13597 bool ApplicationWindow::validFor2DPlot(Table *table, int type)
13598 {
13599     switch (type) {
13600     case Graph::Histogram:
13601     case Graph::Pie:
13602     case Graph::Box:
13603         if (table->selectedColumnCount() < 1) {
13604             QMessageBox::warning(this, tr("Error"), tr("Please select a column to plot!"));
13605             return false;
13606         }
13607         break;
13608     default:
13609         if (table->selectedColumnCount(SciDAVis::Y) < 1) {
13610             QMessageBox::warning(this, tr("Error"), tr("Please select a Y column to plot!"));
13611             return false;
13612         } else if (table->numCols() < 2) {
13613             QMessageBox::critical(this, tr("Error"),
13614                                   tr("You need at least two columns for this operation!"));
13615             return false;
13616         } else if (table->noXColumn()) {
13617             QMessageBox::critical(this, tr("Error"),
13618                                   tr("Please set a default X column for this table, first!"));
13619             return false;
13620         }
13621         break;
13622     }
13623 
13624     return true;
13625 }
13626 
13627 void ApplicationWindow::selectPlotType(int type)
13628 {
13629     if (!d_workspace.activeSubWindow())
13630         return;
13631 
13632     Table *table = qobject_cast<Table *>(d_workspace.activeSubWindow());
13633     if (table && validFor2DPlot(table, type)) {
13634         switch (type) {
13635         case Graph::Histogram:
13636         case Graph::Pie:
13637         case Graph::Box:
13638             multilayerPlot(table, table->selectedColumns(), (Graph::CurveType)type,
13639                            table->firstSelectedRow(), table->lastSelectedRow());
13640             break;
13641         default:
13642             multilayerPlot(table, table->drawableColumnSelection(), (Graph::CurveType)type,
13643                            table->firstSelectedRow(), table->lastSelectedRow());
13644             break;
13645         }
13646         return;
13647     }
13648 
13649     MultiLayer *ml = qobject_cast<MultiLayer *>(d_workspace.activeSubWindow());
13650     if (ml) {
13651         Graph *g = ml->activeGraph();
13652         if (g->curves() > 0)
13653             g->setCurveType(g->curves() - 1, (Graph::CurveType)type);
13654     }
13655 }
13656 
13657 void ApplicationWindow::handleAspectAdded(const AbstractAspect *parent, int index)
13658 {
13659     AbstractAspect *aspect = parent->child(index);
13660     ::future::Matrix *matrix = qobject_cast<::future::Matrix *>(aspect);
13661     if (matrix) {
13662         initMatrix(static_cast<Matrix *>(matrix->view()));
13663         return;
13664     }
13665     ::future::Table *table = qobject_cast<::future::Table *>(aspect);
13666     if (table) {
13667         initTable(static_cast<Table *>(table->view()));
13668         return;
13669     }
13670 }
13671 
13672 void ApplicationWindow::handleAspectAboutToBeRemoved(const AbstractAspect *parent, int index)
13673 {
13674     AbstractAspect *aspect = parent->child(index);
13675     ::future::Matrix *matrix = qobject_cast<::future::Matrix *>(aspect);
13676     if (matrix) {
13677         closeWindow(static_cast<Matrix *>(matrix->view()));
13678         return;
13679     }
13680     ::future::Table *table = qobject_cast<::future::Table *>(aspect);
13681     if (table) {
13682         closeWindow(static_cast<Table *>(table->view()));
13683         return;
13684     }
13685 }
13686 
13687 void ApplicationWindow::showHistory()
13688 {
13689     if (!d_project->undoStack())
13690         return;
13691     QDialog dialog;
13692     QVBoxLayout layout(&dialog);
13693 
13694     QDialogButtonBox button_box;
13695     button_box.setOrientation(Qt::Horizontal);
13696     button_box.setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::NoButton
13697                                   | QDialogButtonBox::Ok);
13698     QObject::connect(&button_box, SIGNAL(accepted()), &dialog, SLOT(accept()));
13699     QObject::connect(&button_box, SIGNAL(rejected()), &dialog, SLOT(reject()));
13700 
13701     int index = d_project->undoStack()->index();
13702     QUndoView undo_view(d_project->undoStack());
13703 
13704     layout.addWidget(&undo_view);
13705     layout.addWidget(&button_box);
13706 
13707     dialog.setWindowTitle(tr("Undo/Redo History"));
13708     if (dialog.exec() == QDialog::Accepted)
13709         return;
13710 
13711     d_project->undoStack()->setIndex(index);
13712 }
13713 
13714 QStringList ApplicationWindow::tableWindows()
13715 {
13716     QList<AbstractAspect *> tables = d_project->descendantsThatInherit("future::Table");
13717     QStringList result;
13718     foreach (AbstractAspect *aspect, tables)
13719         result.append(aspect->name());
13720     return result;
13721 }
13722 
13723 QSettings &ApplicationWindow::getSettings()
13724 {
13725 #ifdef Q_OS_MAC // Mac
13726     static QSettings d_settings(QSettings::IniFormat, QSettings::UserScope, "SciDAVis", "SciDAVis");
13727 #else
13728     static QSettings d_settings(QSettings::NativeFormat, QSettings::UserScope, "SciDAVis",
13729                                 "SciDAVis");
13730 #endif
13731     return d_settings;
13732 }
13733 
13734 // initialize singleton
13735 static auto &SciDavisSettingsSingleton = ApplicationWindow::getSettings();
13736