diff --git a/src/backend/core/Project.cpp b/src/backend/core/Project.cpp index c48feffe3..773dea4cd 100644 --- a/src/backend/core/Project.cpp +++ b/src/backend/core/Project.cpp @@ -1,416 +1,412 @@ /*************************************************************************** File : Project.cpp Project : LabPlot Description : Represents a LabPlot project. -------------------------------------------------------------------- Copyright : (C) 2011-2014 Alexander Semke (alexander.semke@web.de) Copyright : (C) 2007-2008 Tilman Benkert (thzs@gmx.net) Copyright : (C) 2007 Knut Franke (knut.franke@gmx.de) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "backend/core/Project.h" #include "backend/lib/XmlStreamReader.h" #include "backend/datasources/LiveDataSource.h" #include "backend/spreadsheet/Spreadsheet.h" #include "backend/worksheet/Worksheet.h" #include "backend/worksheet/plots/cartesian/XYEquationCurve.h" #include "backend/worksheet/plots/cartesian/XYDataReductionCurve.h" #include "backend/worksheet/plots/cartesian/XYDifferentiationCurve.h" #include "backend/worksheet/plots/cartesian/XYIntegrationCurve.h" #include "backend/worksheet/plots/cartesian/XYInterpolationCurve.h" #include "backend/worksheet/plots/cartesian/XYSmoothCurve.h" #include "backend/worksheet/plots/cartesian/XYFitCurve.h" #include "backend/worksheet/plots/cartesian/XYFourierFilterCurve.h" #include "backend/worksheet/plots/cartesian/XYFourierTransformCurve.h" #include "backend/worksheet/plots/cartesian/Axis.h" #include "backend/datapicker/DatapickerCurve.h" #include #include #include #include #include #include #include /** * \class Project * \brief Represents a project. * \ingroup core * Project represents the root node of all objects created during the runtime of the program. * Manages also the undo stack. */ /** * \enum Project::MdiWindowVisibility * \brief MDI subwindow visibility setting */ /** * \var Project::folderOnly * \brief only show MDI windows corresponding to Parts in the current folder */ /** * \var Project::foldAndSubfolders * \brief show MDI windows corresponding to Parts in the current folder and its subfolders */ /** * \var Project::allMdiWindows * \brief show MDI windows for all Parts in the project simultaneously */ class Project::Private { - public: - Private() : - mdiWindowVisibility(Project::folderOnly), - scriptingEngine(0), - version(LVERSION), - author(QString(qgetenv("USER"))), - modificationTime(QDateTime::currentDateTime()), - changed(false), - loading(false) - {} - - QUndoStack undo_stack; - MdiWindowVisibility mdiWindowVisibility; - AbstractScriptingEngine* scriptingEngine; - QString fileName; - QString version; - QString author; - QDateTime modificationTime; - bool changed; - bool loading; +public: + Private() : + mdiWindowVisibility(Project::folderOnly), + scriptingEngine(0), + version(LVERSION), + author(QString(qgetenv("USER"))), + modificationTime(QDateTime::currentDateTime()), + changed(false), + loading(false) { + } + + QUndoStack undo_stack; + MdiWindowVisibility mdiWindowVisibility; + AbstractScriptingEngine* scriptingEngine; + QString fileName; + QString version; + QString author; + QDateTime modificationTime; + bool changed; + bool loading; }; Project::Project() : Folder(i18n("Project")), d(new Private()) { //load default values for name, comment and author from config KConfig config; KConfigGroup group = config.group("Project"); d->author = group.readEntry("Author", QString()); //we don't have direct access to the members name and comment //->temporaly disable the undo stack and call the setters setUndoAware(false); d->loading = true; setName(group.readEntry("Name", i18n("Project"))); setComment(group.readEntry("Comment", QString())); setUndoAware(true); d->loading = false; d->changed = false; // TODO: intelligent engine choosing // Q_ASSERT(ScriptingEngineManager::instance()->engineNames().size() > 0); // QString engine_name = ScriptingEngineManager::instance()->engineNames()[0]; // d->scriptingEngine = ScriptingEngineManager::instance()->engine(engine_name); connect(this, SIGNAL(aspectDescriptionChanged(const AbstractAspect*)),this, SLOT(descriptionChanged(const AbstractAspect*))); } Project::~Project() { //if the project is being closed, in Worksheet the scene items are being removed and the selection in the view can change. //don't react on these changes since this can lead crashes (worksheet object is already in the destructor). //->notify all worksheets about the project being closed. - QList liveDataSources = children(); + QList liveDataSources = children(); - for(auto* lds : liveDataSources) { - lds->pauseReading(); - } + for(auto* lds : liveDataSources) + lds->pauseReading(); - foreach(Worksheet* w, children()) + foreach(Worksheet* w, children()) w->setIsClosing(); d->undo_stack.clear(); delete d; } QUndoStack* Project::undoStack() const { return &d->undo_stack; } QMenu* Project::createContextMenu() { QMenu* menu = new QMenu(); // no remove action from AbstractAspect in the project context menu emit requestProjectContextMenu(menu); return menu; } QMenu* Project::createFolderContextMenu(const Folder* folder) { QMenu* menu = const_cast(folder)->AbstractAspect::createContextMenu(); Q_ASSERT(menu); emit requestFolderContextMenu(folder, menu); return menu; } void Project::setMdiWindowVisibility(MdiWindowVisibility visibility) { d->mdiWindowVisibility = visibility; emit mdiWindowVisibilityChanged(); } Project::MdiWindowVisibility Project::mdiWindowVisibility() const { return d->mdiWindowVisibility; } AbstractScriptingEngine* Project::scriptingEngine() const { return d->scriptingEngine; } CLASS_D_ACCESSOR_IMPL(Project, QString, fileName, FileName, fileName) BASIC_D_ACCESSOR_IMPL(Project, QString, version, Version, version) CLASS_D_ACCESSOR_IMPL(Project, QString, author, Author, author) CLASS_D_ACCESSOR_IMPL(Project, QDateTime, modificationTime, ModificationTime, modificationTime) void Project::setChanged(const bool value) { if (d->loading) return; if (value) emit changed(); d->changed = value; } bool Project ::hasChanged() const { return d->changed ; } void Project::descriptionChanged(const AbstractAspect* aspect) { if (d->loading) return; if (this!=aspect) return; d->changed = true; emit changed(); } void Project::navigateTo(const QString& path) { requestNavigateTo(path); } bool Project::isLoading() const { return d->loading; } //############################################################################## //################## Serialization/Deserialization ########################### //############################################################################## /** * \brief Save as XML */ void Project::save(QXmlStreamWriter* writer) const { //set the version and the modification time to the current values d->version = LVERSION; d->modificationTime = QDateTime::currentDateTime(); writer->setAutoFormatting(true); writer->writeStartDocument(); writer->writeDTD(""); writer->writeStartElement("project"); writer->writeAttribute("version", version()); writer->writeAttribute("fileName", fileName()); writer->writeAttribute("modificationTime", modificationTime().toString("yyyy-dd-MM hh:mm:ss:zzz")); writer->writeAttribute("author", author()); writeBasicAttributes(writer); writeCommentElement(writer); //save all children foreach(AbstractAspect* child, children(IncludeHidden)) { writer->writeStartElement("child_aspect"); child->save(writer); writer->writeEndElement(); } //save the state of the views (visible, maximized/minimized/geometry) //and the state of the project explorer (expanded items, currently selected item) emit requestSaveState(writer); writer->writeEndElement(); writer->writeEndDocument(); } /** * \brief Load from XML */ bool Project::load(XmlStreamReader* reader) { d->loading = true; while (!(reader->isStartDocument() || reader->atEnd())) reader->readNext(); if(!(reader->atEnd())) { if (!reader->skipToNextTag()) return false; if (reader->name() == "project") { QString version = reader->attributes().value("version").toString(); if(version.isEmpty()) reader->raiseWarning(i18n("Attribute 'version' is missing.")); else d->version = version; if (!readBasicAttributes(reader)) return false; if (!readProjectAttributes(reader)) return false; while (!reader->atEnd()) { reader->readNext(); if (reader->isEndElement()) break; if (reader->isStartElement()) { if (reader->name() == "comment") { if (!readCommentElement(reader)) return false; } else if(reader->name() == "child_aspect") { if (!readChildAspectElement(reader)) return false; } else if(reader->name() == "state") { //load the state of the views (visible, maximized/minimized/geometry) //and the state of the project explorer (expanded items, currently selected item) emit requestLoadState(reader); } else { reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString())); if (!reader->skipToEndElement()) return false; } } } //wait until all columns are decoded from base64-encoded data QThreadPool::globalInstance()->waitForDone(); //everything is read now. //restore the pointer to the data sets (columns) in xy-curves etc. QList curves = children(AbstractAspect::Recursive); QList axes = children(AbstractAspect::Recursive); QList dataPickerCurves = children(AbstractAspect::Recursive); if (!curves.isEmpty() || !axes.isEmpty()) { QList columns = children(AbstractAspect::Recursive); //XY-curves foreach (XYCurve* curve, curves) { if (!curve) continue; curve->suppressRetransform(true); XYEquationCurve* equationCurve = dynamic_cast(curve); XYDataReductionCurve* dataReductionCurve = dynamic_cast(curve); XYDifferentiationCurve* differentiationCurve = dynamic_cast(curve); XYIntegrationCurve* integrationCurve = dynamic_cast(curve); XYInterpolationCurve* interpolationCurve = dynamic_cast(curve); XYSmoothCurve* smoothCurve = dynamic_cast(curve); XYFitCurve* fitCurve = dynamic_cast(curve); XYFourierFilterCurve* filterCurve = dynamic_cast(curve); XYFourierTransformCurve* dftCurve = dynamic_cast(curve); if (equationCurve) { //curves defined by a mathematical equations recalculate their own columns on load again. equationCurve->recalculate(); } else if (dataReductionCurve) { RESTORE_COLUMN_POINTER(dataReductionCurve, xDataColumn, XDataColumn); RESTORE_COLUMN_POINTER(dataReductionCurve, yDataColumn, YDataColumn); } else if (differentiationCurve) { RESTORE_COLUMN_POINTER(differentiationCurve, xDataColumn, XDataColumn); RESTORE_COLUMN_POINTER(differentiationCurve, yDataColumn, YDataColumn); } else if (integrationCurve) { RESTORE_COLUMN_POINTER(integrationCurve, xDataColumn, XDataColumn); RESTORE_COLUMN_POINTER(integrationCurve, yDataColumn, YDataColumn); } else if (interpolationCurve) { RESTORE_COLUMN_POINTER(interpolationCurve, xDataColumn, XDataColumn); RESTORE_COLUMN_POINTER(interpolationCurve, yDataColumn, YDataColumn); } else if (smoothCurve) { RESTORE_COLUMN_POINTER(smoothCurve, xDataColumn, XDataColumn); RESTORE_COLUMN_POINTER(smoothCurve, yDataColumn, YDataColumn); } else if (fitCurve) { RESTORE_COLUMN_POINTER(fitCurve, xDataColumn, XDataColumn); RESTORE_COLUMN_POINTER(fitCurve, yDataColumn, YDataColumn); RESTORE_COLUMN_POINTER(fitCurve, xErrorColumn, XErrorColumn); RESTORE_COLUMN_POINTER(fitCurve, yErrorColumn, YErrorColumn); } else if (filterCurve) { RESTORE_COLUMN_POINTER(filterCurve, xDataColumn, XDataColumn); RESTORE_COLUMN_POINTER(filterCurve, yDataColumn, YDataColumn); } else if (dftCurve) { RESTORE_COLUMN_POINTER(dftCurve, xDataColumn, XDataColumn); RESTORE_COLUMN_POINTER(dftCurve, yDataColumn, YDataColumn); } else { RESTORE_COLUMN_POINTER(curve, xColumn, XColumn); RESTORE_COLUMN_POINTER(curve, yColumn, YColumn); RESTORE_COLUMN_POINTER(curve, valuesColumn, ValuesColumn); RESTORE_COLUMN_POINTER(curve, xErrorPlusColumn, XErrorPlusColumn); RESTORE_COLUMN_POINTER(curve, xErrorMinusColumn, XErrorMinusColumn); RESTORE_COLUMN_POINTER(curve, yErrorPlusColumn, YErrorPlusColumn); RESTORE_COLUMN_POINTER(curve, yErrorMinusColumn, YErrorMinusColumn); } RESTORE_POINTER(curve, dataSourceCurve, DataSourceCurve, XYCurve, curves); curve->suppressRetransform(false); curve->retransform(); } //Axes foreach (Axis* axis, axes) { if (!axis) continue; RESTORE_COLUMN_POINTER(axis, majorTicksColumn, MajorTicksColumn); RESTORE_COLUMN_POINTER(axis, minorTicksColumn, MinorTicksColumn); } foreach (DatapickerCurve* dataPickerCurve, dataPickerCurves) { if (!dataPickerCurve) continue; RESTORE_COLUMN_POINTER(dataPickerCurve, posXColumn, PosXColumn); RESTORE_COLUMN_POINTER(dataPickerCurve, posYColumn, PosYColumn); RESTORE_COLUMN_POINTER(dataPickerCurve, plusDeltaXColumn, PlusDeltaXColumn); RESTORE_COLUMN_POINTER(dataPickerCurve, minusDeltaXColumn, MinusDeltaXColumn); RESTORE_COLUMN_POINTER(dataPickerCurve, plusDeltaYColumn, PlusDeltaYColumn); RESTORE_COLUMN_POINTER(dataPickerCurve, minusDeltaYColumn, MinusDeltaYColumn); - } + } } - } else {// no project element + } else // no project element reader->raiseError(i18n("no project element found")); - } - } else {// no start document + } else // no start document reader->raiseError(i18n("no valid XML document found")); - } d->loading = false; emit loaded(); return !reader->hasError(); } bool Project::readProjectAttributes(XmlStreamReader* reader) { QXmlStreamAttributes attribs = reader->attributes(); QString str = attribs.value(reader->namespaceUri().toString(), "fileName").toString(); if(str.isEmpty()) { reader->raiseError(i18n("Project file name missing.")); return false; } d->fileName = str; str = attribs.value(reader->namespaceUri().toString(), "modificationTime").toString(); QDateTime modificationTime = QDateTime::fromString(str, "yyyy-dd-MM hh:mm:ss:zzz"); if(str.isEmpty() || !modificationTime.isValid()) { reader->raiseWarning(i18n("Invalid project modification time. Using current time.")); d->modificationTime = QDateTime::currentDateTime(); - } else { + } else d->modificationTime = modificationTime; - } str = attribs.value(reader->namespaceUri().toString(), "author").toString(); d->author = str; return true; } diff --git a/src/backend/core/Project.h b/src/backend/core/Project.h index 46218937b..6d2848409 100644 --- a/src/backend/core/Project.h +++ b/src/backend/core/Project.h @@ -1,97 +1,102 @@ /*************************************************************************** File : Project.h Project : LabPlot Description : Represents a LabPlot project. -------------------------------------------------------------------- Copyright : (C) 2011-2014 Alexander Semke (alexander.semke@web.de) Copyright : (C) 2007-2008 Tilman Benkert (thzs@gmx.net) Copyright : (C) 2007 Knut Franke (knut.franke@gmx.de) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #ifndef PROJECT_H #define PROJECT_H #include "backend/core/Folder.h" #include "backend/lib/macros.h" class QString; class AbstractScriptingEngine; class Project : public Folder { Q_OBJECT - public: - enum MdiWindowVisibility - { - folderOnly, - folderAndSubfolders, - allMdiWindows - }; - - public: - Project(); - ~Project(); - - virtual const Project* project() const { return this; } - virtual Project* project() { return this; } - virtual QUndoStack* undoStack() const; - virtual QString path() const { return name(); } - virtual QMenu* createContextMenu(); - virtual QMenu* createFolderContextMenu(const Folder*); - - AbstractScriptingEngine* scriptingEngine() const; - - void setMdiWindowVisibility(MdiWindowVisibility visibility); - MdiWindowVisibility mdiWindowVisibility() const; - CLASS_D_ACCESSOR_DECL(QString, fileName, FileName) - BASIC_D_ACCESSOR_DECL(QString, version, Version) - CLASS_D_ACCESSOR_DECL(QString, author, Author) - CLASS_D_ACCESSOR_DECL(QDateTime, modificationTime, ModificationTime) - - bool isLoading() const; - void setChanged(const bool value=true); - bool hasChanged() const; - void navigateTo(const QString& path); - - virtual void save(QXmlStreamWriter*) const; - virtual bool load(XmlStreamReader*); - - public slots: - void descriptionChanged(const AbstractAspect*); - - signals: - void requestSaveState(QXmlStreamWriter*) const; - void requestLoadState(XmlStreamReader*) const; - void requestProjectContextMenu(QMenu*); - void requestFolderContextMenu(const Folder*, QMenu*); - void mdiWindowVisibilityChanged(); - void changed() const; - void requestNavigateTo(const QString& path) const; - void loaded(); - - private: - class Private; - Private* d; - bool readProjectAttributes(XmlStreamReader*); +public: + enum MdiWindowVisibility { + folderOnly, + folderAndSubfolders, + allMdiWindows + }; + +public: + Project(); + ~Project(); + + virtual const Project* project() const { + return this; + } + virtual Project* project() { + return this; + } + virtual QUndoStack* undoStack() const; + virtual QString path() const { + return name(); + } + virtual QMenu* createContextMenu(); + virtual QMenu* createFolderContextMenu(const Folder*); + + AbstractScriptingEngine* scriptingEngine() const; + + void setMdiWindowVisibility(MdiWindowVisibility visibility); + MdiWindowVisibility mdiWindowVisibility() const; + CLASS_D_ACCESSOR_DECL(QString, fileName, FileName) + BASIC_D_ACCESSOR_DECL(QString, version, Version) + CLASS_D_ACCESSOR_DECL(QString, author, Author) + CLASS_D_ACCESSOR_DECL(QDateTime, modificationTime, ModificationTime) + + bool isLoading() const; + void setChanged(const bool value=true); + bool hasChanged() const; + void navigateTo(const QString& path); + + virtual void save(QXmlStreamWriter*) const; + virtual bool load(XmlStreamReader*); + +public slots: + void descriptionChanged(const AbstractAspect*); + +signals: + void requestSaveState(QXmlStreamWriter*) const; + void requestLoadState(XmlStreamReader*) const; + void requestProjectContextMenu(QMenu*); + void requestFolderContextMenu(const Folder*, QMenu*); + void mdiWindowVisibilityChanged(); + void changed() const; + void requestNavigateTo(const QString& path) const; + void loaded(); + +private: + class Private; + Private* d; + bool readProjectAttributes(XmlStreamReader*); }; #endif // ifndef PROJECT_H