File indexing completed on 2024-03-24 15:14:46

0001 /*************************************************************************************
0002  *  Copyright (C) 2010-2012 by Percy Camilo T. Aucahuasi <percy.camilo.ta@gmail.com> *
0003  *                                                                                   *
0004  *  This program is free software; you can redistribute it and/or                    *
0005  *  modify it under the terms of the GNU General Public License                      *
0006  *  as published by the Free Software Foundation; either version 2                   *
0007  *  of the License, or (at your option) any later version.                           *
0008  *                                                                                   *
0009  *  This program is distributed in the hope that it will be useful,                  *
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
0012  *  GNU General Public License for more details.                                     *
0013  *                                                                                   *
0014  *  You should have received a copy of the GNU General Public License                *
0015  *  along with this program; if not, write to the Free Software                      *
0016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
0017  *************************************************************************************/
0018 
0019 #include "mainwindow.h"
0020 
0021 //Analitza includes
0022 #include <analitza/expression.h>
0023 #include <analitzagui/plotsview2d.h>
0024 #include <analitzagui/plotsview3d_es.h>
0025 #include <analitzaplot/plotsdictionarymodel.h>
0026 #include <analitzaplot/planecurve.h>
0027 #include <analitzaplot/functiongraph.h>
0028 #include <analitzaplot/plotter3d_es.h>
0029 #include <analitzaplot/plotsmodel.h>
0030 #include <analitzaplot/plotsfactory.h>
0031 
0032 //Qt includes
0033 #include <QBuffer>
0034 #include <QDockWidget>
0035 #include <QLayout>
0036 #include <QLineEdit>
0037 #include <QPushButton>
0038 #include <QToolButton>
0039 #include <QDebug>
0040 #include <QFileDialog>
0041 #include <QClipboard>
0042 #include <QSettings>
0043 #include <QJsonDocument>
0044 #include <QApplication>
0045 
0046 //KDE includes
0047 #include <KLocalizedString>
0048 #include <KStandardDirs>
0049 #include <KActionCollection>
0050 #include <KStandardAction>
0051 #include <KStatusBar>
0052 #include <KMessageBox>
0053 #include <KIO/NetAccess>
0054 #include <KTemporaryFile>
0055 #include <KToolBar>
0056 #include <KMenuBar>
0057 #include <KConfigGroup>
0058 #include <KIO/CommandLauncherJob>
0059 #include <KIO/ApplicationLauncherJob>
0060 
0061 //local includes
0062 #include "spaceitem.h"
0063 #include "spacesmodel.h"
0064 #include "dashboard.h"
0065 #include "plotseditor.h"
0066 #include "datastore.h"
0067 #include "plotsbuilder.h"
0068 #include "spaceinformation.h"
0069 #include "spaceoptions.h"
0070 #include "filter.h"
0071 #include "dictionarycollection.h"
0072 
0073 using namespace Analitza;
0074 
0075 MainWindow::MainWindow(QWidget *parent)
0076     : KXmlGuiWindow(parent)
0077 {
0078     m_document = new DataStore(this);
0079 
0080     m_dashboard = new Dashboard(this);
0081     m_dashboard->setDocument(m_document);
0082 
0083     //From Main Dashboard to the activated space UI
0084     connect(m_dashboard, SIGNAL(spaceActivated(int)), SLOT(activateSpace(int)));
0085 
0086     connect(m_dashboard, SIGNAL(spaceActivated(int)), m_document , SIGNAL(spaceActivated(int)));
0087 
0088     setupDocks();
0089     setupActions();
0090     setupGUI(Keys | StatusBar | Save | Create, "khipu.rc");
0091 
0092     m_filter = new Filter(this);
0093     m_filter->setFilterDashboard(m_dashboard);
0094 
0095     connect(m_filter, SIGNAL(filterByText(QString)), m_dashboard, SLOT(filterByText(QString)));
0096     connect(m_dashboard, SIGNAL(plotRequested(QModelIndex)), this, SLOT(createPlot(QModelIndex)));
0097     connect(m_dashboard, SIGNAL(showFilter(bool)), m_filter, SLOT(setFilterVisible(bool)));
0098     connect(m_dashboard, SIGNAL(restoreDictionaryData(Analitza::Dimension)), m_dictionaryDock, SLOT(setSpaceDimension(Analitza::Dimension)));
0099 
0100     //Main tool bar for Khipu
0101     toolBar("mainToolBar")->addWidget(m_filter);
0102     setCentralWidget(m_dashboard);
0103     activateDashboardUi();
0104 
0105     //Used to update the recent file list
0106     updateRecentFileList();
0107 }
0108 
0109 void MainWindow::closeEvent(QCloseEvent * event)
0110 {
0111     // Do not want to close then just ignore the event
0112     if (!closeClicked())
0113         event->ignore();
0114 }
0115 
0116 MainWindow::~MainWindow()
0117 {
0118 }
0119 
0120 QAction* MainWindow::createAction(const char* name, const QString& text, const QString& iconName, const QKeySequence& shortcut, const QObject* recvr, const char* slot, bool isCheckable, bool checked)
0121 {
0122     auto act = new QAction(this);
0123     act->setText(text);
0124     act->setIcon(QIcon::fromTheme(iconName));
0125     act->setShortcut(shortcut);
0126     act->setCheckable(isCheckable);
0127 
0128     if (isCheckable)
0129     {
0130         act->setChecked(checked);
0131         QObject::connect(act, SIGNAL(toggled(bool)), recvr, slot);
0132     } else
0133         QObject::connect(act, SIGNAL(triggered()), recvr, slot);
0134 
0135     actionCollection()->addAction(name, act);
0136     return act;
0137 }
0138 
0139 void MainWindow::setupDocks()
0140 {
0141     PlotsBuilder *plotsBuilder = new PlotsBuilder(this);
0142     m_plotsBuilderDock = new QDockWidget(i18n("&Shortcuts"), this);
0143     m_plotsBuilderDock->setWidget(plotsBuilder); // plotsbuilder debe ser miembro
0144     m_plotsBuilderDock->setObjectName("dsfs");
0145     m_plotsBuilderDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
0146     m_plotsBuilderDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
0147     m_plotsBuilderDock->hide();
0148 
0149     //Connecting the buttons to create a specific plot
0150     plotsBuilder->mapConnection(PlotsBuilder::CartesianGraphCurve, this, SLOT(buildCartesianGraphCurve()));
0151     plotsBuilder->mapConnection(PlotsBuilder::CartesianImplicitCurve, this, SLOT(buildCartesianImplicitCurve()));
0152     plotsBuilder->mapConnection(PlotsBuilder::CartesianParametricCurve2D, this, SLOT(buildCartesianParametricCurve2D()));
0153     plotsBuilder->mapConnection(PlotsBuilder::PolarGraphCurve, this, SLOT(buildPolarGraphCurve()));
0154     plotsBuilder->mapConnection(PlotsBuilder::CartesianParametricCurve3D, this, SLOT(buildCartesianParametricCurve3D()));
0155     plotsBuilder->mapConnection(PlotsBuilder::CartesianGraphSurface, this, SLOT(buildCartesianGraphSurface()));
0156     plotsBuilder->mapConnection(PlotsBuilder::CartesianImplicitSurface, this, SLOT(buildCartesianImplicitSurface()));
0157     plotsBuilder->mapConnection(PlotsBuilder::CartesianParametricSurface, this, SLOT(buildCartesianParametricSurface()));
0158     plotsBuilder->mapConnection(PlotsBuilder::CylindricalGraphSurface, this, SLOT(buildCylindricalGraphSurface()));
0159     plotsBuilder->mapConnection(PlotsBuilder::SphericalGraphSurface, this, SLOT(buildSphericalGraphSurface()));
0160 
0161     //Plot-Editing dock
0162     m_spacePlotsDock = new PlotsEditor(this);
0163     m_spacePlotsDock->setDocument(m_document);
0164     m_spacePlotsDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
0165     m_spacePlotsDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
0166 
0167     connect(m_spacePlotsDock, SIGNAL(goHome()), SLOT(goHome()));
0168     connect(m_spacePlotsDock, SIGNAL(sendStatus(QString, int)), statusBar(), SLOT(showMessage(QString, int)));
0169     connect(m_spacePlotsDock, SIGNAL(updateGridcolor(QColor)), m_dashboard, SLOT(setGridColor(QColor)));
0170     connect(m_dashboard, SIGNAL(spaceActivated(int)), m_spacePlotsDock, SLOT(setCurrentSpace(int)));
0171     connect(m_spacePlotsDock, SIGNAL(mapDataChanged()), this, SLOT(autoSaveFile()));
0172     connect(m_document, SIGNAL(mapDataChanged()), this, SLOT(autoSaveFile()));
0173 
0174     //Space information dock
0175     m_spaceInfoDock = new SpaceInformation(this);
0176     m_spaceOptionsDock = new SpaceOptions(this);
0177 
0178     //Plot-Dictionary Dock
0179     m_dictionaryDock = new DictionaryCollection(this);
0180     m_dictionaryDock->setDashboardWidget(m_dashboard);
0181     m_dictionaryDock->setDocument(m_document);
0182     m_dictionaryDock->setDictionaryDataMap();
0183     m_dictionaryDock->setDefaultDictionaries();
0184 
0185     connect(this, SIGNAL(Spaceinserted(Analitza::Dimension)), m_dictionaryDock, SLOT(setSpaceDimension(Analitza::Dimension)));
0186     connect(m_dictionaryDock, SIGNAL(mapDataChanged()), this, SLOT(autoSaveFile()));
0187     connect(m_document, SIGNAL(gridStyleChanged(int)), m_spaceOptionsDock, SLOT(setGridStyleIndex(int)));
0188 
0189     //Signal/slots for 2d Space
0190     connect(m_spaceOptionsDock, SIGNAL(updateGridStyle(int)), m_dashboard, SLOT(setGridStyle(int)));
0191     connect(m_spaceOptionsDock, SIGNAL(updateGridColor(QColor)), m_dashboard, SLOT(setPlotsViewGridColor(QColor)));
0192     connect(m_spaceOptionsDock, SIGNAL(setXAxisLabel(QString)), m_dashboard->view2d(), SLOT(setXAxisLabel(QString)));
0193     connect(m_spaceOptionsDock, SIGNAL(setYAxisLabel(QString)), m_dashboard->view2d(), SLOT(setYAxisLabel(QString)));
0194     connect(m_spaceOptionsDock, SIGNAL(ticksFormatChanged(Analitza::TicksFormat)), m_dashboard->view2d(), SLOT(setTicksFormat(Analitza::TicksFormat)));
0195     connect(m_spaceOptionsDock, SIGNAL(ticksShown(QFlags<Qt::Orientation>)), m_dashboard->view2d(), SLOT(setTicksShown(QFlags<Qt::Orientation>)));
0196     connect(m_spaceOptionsDock, SIGNAL(axesShown(QFlags<Qt::Orientation>)), m_dashboard->view2d(), SLOT(setAxesShown(QFlags<Qt::Orientation>)));
0197 
0198     //Signal/slots for 3d Space
0199    // connect(m_spaceOptionsDock, SIGNAL(axisIsDrawn(bool)), m_dashboard->view3d(), SLOT(setAxisIsDrawn(bool)));
0200    // connect(m_spaceOptionsDock, SIGNAL(gridIsDrawn(bool)), m_dashboard->view3d(), SLOT(setGridIsDrawn(bool)));
0201    // connect(m_spaceOptionsDock, SIGNAL(sceneResized(int)), m_dashboard->view3d(), SLOT(resizeScene(int)));
0202 
0203     addDockWidget(Qt::LeftDockWidgetArea, m_plotsBuilderDock);
0204     addDockWidget(Qt::LeftDockWidgetArea, m_spacePlotsDock);
0205     addDockWidget(Qt::LeftDockWidgetArea, m_spaceOptionsDock);
0206     addDockWidget(Qt::LeftDockWidgetArea, m_spaceInfoDock);
0207     addDockWidget(Qt::LeftDockWidgetArea, m_dictionaryDock);
0208 
0209     tabifyDockWidget(m_plotsBuilderDock, m_spacePlotsDock);
0210     tabifyDockWidget(m_spacePlotsDock, m_spaceOptionsDock);
0211     tabifyDockWidget(m_spaceOptionsDock, m_spaceInfoDock);
0212     tabifyDockWidget(m_spaceInfoDock, m_dictionaryDock);
0213 }
0214 
0215 void MainWindow::setupActions()
0216 {
0217     //file
0218     KStandardAction::openNew(this, SLOT(newFile()), actionCollection());
0219     KStandardAction::open(this, SLOT(openFileClicked()), actionCollection());
0220     m_openrecent=KStandardAction::openRecent(this, SLOT(openRecentClicked(const QUrl& )), actionCollection());
0221     connect(m_openrecent, SIGNAL(recentListCleared()), this, SLOT(clearRecentFileList()));
0222 
0223     KStandardAction::save(this, SLOT(saveClicked()), actionCollection());
0224     KStandardAction::saveAs(this, SLOT(saveAsClicked()), actionCollection());
0225     KStandardAction::quit(this, SLOT(close()), actionCollection());
0226     createAction("save_plotImage", i18n("&Save Plot as PNG"), QString(), Qt::CTRL + Qt::Key_P, this, SLOT(savePlot()));
0227 
0228     //edit - dashboard
0229     createAction("add_space2d", i18n("Add Space &2D"), "add-space2d", Qt::CTRL + Qt::Key_2, this, SLOT(addSpace2D()));
0230     createAction("add_space3d", i18n("Add Space &3D"), "add-space3d", Qt::CTRL + Qt::Key_3, this, SLOT(addSpace3D()));
0231 
0232     //view - dashboard
0233     m_plotsBuilderDock->toggleViewAction()->setIcon(QIcon::fromTheme("formula"));
0234     m_plotsBuilderDock->toggleViewAction()->setShortcut(Qt::Key_S);
0235     m_plotsBuilderDock->toggleViewAction()->setToolTip(i18n("Create a plot in a new space"));
0236     actionCollection()->addAction("show_plotsbuilder", m_plotsBuilderDock->toggleViewAction());
0237 
0238     createAction("show_plotsdictionary", i18n("Plot &Dictionaries"), "functionhelp", Qt::CTRL + Qt::Key_D, this,
0239                  SLOT(setVisibleDictionary()));
0240 
0241     //view - space
0242 //     createAction("show_plots_editor", i18n("S&how Space Plots"), "address-book-new", Qt::CTRL + Qt::Key_W, this, SLOT(fooSlot()), true);
0243     m_spacePlotsDock->toggleViewAction()->setIcon(QIcon::fromTheme("editplots"));
0244     m_spacePlotsDock->toggleViewAction()->setShortcut(Qt::CTRL + Qt::Key_A);
0245     actionCollection()->addAction("show_plots_editor", m_spacePlotsDock->toggleViewAction());
0246 
0247 //     createAction("show_space_info", i18n("&Show Space Information"), "document-properties", Qt::CTRL + Qt::Key_W, this, SLOT(fooSlot()), true);
0248     m_spaceInfoDock->toggleViewAction()->setIcon(QIcon::fromTheme("dialog-information"));
0249     m_spaceInfoDock->toggleViewAction()->setShortcut(Qt::CTRL + Qt::Key_I);
0250     actionCollection()->addAction("show_space_info", m_spaceInfoDock->toggleViewAction());
0251 
0252 //     createAction("show_plotter_options", i18n("&Show Space Options"), "configure", Qt::CTRL + Qt::Key_W, this, SLOT(fooSlot()), true);
0253     m_spaceOptionsDock->toggleViewAction()->setIcon(QIcon::fromTheme("diagram-options"));
0254     m_spaceOptionsDock->toggleViewAction()->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_O);
0255     actionCollection()->addAction("show_plotter_options", m_spaceOptionsDock->toggleViewAction());
0256 
0257     m_dictionaryDock->toggleViewAction()->setIcon(QIcon::fromTheme("list-add"));
0258     m_dictionaryDock->toggleViewAction()->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_D);
0259     actionCollection()->addAction("show_dictionary_collection", m_dictionaryDock->toggleViewAction());
0260 
0261     //go
0262     QAction *firstPageAct = KStandardAction::firstPage(this, SLOT(firstPageActClicked()), actionCollection());
0263     firstPageAct->setText(i18n("&Go First Space"));
0264     firstPageAct->setIcon(QIcon::fromTheme("go-first-view"));
0265     firstPageAct->setEnabled(true);
0266 
0267     m_priorAct = KStandardAction::prior(this, SLOT(priorActClicked()), actionCollection());
0268     m_priorAct->setText(i18n("&Go Previous Space"));
0269     m_priorAct->setIcon(QIcon::fromTheme("go-previous-view"));
0270     m_priorAct->setEnabled(true);
0271 
0272     m_nextAct = KStandardAction::next(this, SLOT(nextActClicked()), actionCollection());
0273     m_nextAct->setText(i18n("&Go Next Space"));
0274     m_nextAct->setIcon(QIcon::fromTheme("go-next-view"));
0275     m_nextAct->setEnabled(true);
0276 
0277     QAction *lastPageAct = KStandardAction::lastPage(this, SLOT(lastPageActClicked()), actionCollection());
0278     lastPageAct->setText(i18n("&Go Last Space"));
0279     lastPageAct->setIcon(QIcon::fromTheme("go-last-view"));
0280     lastPageAct->setEnabled(true);
0281 
0282     KStandardAction::home(this, SLOT(goHome()), actionCollection());
0283     //tools dashboard
0284     createAction("delete_currentspace", i18n("&Remove Current Space"), "list-remove", Qt::CTRL + Qt::Key_W, this, SLOT(removeCurrentSpace()))->setVisible(false);;
0285     //tools space
0286     createAction("copy_snapshot", i18n("&Take Snapshot"), "take-snapshot", Qt::CTRL + Qt::SHIFT + Qt::Key_C, this, SLOT(copySnapshot()));
0287     m_getdictionaryAct=createAction("get_dictionary", i18n("&Get Plot-Dictionary files"), "get-hot-new-stuff", Qt::CTRL + Qt::SHIFT + Qt::Key_G, m_dashboard, SLOT(getDictionaryClicked()));
0288     m_importdictionaryAct=createAction("import_dictionary", i18n("&Import Plot-Dictionary file"), "document-import", Qt::CTRL + Qt::SHIFT + Qt::Key_I, m_dashboard, SLOT(importDictionaryClicked()));
0289 
0290     //     createAction("export_snapshot", i18n("&Export Space Snapshot"), "view-preview", Qt::CTRL + Qt::Key_W, this, SLOT(fooSlot()));
0291     //settings
0292     KStandardAction::showMenubar(this, SLOT(setMenuBarVisibility(bool)), actionCollection());
0293     KStandardAction::fullScreen(this, SLOT(fullScreenView(bool)), this , actionCollection());
0294 }
0295 
0296 //Saving a space title
0297 void MainWindow::setCurrentSpaceTitle(const QString& str)
0298 {
0299     m_document->spacesModel()->space(m_document->currentSpace())->setName(str);
0300 }
0301 
0302 //Saving a space description
0303 void MainWindow::setCurrentSpaceDesc(const QString& desc)
0304 {
0305     m_document->spacesModel()->space(m_document->currentSpace())->setDescription(desc);
0306 }
0307 
0308 void MainWindow::fullScreenView (bool isFull)
0309 {
0310     if (isFull) {
0311         showFullScreen();
0312         statusBar()->hide();
0313         m_spaceOptionsDock->hide();
0314         m_spaceInfoDock->hide();
0315         m_spacePlotsDock->hide();
0316         m_plotsBuilderDock->hide();
0317         m_dictionaryDock->hide();
0318     } else {
0319         showNormal();
0320         statusBar()->show();
0321     }
0322     toolBar("mainToolBar")->setVisible(!isFull);
0323 }
0324 
0325 void MainWindow::firstPageActClicked()
0326 {
0327     m_getdictionaryAct->setVisible(false);
0328     m_importdictionaryAct->setVisible(false);
0329 
0330     int currentSpaceRow=m_document->currentSpace();
0331 
0332     if (m_document->spacesModel()->rowCount()==0) { //For empty space model
0333         statusBar()->showMessage(i18n("There is not any space available to show!"), MessageDuration);
0334     } else if (currentSpaceRow==0) { //Already on the first space
0335         QModelIndex firstInd=m_document->spacesModel()->index(0);
0336         m_dashboard->setCurrentSpace(firstInd);
0337         statusBar()->showMessage(i18n("Currently you are on the first space!"), MessageDuration);
0338     } else if (m_document->spacesModel()->rowCount()>0) {
0339         QModelIndex firstInd=m_document->spacesModel()->index(0);
0340         m_dashboard->setCurrentSpace(firstInd);
0341     }
0342 }
0343 
0344 void MainWindow::priorActClicked()
0345 {
0346     int currentSpaceRow=m_document->currentSpace();
0347     if (currentSpaceRow==0) {
0348         statusBar()->showMessage(i18n("You are already on the first space!"), MessageDuration);
0349     } else if (currentSpaceRow>0) {
0350         QModelIndex prevInd=m_document->spacesModel()->index(currentSpaceRow-1);
0351         m_dashboard->setCurrentSpace(prevInd);
0352     }
0353 }
0354 
0355 void MainWindow::nextActClicked()
0356 {
0357     int currentSpaceRow=m_document->currentSpace();
0358     int size=m_document->spacesModel()->rowCount();
0359     if (currentSpaceRow==size-1) {
0360         statusBar()->showMessage(i18n("You are already on the last space!"), MessageDuration);
0361     } else if (currentSpaceRow<size-1) {
0362         QModelIndex nextInd=m_document->spacesModel()->index(currentSpaceRow+1);
0363         m_dashboard->setCurrentSpace(nextInd);
0364     }
0365 }
0366 
0367 void MainWindow::lastPageActClicked()
0368 {
0369     m_getdictionaryAct->setVisible(false);
0370     m_importdictionaryAct->setVisible(false);
0371 
0372     int currentSpaceRow=m_document->currentSpace();
0373     int size=m_document->spacesModel()->rowCount();
0374 
0375     if (m_document->spacesModel()->rowCount()==0) { //For empty space model
0376         statusBar()->showMessage(i18n("There is not any space available to show!"), MessageDuration);
0377     } else if (currentSpaceRow==size-1) { //Already on the last space
0378         QModelIndex lastInd=m_document->spacesModel()->index(size-1);
0379         m_dashboard->setCurrentSpace(lastInd);
0380         statusBar()->showMessage(i18n("Currently you are on the last space!"), MessageDuration);
0381     } else if (m_document->spacesModel()->rowCount() >0) {
0382         int size=m_document->spacesModel()->rowCount();
0383         QModelIndex lastInd=m_document->spacesModel()->index(size-1);
0384         m_dashboard->setCurrentSpace(lastInd);
0385     }
0386 }
0387 
0388 void MainWindow::clearRecentFileList()
0389 {
0390     KConfig config;
0391     KConfigGroup recentFiles(&config, "file_Recent");
0392     recentFiles.deleteEntry("recentFileList");
0393 }
0394 
0395 void MainWindow::setMenuBarVisibility(bool isShow)
0396 {
0397     if (isShow) {
0398         menuBar()->show();
0399     } else {
0400         KMessageBox::information(this, i18n("Press Ctrl + M to make menubar visible again"), i18n("Menubar Visibility"));
0401         menuBar()->hide();
0402     }
0403 }
0404 
0405 void MainWindow::autoSaveFile()
0406 {
0407     updateThumbnail();
0408 
0409     //no filename available, need to save it as temporary , filename used here is ".khipu.autosave"
0410     if (m_fileLocation.isEmpty()) {
0411         saveFile(getDefaultAutoSavepath());
0412     } else {
0413         QString path=QFileInfo(m_fileLocation).dir().path().append("/.").append(QFileInfo(m_fileLocation).baseName().append(".khipu.autosave"));
0414         saveFile(QUrl::fromLocalFile(path));
0415     }
0416 }
0417 
0418 //Update thumbnail whenever the plots are changed.
0419 void MainWindow::updateThumbnail()
0420 {
0421 
0422     if (m_document->spacesModel()->rowCount()==0)
0423         return;
0424 
0425     SpaceItem *space = m_document->spacesModel()->space(m_document->currentSpace());
0426 
0427     if (space==nullptr)
0428         return;
0429 
0430     if (space->dimension()!=Analitza::Dim2D && space->dimension()!=Analitza::Dim3D)
0431         return;
0432 
0433     const QPixmap thumbnail = m_dashboard->thumbnail(space->dimension()).scaled(QSize(PreviewWidth, PreviewHeight), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
0434     space->setThumbnail(thumbnail);
0435 }
0436 
0437 void MainWindow::checkforAutoSavedFile()
0438 {
0439     openFile(getDefaultAutoSavepath());
0440 }
0441 
0442 void MainWindow::newFile()
0443 {
0444     // if there are not any plots added (i.e. file is completely clean)
0445     if (m_document->plotsModel()->rowCount()==0) {
0446         QMessageBox::information(this, i18n("No need to create New Window"), i18n("There are not any plots available. So, you do not need to create a new Plot Window"));
0447         return;
0448     }
0449 
0450     // creates a new proccess.
0451     // The commandline arguments is used to create a completely new instance of Khipu(i.e. it does not reload the autosaved file)
0452     auto *job = new KIO::CommandLauncherJob(QStringLiteral("khipu"), {QStringLiteral("--ignoreautosavedfile")});
0453     job->setDesktopName(QStringLiteral("org.kde.khipu"));
0454     job->start();
0455 }
0456 
0457 void MainWindow::openRecentClicked(const QUrl&  name)
0458 {
0459     // no plots are available , can open in the same proccess.
0460     if (m_document->plotsModel()->rowCount()==0) {
0461         openFile(name);
0462         return;
0463     }
0464     auto *job = new KIO::ApplicationLauncherJob(KService::serviceByDesktopName(QStringLiteral("org.kde.khipu")));
0465     job->setUrls({name});
0466     job->start();
0467 }
0468 
0469 void MainWindow::setCurrentFile(const QString &fileName)
0470 {
0471     if (fileName.isEmpty())
0472         return;
0473 
0474     KConfig config;
0475     KConfigGroup recentFiles(&config, "file_Recent");
0476 
0477     QStringList files =recentFiles.readPathEntry("recentFileList", QStringList());
0478     files.removeAll(fileName);
0479     files.prepend(fileName);
0480 
0481     while (files.size() > MaxRecentFiles)
0482         files.removeLast();
0483 
0484     recentFiles.deleteEntry("recentFileList");
0485     recentFiles.writePathEntry("recentFileList", files);
0486     recentFiles.sync();
0487     updateRecentFileList();
0488 }
0489 
0490 void MainWindow::updateRecentFileList()
0491 {
0492     KConfig config;
0493     KConfigGroup recentFiles(&config, "file_Recent");
0494     QStringList files =  recentFiles.readPathEntry("recentFileList", QStringList());
0495     int numRecentFiles = qMin(files.size(), (int)MaxRecentFiles);
0496 
0497     // Traversing in reverse manner will lead to the correct Recently opened file-list
0498     for (int i = numRecentFiles-1; i >=0 ; i--) {
0499         QString text=files[i];
0500         m_openrecent->addUrl(QUrl::fromLocalFile(text), QFileInfo(text).fileName());
0501     }
0502 }
0503 
0504 bool MainWindow::openFileClicked()
0505 {
0506     const auto url = QFileDialog::getOpenFileUrl(this, i18n("Open"), {},
0507                      i18n("Khipu Files (*.khipu);;All Files (*)"));
0508 
0509     if (url.path().isEmpty() || m_currentFileUrl == url)
0510         return false;
0511 
0512     openFile(url);
0513 
0514     return true;
0515 }
0516 
0517 bool MainWindow::openFile(const QUrl &url)
0518 {
0519     if (url.path().isEmpty())
0520         return false;
0521 
0522     QFile file;
0523 
0524     if (!url.isLocalFile())
0525     {
0526         if (!KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, this))
0527         {
0528             KMessageBox::error(this, i18n("The file does not exist."));
0529             return false;
0530         }
0531 
0532         QString tmpfile;
0533 
0534         if (!KIO::NetAccess::download(url, tmpfile, this))
0535         {
0536             KMessageBox::error(this, i18n("An error appeared when opening this file (%1)", KIO::NetAccess::lastErrorString()));
0537             return false;
0538         }
0539         file.setFileName(tmpfile);
0540     }
0541     else
0542         file.setFileName(url.toLocalFile());
0543 
0544     // for the default autosaved file (.khipu.autosave)
0545     if (url == getDefaultAutoSavepath())
0546     {
0547         // ask for reloading the autosave file
0548         if (!file.exists())
0549             return false;
0550         int answer=KMessageBox::questionYesNo(this, i18n("Do you want to recover the file you have not saved last time?"), i18n("Autosaved .khipu file"));
0551 
0552         if (answer!=KMessageBox::Yes)
0553         {
0554             QFile file(url.toLocalFile());
0555             if (file.remove())
0556                 return false;
0557         }
0558     } 
0559     else 
0560     {
0561         QString path=url.toLocalFile();
0562         
0563         // not , current autosave !
0564         if (!path.contains(".khipu.autosave"))
0565             setCurrentFile(path);
0566         
0567         m_fileLocation = path; // this allows user to save the other work in the file which he/she has just opened.
0568         
0569         changeTitleBar(path);
0570 
0571         //check for available autosave file
0572         QString currentautosavepath=getCurrentAutoSavepath(path);
0573         
0574         if (QFile::exists(currentautosavepath)) 
0575         {
0576 
0577             // ask for reloading the autosave file
0578             int answer=KMessageBox::questionYesNo(this, i18n("There are some unsaved changes in the file %1. Do you want to recover them?", QFileInfo(path).baseName()), i18n("Autosaved .khipu file"));
0579             
0580             if (answer==KMessageBox::Yes) 
0581             {
0582                 // user wants to open the autosave file.
0583                 file.setFileName(currentautosavepath);
0584             }
0585         }
0586     }
0587     if (!file.open(QFile::ReadOnly)) 
0588     {
0589         KMessageBox::error(this, i18n("Error while reading file, maybe path is not found."), i18n("Error while reading"));
0590         
0591         if (file.fileName() != getDefaultAutoSavepath().toLocalFile())
0592             KMessageBox::error(this, i18n("%1 could not be opened", file.fileName()));
0593        
0594         return false;
0595     }
0596 
0597     m_parsedSpaceDetails = QJsonDocument::fromJson(file.readAll()).toVariant().toList();
0598     file.close();
0599 
0600     if (!url.isLocalFile())
0601         KIO::NetAccess::removeTempFile( file.fileName() );
0602 
0603     // if a wrong file is hit
0604     if (m_parsedSpaceDetails.isEmpty())
0605     { 
0606         KMessageBox::error(this, i18n("Problem in parsing the contents of the file, maybe a wrong khipu file."), i18n("Error while reading"));
0607         
0608         return false;
0609     }
0610 
0611     m_dashboard->m_openclicked = true;
0612 
0613     //NOTE we need to remove all current data before load new data from file
0614     bool reloadviews = false;
0615     
0616     if (m_document->spacesModel()->rowCount() > 0)
0617     {
0618         m_document->clearAllData();
0619         reloadviews = true;
0620     }
0621     
0622     foreach (QVariant record, m_parsedSpaceDetails) 
0623     {
0624         QVariantMap map = record.toMap();
0625 
0626         QString spacename=map.value("name").toString();
0627         QString spaceDescription=map.value("description").toString();        
0628         QByteArray image= map.value("image").toByteArray();
0629 
0630         Analitza::Dimension dim=static_cast<Analitza::Dimension> (map.value("dimension").toInt());
0631         QPixmap thumbnail= toPixmap(image);
0632 
0633         m_document->spacesModel()->addSpace(dim, spacename, spaceDescription, thumbnail);
0634     }
0635     
0636     //NOTE we need to realod views after load a new file data (see datastore::clearalldata)
0637     if (reloadviews)
0638     {
0639         m_dashboard->setDocument(m_document);
0640         m_spacePlotsDock->setDocument(m_document);
0641         m_dictionaryDock->setDocument(m_document);
0642     }
0643     
0644     m_dashboard->goHome();
0645     activateDashboardUi();
0646     
0647     m_currentFileUrl = url;
0648     
0649     return true;
0650 }
0651 
0652 QPixmap MainWindow::toPixmap(const QByteArray &bytearray)
0653 {
0654     QByteArray imageArray(QByteArray::fromBase64(bytearray));
0655     QBuffer imagebuffer(&imageArray);
0656     imagebuffer.open(QIODevice::ReadOnly);
0657     QImage img;
0658     img.loadFromData(imagebuffer.data(), "PNG");
0659     return QPixmap::fromImage(img);
0660 }
0661 
0662 void MainWindow::saveClicked()
0663 {
0664     // Intially when the data is not saved. We would not have the actual file path.
0665     if (m_fileLocation.isEmpty())
0666     {
0667         QUrl url = QFileDialog::getSaveFileUrl(this, i18n("Save As"), {}, i18n("Khipu Files (*.khipu);;All Files (*)") );
0668         if (url.isEmpty())
0669             return;
0670 
0671         //overwriting warning
0672         if (QFileInfo::exists(url.toLocalFile()))
0673         {
0674             int answer=KMessageBox::questionYesNo(this,
0675             i18n("The file which you want to save, already exists. Do you want to overwrite this file?"),
0676             i18n("Warning: File already exists"));
0677                 if (answer==KMessageBox::No)
0678                     return;
0679         }
0680             m_fileLocation =url.toLocalFile();
0681     }
0682     saveFile(QUrl::fromLocalFile(m_fileLocation));
0683 }
0684 
0685 bool MainWindow::closeClicked()
0686 {
0687     QFile autosaveFile(getDefaultAutoSavepath().toLocalFile());
0688 
0689     const QFileInfo fi(m_fileLocation);
0690     QString path = fi.dir().path().append("/.").append(fi.baseName().append(".khipu.autosave"));
0691     QFile currentautosaveFile(path);
0692 
0693     if (autosaveFile.exists() || currentautosaveFile.exists()) {
0694         int answer=KMessageBox::questionYesNoCancel(this,
0695                    i18n("The current file contains some unsaved work. Do you want to save it?"),
0696                    i18n("Warning: Unsaved changes"));
0697         if (answer==KMessageBox::Yes) {
0698             saveClicked();
0699             return true;
0700         } else if (answer==KMessageBox::Cancel) {
0701             return false;
0702         } else if (answer==KMessageBox::No) {
0703             // if user selects No , then he/she can restore the work using autosaving feature. But this can be removed !
0704             return true;
0705         }
0706     }
0707     return true; // just close the application.
0708 }
0709 
0710 bool MainWindow::saveAsClicked()
0711 {
0712     const auto path = QFileDialog::getSaveFileUrl( this, i18n("Save As"), {}, i18n("Khipu Files (*.khipu);;All Files (*)"));
0713  
0714     if (path.isEmpty())
0715         return false;
0716     
0717     if (saveFile(path))
0718     {
0719         m_fileLocation = path.toLocalFile();
0720         
0721         return true;
0722     }
0723     
0724     return false;
0725 }
0726 
0727 bool MainWindow::saveFile(const QUrl &url)
0728 {
0729     QMap<SpaceItem*, Analitza::PlotItem*> map=m_document->currentDataMap();
0730 
0731     // just starting, no plots and no spaces are available, so no need to save
0732     if (map.empty() && m_document->spacesModel()->items().isEmpty())
0733     {
0734         // no plots are there. so, we dont need autosave file
0735         QFile tempautosaveFile(getDefaultAutoSavepath().toLocalFile());
0736         tempautosaveFile.remove();
0737 
0738         QString path=QFileInfo(m_fileLocation).dir().path().append("/.").append(QFileInfo(m_fileLocation).baseName().append(".khipu.autosave"));
0739         QFile currentautosaveFile(path);
0740         currentautosaveFile.remove();
0741         
0742         return false;
0743     }
0744 
0745     //NOTE We need to read all space items, not just only the mapped ones (see bug: 328252)
0746     QList<SpaceItem*> spaceList=m_document->spacesModel()->items();
0747 
0748     if (spaceList.empty()) 
0749     {
0750         KMessageBox::error(this, i18n("Error while reading file, file may be empty"), i18n("Error while reading"));
0751     
0752         return false;
0753     }
0754 
0755     QVariantList plotspace_list;
0756 
0757     foreach(SpaceItem* space, spaceList) {
0758         QString spaceName = space->name();
0759         QString spaceDescription = space->description();        
0760         QPixmap thumbnail = space->thumbnail();
0761         int dim = space->dimension();
0762 
0763         QVariantList subplot_list;
0764         subplot_list.clear();
0765 
0766         QVariantMap plotspace;
0767         plotspace.insert("name", spaceName);
0768         plotspace.insert("description", spaceDescription);
0769         plotspace.insert("dimension", dim);
0770         plotspace.insert("image", thumbnailtoByteArray(thumbnail));
0771 
0772         QList<Analitza::PlotItem*> plotList=map.values(space);
0773 
0774         foreach(Analitza::PlotItem* plotitem, plotList) {
0775             QString plotName = plotitem->name();
0776             QString plotExpression = plotitem->expression().toString();
0777             QColor plotcolor = plotitem->color();
0778 
0779             QVariantMap plot;
0780             plot.insert("name", plotName);
0781             plot.insert("expression", plotExpression);
0782             plot.insert("color", plotcolor);
0783 
0784             if (dim==2) {
0785                 Analitza::FunctionGraph* functiongraph = static_cast<Analitza::FunctionGraph*>(plotitem);
0786 
0787                 if (functiongraph->hasIntervals())
0788                 {
0789                     QString arg1min = functiongraph->interval(functiongraph->parameters().at(0), false).first.toString();
0790                     QString arg1max = functiongraph->interval(functiongraph->parameters().at(0), false).second.toString();
0791 
0792                     plot.insert("arg1min", arg1min);
0793                     plot.insert("arg1max", arg1max);
0794                 }
0795             }
0796 
0797             //writehere
0798             subplot_list << plot;
0799 
0800         }
0801 
0802         QByteArray subjson = QJsonDocument::fromVariant(subplot_list).toJson();
0803         plotspace.insert("plots", subjson);
0804         plotspace_list << plotspace;
0805     }
0806 
0807     QByteArray json = QJsonDocument::fromVariant(plotspace_list).toJson();
0808 
0809     if (!url.isLocalFile())
0810     {
0811         KTemporaryFile tmpfile;
0812        
0813         if (!tmpfile.open())
0814         {
0815             KMessageBox::error(this, i18n("Could not open %1 for writing", QUrl(tmpfile.fileName()).toLocalFile()), i18n("Error while writing"));
0816             
0817             return false;
0818         }
0819         
0820         QTextStream out(&tmpfile);
0821         out << json;
0822         out.flush();
0823         
0824         if (!KIO::NetAccess::upload(tmpfile.fileName(), url, this))
0825         {
0826             KMessageBox::error(this, i18n("Could not open %1 for writing %2", url.toDisplayString(), KIO::NetAccess::lastErrorString()), i18n("Error while writing"));
0827 
0828             return false;
0829         }
0830     }
0831     else
0832     {
0833         if (!url.isLocalFile())
0834         {
0835             KMessageBox::error(this, i18n("Error while saving file. Maybe path is not found"), i18n("Error while saving"));
0836         
0837             return false;
0838         }
0839 
0840         QFile file(url.toLocalFile());
0841 
0842         // saved action clicked by the user , this is not the autosave case
0843         QString currentautosavepath = getCurrentAutoSavepath(m_fileLocation);
0844         
0845         if (url != getDefaultAutoSavepath() && url.toLocalFile()!=currentautosavepath)
0846         {
0847             if (!file.open(QFile::WriteOnly | QFile::Text)) 
0848                 return false;
0849 
0850             // remove the auto save file (can be improved later) -> better to use function (TODO)
0851             QFile tempautosaveFile(getDefaultAutoSavepath().toLocalFile());
0852             tempautosaveFile.remove();
0853             QFile currentautosaveFile(currentautosavepath);
0854             currentautosaveFile.remove();
0855 
0856             setCurrentFile(url.toLocalFile());
0857             statusBar()->showMessage(i18n("File %1 [%2] is saved successfully",
0858                                           QFileInfo(url.toLocalFile()).fileName(), url.toLocalFile()), MessageDuration);
0859             changeTitleBar(url.toLocalFile());
0860         }
0861         else // autosave case
0862         {
0863             if (!file.open(QFile::WriteOnly | QFile::Text)) 
0864                 return false;
0865         }
0866 
0867         QTextStream out(&file);
0868         out << json;
0869         file.close();
0870     }
0871     
0872     m_currentFileUrl = url;
0873     
0874     return true;
0875 }
0876 
0877 void MainWindow::changeTitleBar(const QString& path)
0878 {
0879     window()->setWindowTitle(QFileInfo(path).fileName().append(" - Khipu"));
0880 }
0881 
0882 QString MainWindow::getCurrentAutoSavepath(const QString &path)
0883 {
0884     if (!path.isEmpty())
0885         return QFileInfo(path).dir().path().append("/.").append(QFileInfo(path).baseName().append(".autosave"));
0886     
0887     return QString();
0888 }
0889 
0890 QUrl MainWindow::getDefaultAutoSavepath() const
0891 {
0892     return QUrl::fromLocalFile(QDir::homePath().append("/.khipu.autosave"));
0893 }
0894 
0895 void MainWindow::savePlot()
0896 {
0897     if (m_document->currentSpace()==-1)
0898         return;
0899     Dimension dim = m_document->spacesModel()->space(m_document->currentSpace())->dimension();
0900     m_dashboard->exportSpaceSnapshot(dim);
0901 }
0902 
0903 void MainWindow::activateSpace(int spaceidx)
0904 {
0905     activateSpaceUi();
0906 
0907     m_spacePlotsDock->reset(true);
0908 
0909     SpaceItem *space = m_document->spacesModel()->space(spaceidx);
0910     m_spaceInfoDock->setInformation(space->name(), space->description());
0911 
0912     m_spaceOptionsDock->setDimension(space->dimension());
0913 }
0914 
0915 void MainWindow::activateDashboardUi()
0916 {
0917     //menubar
0918     //edit
0919     action("add_space2d")->setVisible(true);
0920     action("add_space3d")->setVisible(true);
0921 
0922     if (m_document->spacesModel()->rowCount()>0)
0923         action("delete_currentspace")->setVisible(true);
0924 
0925     //view
0926     action("show_plotsbuilder")->setVisible(true);
0927     action("show_plotsdictionary")->setVisible(true);
0928     action("show_plots_editor")->setVisible(false);
0929     action("show_space_info")->setVisible(false);
0930     action("show_plotter_options")->setVisible(false);
0931     action("show_dictionary_collection")->setVisible(false);
0932 
0933     //go
0934     action("go_home")->setVisible(false);
0935     //tools
0936     action("copy_snapshot")->setVisible(false);
0937     action("save_plotImage")->setVisible(false);
0938 
0939     //docks
0940     // primero oculto los widgets sino el size de los que voy a ocultar interfieren y la mainwnd se muestra muy grande
0941     m_spacePlotsDock->hide();
0942     m_spaceInfoDock->hide();
0943     m_spaceOptionsDock->hide();
0944     m_plotsBuilderDock->hide();
0945     m_dictionaryDock->hide();
0946     m_priorAct->setVisible(false);
0947     m_nextAct->setVisible(false);
0948     //actions should be invisible
0949     m_getdictionaryAct->setVisible(false);
0950     m_importdictionaryAct->setVisible(false);
0951 }
0952 
0953 void MainWindow::activateSpaceUi()
0954 {
0955     m_dashboard->setCurrentIndex(1);
0956 
0957     //menu
0958     
0959     //tools
0960     m_filter->setFilterVisible(false);
0961     
0962     //edit
0963     action("add_space2d")->setVisible(false);
0964     action("add_space3d")->setVisible(false);
0965     action("delete_currentspace")->setVisible(false);
0966     //view
0967     action("show_plotsbuilder")->setVisible(false);
0968     action("show_plotsdictionary")->setVisible(false);
0969     action("show_plots_editor")->setVisible(true);
0970     action("show_space_info")->setVisible(true);
0971     action("show_plotter_options")->setVisible(true);
0972     action("show_dictionary_collection")->setVisible(true);
0973 
0974     //go
0975     action("go_home")->setVisible(true);
0976     //tools
0977     action("copy_snapshot")->setVisible(true);
0978     action("save_plotImage")->setVisible(true);
0979 
0980     //docks
0981     //lo mismo ... primero hides luego show
0982     m_plotsBuilderDock->hide();
0983     m_spacePlotsDock->show();
0984     m_spaceInfoDock->show();
0985     m_spaceOptionsDock->show();
0986     m_dictionaryDock->show();
0987     m_priorAct->setVisible(true);
0988     m_nextAct->setVisible(true);
0989 }
0990 
0991 void MainWindow::copySnapshot()
0992 {
0993     SpaceItem *space = m_document->spacesModel()->space(m_document->currentSpace());
0994     switch (space->dimension())
0995     {
0996     case Analitza::Dim2D:
0997         m_dashboard->copySpace2DSnapshotToClipboard();
0998         break;
0999     case Analitza::Dim3D:
1000         m_dashboard->copySpace3DSnapshotToClipboard();
1001         break;
1002     default:
1003         break;
1004     }
1005     statusBar()->showMessage(i18n("The diagram was copied to clipboard"), MessageDuration);
1006 }
1007 
1008 void MainWindow::setVisibleDictionary()
1009 {
1010 
1011     //menu
1012     //edit
1013     action("add_space2d")->setVisible(false);
1014     action("add_space3d")->setVisible(false);
1015     action("delete_currentspace")->setVisible(false);
1016     //view
1017     action("show_plotsbuilder")->setVisible(false);
1018     action("show_plots_editor")->setVisible(false);
1019     action("show_space_info")->setVisible(false);
1020     action("show_plotter_options")->setVisible(false);
1021     action("show_dictionary_collection")->setVisible(false);
1022     //go
1023     action("show_plotsdictionary")->setVisible(false);
1024     action("go_home")->setVisible(true);
1025 
1026     //tools
1027     action("copy_snapshot")->setVisible(false);
1028     action("save_plotImage")->setVisible(false);
1029 
1030     //docks on the dashboard
1031     m_plotsBuilderDock->hide();
1032     m_spacePlotsDock->hide();
1033     m_spaceInfoDock->hide();
1034     m_spaceOptionsDock->hide();
1035     m_dictionaryDock->hide();
1036     m_dashboard->showDictionary();
1037     m_priorAct->setVisible(false);
1038     m_nextAct->setVisible(false);
1039 
1040     //actions should be visible
1041     m_getdictionaryAct->setVisible(true);
1042     m_importdictionaryAct->setVisible(true);
1043     m_dashboard->activateDictionaryData();
1044 }
1045 
1046 void MainWindow::addSpace2D()
1047 {
1048     activateSpaceUi();
1049 
1050     m_dashboard->showPlotsView2D();
1051     int rows=m_document->spacesModel()->rowCount();
1052     m_document->spacesModel()->addSpace(Analitza::Dim2D, i18n("Untitled %1", rows+1));
1053 
1054     emit Spaceinserted(Dim2D);
1055 }
1056 
1057 void MainWindow::addSpace3D()
1058 {
1059     activateSpaceUi();
1060 
1061     m_dashboard->showPlotsView3D();
1062     int rows=m_document->spacesModel()->rowCount();
1063     m_document->spacesModel()->addSpace(Analitza::Dim3D, i18n("Untitled %1", rows+1));
1064 
1065     emit Spaceinserted(Dim3D);
1066 }
1067 
1068 void MainWindow::removeCurrentSpace()
1069 {
1070     m_document->removeCurrentSpace();
1071 
1072     if (m_document->spacesModel()->rowCount() == 0)
1073         action("delete_currentspace")->setVisible(false);
1074 }
1075 
1076 // Allows the user to go Home which will save the current space and take the user to the main view
1077 void MainWindow::goHome()
1078 {
1079     if (m_dashboard->currentIndex() != 0)
1080     {
1081         //Current Space from where go home is pressed
1082         SpaceItem *space = m_document->spacesModel()->space(m_document->currentSpace());
1083 
1084         space->stamp(); // marcamos la fecha y hora de ingreso al space
1085         space->setName(m_spaceInfoDock->title());
1086         space->setDescription(m_spaceInfoDock->description());
1087 
1088         // Thumbnail of the current space which is used to identify the space
1089         const QPixmap thumbnail = m_dashboard->thumbnail(space->dimension()).scaled(QSize(PreviewWidth, PreviewHeight), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1090         space->setThumbnail(thumbnail);
1091     }
1092     m_dashboard->goHome();
1093     activateDashboardUi();
1094 }
1095 
1096 QByteArray MainWindow::thumbnailtoByteArray(const QPixmap &thumbnail)
1097 {
1098     QImage image = thumbnail.toImage();
1099     QByteArray imageArray;
1100     QBuffer buffer(&imageArray);
1101     buffer.open(QIODevice::WriteOnly);
1102     image.save(&buffer, "PNG");
1103     QByteArray encodedImage=buffer.data().toBase64();
1104     return encodedImage;
1105 }
1106 
1107 void MainWindow::buildCartesianGraphCurve()
1108 {
1109     addSpace2D();
1110     m_spacePlotsDock->buildCartesianGraphCurve(true);
1111 }
1112 
1113 void MainWindow::buildCartesianImplicitCurve()
1114 {
1115     addSpace2D();
1116     m_spacePlotsDock->buildCartesianImplicitCurve(true);
1117 }
1118 
1119 void MainWindow::buildCartesianParametricCurve2D()
1120 {
1121     addSpace2D();
1122     m_spacePlotsDock->buildCartesianParametricCurve2D(true);
1123 }
1124 
1125 void MainWindow::buildPolarGraphCurve()
1126 {
1127     addSpace2D();
1128     m_spacePlotsDock->buildPolarGraphCurve(true);
1129 }
1130 
1131 void MainWindow::buildCartesianParametricCurve3D()
1132 {
1133     addSpace3D();
1134     m_spacePlotsDock->buildCartesianParametricCurve3D(true);
1135 }
1136 
1137 void MainWindow::buildCartesianGraphSurface()
1138 {
1139     addSpace3D();
1140     m_spacePlotsDock->buildCartesianGraphSurface(true);
1141 }
1142 
1143 void MainWindow::buildCartesianImplicitSurface()
1144 {
1145     addSpace3D();
1146     m_spacePlotsDock->buildCartesianImplicitSurface(true);
1147 }
1148 
1149 void MainWindow::buildCartesianParametricSurface()
1150 {
1151     addSpace3D();
1152     m_spacePlotsDock->buildCartesianParametricSurface(true);
1153 }
1154 
1155 void MainWindow::buildCylindricalGraphSurface()
1156 {
1157     addSpace3D();
1158     m_spacePlotsDock->buildCylindricalGraphSurface(true);
1159 }
1160 
1161 void MainWindow::buildSphericalGraphSurface()
1162 {
1163     addSpace3D();
1164     m_spacePlotsDock->buildSphericalGraphSurface(true);
1165 }
1166 
1167 void MainWindow::createPlot(const QModelIndex &ind)
1168 { 
1169     if (ind.row() < 0)
1170         return;
1171 
1172     //Parsing the data from the qjson file
1173     QVariantMap map = m_parsedSpaceDetails.at(ind.row()).toMap(); // corresponding space entry
1174 
1175     Analitza::Dimension dim=static_cast<Analitza::Dimension> (map.value("dimension").toInt());
1176     QVariantList plotList= QJsonDocument::fromJson(map.value("plots").toByteArray()).toVariant().toList();
1177 
1178     foreach(QVariant plot, plotList) {
1179 
1180         QVariantMap plotmap = plot.toMap();
1181         QString plotname=plotmap.value("name").toString();
1182         QString ploteqn=plotmap.value("expression").toString();
1183         QColor plotcolor=plotmap.value("color").toString();
1184 
1185         double arg1min=plotmap.value("arg1min").toDouble();
1186         double arg1max=plotmap.value("arg1max").toDouble();
1187 
1188         QStringList errors;
1189 
1190         PlotBuilder req = PlotsFactory::self()->requestPlot(Analitza::Expression(QString(ploteqn)), dim);
1191 
1192         if (req.canDraw()) 
1193         {
1194 
1195             FunctionGraph *item = nullptr;
1196             item = req.create(plotcolor, plotname);
1197 
1198             if (dim==Dim2D)
1199             {
1200                 //Used to deal with infinite intervals.
1201                 if (arg1min!=0 || arg1max!=0)
1202                     item->setInterval(item->parameters().first(), arg1min, arg1max);
1203             }
1204             
1205             m_document->plotsModel()->addPlot(item);
1206         } 
1207         else
1208             errors = req.errors();
1209     }
1210 }
1211 
1212 #include "moc_mainwindow.cpp"