File indexing completed on 2024-05-12 03:47:25

0001 /*
0002     File                 : AbstractAspect.h
0003     Project              : LabPlot
0004     Description          : Base class for all objects in a Project.
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2007-2009 Tilman Benkert <thzs@gmx.net>
0007     SPDX-FileCopyrightText: 2007-2010 Knut Franke <knut.franke@gmx.de>
0008     SPDX-FileCopyrightText: 2011-2023 Alexander Semke <alexander.semke@web.de>
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #ifndef ABSTRACT_ASPECT_H
0013 #define ABSTRACT_ASPECT_H
0014 
0015 #include <QObject>
0016 #include <QVector>
0017 
0018 class AbstractAspectPrivate;
0019 class Folder;
0020 class Project;
0021 class XmlStreamReader;
0022 
0023 class QDateTime;
0024 class QIcon;
0025 class QMenu;
0026 class QUndoCommand;
0027 class QUndoStack;
0028 class QXmlStreamWriter;
0029 
0030 /// Information about class inheritance
0031 /// enum values are chosen such that @verbatim inherits(base)@endverbatim
0032 /// returns true if the class inherits from @verbatim base@endverbatim.
0033 ///
0034 /// AspectType is used in GuiObserver to select the correct dock widget.
0035 enum class AspectType : quint64 {
0036     AbstractAspect = 0,
0037 
0038     // classes without inheriters
0039     AbstractFilter = 0x0100001,
0040     DatapickerCurve = 0x0100002,
0041     DatapickerPoint = 0x0100004,
0042 
0043     WorksheetElement = 0x0200000,
0044     Axis = 0x0210001,
0045     CartesianPlotLegend = 0x0210002,
0046     CustomPoint = 0x0210004,
0047     PlotArea = 0x0210010,
0048     TextLabel = 0x0210020,
0049     Image = 0x0210030,
0050     ReferenceLine = 0x0210040,
0051     ReferenceRange = 0x0210060,
0052     InfoElement = 0x0210080,
0053 
0054     // bar plots
0055     BarPlot = 0x0210200,
0056     LollipopPlot = 0x0210400,
0057 
0058     // statistical plots
0059     Histogram = 0x0210008,
0060     BoxPlot = 0x0210100,
0061     QQPlot = 0x0210800,
0062     KDEPlot = 0x0210802,
0063 
0064     WorksheetElementContainer = 0x0220000,
0065     AbstractPlot = 0x0221000,
0066     CartesianPlot = 0x0221001,
0067     WorksheetElementGroup = 0x0222000,
0068     XYCurve = 0x0240000,
0069     XYEquationCurve = 0x0240001,
0070 
0071     // analysis curves
0072     XYAnalysisCurve = 0x0280000,
0073     XYConvolutionCurve = 0x0280001,
0074     XYCorrelationCurve = 0x0280002,
0075     XYDataReductionCurve = 0x0280004,
0076     XYDifferentiationCurve = 0x0280008,
0077     XYFitCurve = 0x0280010,
0078     XYFourierFilterCurve = 0x0280020,
0079     XYFourierTransformCurve = 0x0280040,
0080     XYInterpolationCurve = 0x0280080,
0081     XYIntegrationCurve = 0x0280100,
0082     XYSmoothCurve = 0x0280200,
0083     XYHilbertTransformCurve = 0x0280400,
0084 
0085     AbstractPart = 0x0400000,
0086     AbstractDataSource = 0x0410000,
0087     Matrix = 0x0411000,
0088     Spreadsheet = 0x0412000,
0089     LiveDataSource = 0x0412001,
0090     MQTTTopic = 0x0412002,
0091     StatisticsSpreadsheet = 0x0412004,
0092     CantorWorksheet = 0x0420001,
0093     Datapicker = 0x0420002,
0094     DatapickerImage = 0x0420004,
0095     Note = 0x0420008,
0096     Workbook = 0x0420010,
0097     Worksheet = 0x0420020,
0098 
0099     AbstractColumn = 0x1000000,
0100     Column = 0x1000001,
0101     SimpleFilterColumn = 0x1000002,
0102     ColumnStringIO = 0x1000004,
0103 
0104     Folder = 0x2000000,
0105     Project = 0x2000001,
0106     MQTTClient = 0x2000002,
0107     MQTTSubscription = 0x2000004,
0108 };
0109 
0110 #ifdef SDK
0111 #include "labplot_export.h"
0112 class LABPLOT_EXPORT AbstractAspect : public QObject {
0113 #else
0114 class AbstractAspect : public QObject {
0115 #endif
0116     Q_OBJECT
0117 
0118 public:
0119     enum class ChildIndexFlag { IncludeHidden = 0x01, Recursive = 0x02, Compress = 0x04 };
0120 
0121     Q_DECLARE_FLAGS(ChildIndexFlags, ChildIndexFlag)
0122 
0123     friend class AspectChildAddCmd;
0124     friend class AspectChildRemoveCmd;
0125     friend class AbstractAspectPrivate;
0126 
0127     AbstractAspect(const QString& name, AspectType type);
0128     ~AbstractAspect() override;
0129 
0130     enum class NameHandling {
0131         AutoUnique, // Set the name and make it unique (enforce the uniqueness)
0132         UniqueNotRequired, // Set the name without making it unique
0133         UniqueRequired, // Set the name only if it's already unique
0134     };
0135 
0136     // type name for internal use (no translation)
0137     static QString typeName(AspectType type) {
0138         switch (type) {
0139         case AspectType::AbstractAspect:
0140             return QStringLiteral("AbstractAspect");
0141         case AspectType::AbstractFilter:
0142             return QStringLiteral("AbstractFilter");
0143         case AspectType::DatapickerCurve:
0144             return QStringLiteral("DatapickerCurve");
0145         case AspectType::DatapickerPoint:
0146             return QStringLiteral("DatapickerPoint");
0147         case AspectType::WorksheetElement:
0148             return QStringLiteral("WorksheetElement");
0149         case AspectType::Axis:
0150             return QStringLiteral("Axis");
0151         case AspectType::CartesianPlotLegend:
0152             return QStringLiteral("CartesianPlotLegend");
0153         case AspectType::CustomPoint:
0154             return QStringLiteral("CustomPoint");
0155         case AspectType::Histogram:
0156             return QStringLiteral("Histogram");
0157         case AspectType::PlotArea:
0158             return QStringLiteral("PlotArea");
0159         case AspectType::TextLabel:
0160             return QStringLiteral("TextLabel");
0161         case AspectType::Image:
0162             return QStringLiteral("Image");
0163         case AspectType::ReferenceLine:
0164             return QStringLiteral("ReferenceLine");
0165         case AspectType::ReferenceRange:
0166             return QStringLiteral("ReferenceRange");
0167         case AspectType::InfoElement:
0168             return QStringLiteral("InfoElement");
0169         case AspectType::WorksheetElementContainer:
0170             return QStringLiteral("WorksheetElementContainer");
0171         case AspectType::AbstractPlot:
0172             return QStringLiteral("AbstractPlot");
0173         case AspectType::CartesianPlot:
0174             return QStringLiteral("CartesianPlot");
0175         case AspectType::WorksheetElementGroup:
0176             return QStringLiteral("WorksheetElementGroup");
0177         case AspectType::XYCurve:
0178             return QStringLiteral("XYCurve");
0179         case AspectType::XYEquationCurve:
0180             return QStringLiteral("XYEquationCurve");
0181         case AspectType::XYAnalysisCurve:
0182             return QStringLiteral("XYAnalysisCurve");
0183         case AspectType::XYConvolutionCurve:
0184             return QStringLiteral("XYConvolutionCurve");
0185         case AspectType::XYCorrelationCurve:
0186             return QStringLiteral("XYCorrelationCurve");
0187         case AspectType::XYDataReductionCurve:
0188             return QStringLiteral("XYDataReductionCurve");
0189         case AspectType::XYDifferentiationCurve:
0190             return QStringLiteral("XYDifferentiationCurve");
0191         case AspectType::XYFitCurve:
0192             return QStringLiteral("XYFitCurve");
0193         case AspectType::XYFourierFilterCurve:
0194             return QStringLiteral("XYFourierFilterCurve");
0195         case AspectType::XYFourierTransformCurve:
0196             return QStringLiteral("XYFourierTransformCurve");
0197         case AspectType::XYInterpolationCurve:
0198             return QStringLiteral("XYInterpolationCurve");
0199         case AspectType::XYIntegrationCurve:
0200             return QStringLiteral("XYIntegrationCurve");
0201         case AspectType::XYSmoothCurve:
0202             return QStringLiteral("XYSmoothCurve");
0203         case AspectType::XYHilbertTransformCurve:
0204             return QStringLiteral("XYHilbertTransformCurve");
0205         case AspectType::BarPlot:
0206             return QStringLiteral("BarPlot");
0207         case AspectType::BoxPlot:
0208             return QStringLiteral("BoxPlot");
0209         case AspectType::QQPlot:
0210             return QStringLiteral("QQPlot");
0211         case AspectType::KDEPlot:
0212             return QStringLiteral("KDEPlot");
0213         case AspectType::LollipopPlot:
0214             return QStringLiteral("LollipopPlot");
0215         case AspectType::AbstractPart:
0216             return QStringLiteral("AbstractPart");
0217         case AspectType::AbstractDataSource:
0218             return QStringLiteral("AbstractDataSource");
0219         case AspectType::Matrix:
0220             return QStringLiteral("Matrix");
0221         case AspectType::Spreadsheet:
0222             return QStringLiteral("Spreadsheet");
0223         case AspectType::StatisticsSpreadsheet:
0224             return QStringLiteral("StatisticsSpreadsheet");
0225         case AspectType::LiveDataSource:
0226             return QStringLiteral("LiveDataSource");
0227         case AspectType::MQTTTopic:
0228             return QStringLiteral("MQTTTopic");
0229         case AspectType::CantorWorksheet:
0230             return QStringLiteral("CantorWorksheet");
0231         case AspectType::Datapicker:
0232             return QStringLiteral("Datapicker");
0233         case AspectType::DatapickerImage:
0234             return QStringLiteral("DatapickerImage");
0235         case AspectType::Note:
0236             return QStringLiteral("Note");
0237         case AspectType::Workbook:
0238             return QStringLiteral("Workbook");
0239         case AspectType::Worksheet:
0240             return QStringLiteral("Worksheet");
0241         case AspectType::AbstractColumn:
0242             return QStringLiteral("AbstractColumn");
0243         case AspectType::Column:
0244             return QStringLiteral("Column");
0245         case AspectType::SimpleFilterColumn:
0246             return QStringLiteral("SimpleFilterColumn");
0247         case AspectType::ColumnStringIO:
0248             return QStringLiteral("ColumnStringIO");
0249         case AspectType::Folder:
0250             return QStringLiteral("Folder");
0251         case AspectType::Project:
0252             return QStringLiteral("Project");
0253         case AspectType::MQTTClient:
0254             return QStringLiteral("MQTTClient");
0255         case AspectType::MQTTSubscription:
0256             return QStringLiteral("MQTTSubscription");
0257         }
0258 
0259         return {};
0260     }
0261 
0262     QString name() const;
0263     QUuid uuid() const;
0264     void setSuppressWriteUuid(bool);
0265     QString comment() const;
0266     void setCreationTime(const QDateTime&);
0267     QDateTime creationTime() const;
0268     virtual Project* project();
0269     virtual QString path() const;
0270     void setHidden(bool);
0271     bool hidden() const;
0272     void setFixed(bool);
0273     bool isFixed() const;
0274     void setSelected(bool);
0275     void setMoved(bool);
0276     bool isMoved() const;
0277     void setIsLoading(bool);
0278     bool isLoading() const;
0279     virtual QIcon icon() const;
0280     virtual QMenu* createContextMenu();
0281 
0282     AspectType type() const;
0283     bool inherits(AspectType type) const;
0284 
0285     // functions related to the handling of the tree-like project structure
0286     AbstractAspect* parentAspect() const;
0287     AbstractAspect* parent(AspectType type) const;
0288     void setParentAspect(AbstractAspect*);
0289     Folder* folder();
0290     bool isDescendantOf(AbstractAspect* other);
0291     void addChild(AbstractAspect*, QUndoCommand* parent = nullptr);
0292     void addChildFast(AbstractAspect*);
0293     virtual void finalizeAdd(){};
0294     QVector<AbstractAspect*> children(AspectType type, ChildIndexFlags flags = {}) const;
0295     void insertChild(AbstractAspect* child, int index, QUndoCommand* parent = nullptr);
0296     void insertChildBefore(AbstractAspect* child, AbstractAspect* before, QUndoCommand* parent = nullptr);
0297     void insertChildBeforeFast(AbstractAspect* child, AbstractAspect* before);
0298     void reparent(AbstractAspect* newParent, int newIndex = -1);
0299     /*!
0300      * \brief removeChild
0301      * Removing child aspect using an undo command
0302      * \param parent If parent is not nullptr the command will not be executed, but the parent must be executed
0303      * to indirectly execute the created undocommand
0304      */
0305     void removeChild(AbstractAspect*, QUndoCommand* parent = nullptr);
0306     void removeAllChildren();
0307     virtual QVector<AbstractAspect*> dependsOn() const;
0308 
0309     virtual QVector<AspectType> pasteTypes() const;
0310     virtual bool isDraggable() const;
0311     virtual QVector<AspectType> dropableOn() const;
0312     virtual void processDropEvent(const QVector<quintptr>&){};
0313 
0314     template<class T>
0315     T* ancestor() const {
0316         AbstractAspect* parent = parentAspect();
0317         while (parent) {
0318             T* ancestorAspect = dynamic_cast<T*>(parent);
0319             if (ancestorAspect)
0320                 return ancestorAspect;
0321             parent = parent->parentAspect();
0322         }
0323         return nullptr;
0324     }
0325 
0326     template<class T>
0327     QVector<T*> children(ChildIndexFlags flags = {}) const {
0328         QVector<T*> result;
0329         for (auto* child : children()) {
0330             if (flags & ChildIndexFlag::IncludeHidden || !child->hidden()) {
0331                 T* i = dynamic_cast<T*>(child);
0332                 if (i)
0333                     result << i;
0334 
0335                 if (child && flags & ChildIndexFlag::Recursive)
0336                     result << child->template children<T>(flags);
0337             }
0338         }
0339         return result;
0340     }
0341 
0342     template<class T>
0343     T* child(int index, ChildIndexFlags flags = {}) const {
0344         int i = 0;
0345         for (auto* child : children()) {
0346             T* c = dynamic_cast<T*>(child);
0347             if (c && (flags & ChildIndexFlag::IncludeHidden || !child->hidden()) && index == i++)
0348                 return c;
0349         }
0350         return nullptr;
0351     }
0352 
0353     template<class T>
0354     T* child(const QString& name) const {
0355         for (auto* child : children()) {
0356             T* c = dynamic_cast<T*>(child);
0357             if (c && child->name() == name)
0358                 return c;
0359         }
0360         return nullptr;
0361     }
0362 
0363     template<class T>
0364     int childCount(ChildIndexFlags flags = {}) const {
0365         int result = 0;
0366         for (auto* child : children()) {
0367             T* i = dynamic_cast<T*>(child);
0368             if (i && (flags & ChildIndexFlag::IncludeHidden || !child->hidden()))
0369                 result++;
0370         }
0371         return result;
0372     }
0373 
0374     template<class T>
0375     int indexOfChild(const AbstractAspect* child, ChildIndexFlags flags = {}) const {
0376         int index = 0;
0377         for (auto* c : children()) {
0378             if (child == c)
0379                 return index;
0380             T* i = dynamic_cast<T*>(c);
0381             if (i && (flags & ChildIndexFlag::IncludeHidden || !c->hidden()))
0382                 index++;
0383         }
0384         return -1;
0385     }
0386 
0387     // undo/redo related functions
0388     void setUndoAware(bool);
0389     virtual QUndoStack* undoStack() const;
0390     void exec(QUndoCommand*);
0391     void exec(QUndoCommand* command,
0392               const char* preChangeSignal,
0393               const char* postChangeSignal,
0394               QGenericArgument val0 = QGenericArgument(),
0395               QGenericArgument val1 = QGenericArgument(),
0396               QGenericArgument val2 = QGenericArgument(),
0397               QGenericArgument val3 = QGenericArgument());
0398     void beginMacro(const QString& text);
0399     void endMacro();
0400 
0401     // save/load
0402     virtual void save(QXmlStreamWriter*) const = 0;
0403     virtual bool load(XmlStreamReader*, bool preview) = 0;
0404     void setPasted(bool);
0405     bool pasted() const;
0406 
0407     static AspectType clipboardAspectType(QString&);
0408     static QString uniqueNameFor(const QString& name, const QStringList& names);
0409 
0410 protected:
0411     void info(const QString& text) {
0412         Q_EMIT statusInfo(text);
0413     }
0414 
0415     // serialization/deserialization
0416     bool readBasicAttributes(XmlStreamReader*);
0417     void writeBasicAttributes(QXmlStreamWriter*) const;
0418     void writeCommentElement(QXmlStreamWriter*) const;
0419     bool readCommentElement(XmlStreamReader*);
0420 
0421     const AspectType m_type;
0422 
0423 private:
0424     AbstractAspectPrivate* d;
0425 
0426     QString uniqueNameFor(const QString&) const;
0427     const QVector<AbstractAspect*>& children() const;
0428     void connectChild(AbstractAspect*);
0429 
0430 public Q_SLOTS:
0431     bool setName(const QString&, NameHandling handling = NameHandling::AutoUnique, QUndoCommand* parent = nullptr);
0432     void setComment(const QString&);
0433     void remove();
0434     void remove(QUndoCommand* parent);
0435     void copy();
0436     void duplicate();
0437     void paste(bool duplicate = false);
0438 
0439 private Q_SLOTS:
0440     void moveUp();
0441     void moveDown();
0442 
0443 protected Q_SLOTS:
0444     virtual void childSelected(const AbstractAspect*);
0445     virtual void childDeselected(const AbstractAspect*);
0446 
0447 Q_SIGNALS:
0448     void aspectDescriptionAboutToChange(const AbstractAspect*);
0449     void aspectDescriptionChanged(const AbstractAspect*);
0450     /*!
0451      * \brief aspectAboutToBeAdded
0452      * Signal indicating a new child was added at position \p index. Do not connect to both variants of aspectAboutToBeAdded!
0453      * \param parent
0454      * \param index Position of the new aspect
0455      * \param child
0456      */
0457     void childAspectAboutToBeAdded(const AbstractAspect* parent, int index, const AbstractAspect* child);
0458     /*!
0459      * \brief aspectAboutToBeAdded
0460      * \param parent
0461      * \param before aspect one position before the child
0462      * \param child
0463      */
0464     void childAspectAboutToBeAdded(const AbstractAspect* parent, const AbstractAspect* before, const AbstractAspect* child);
0465     void childAspectAdded(const AbstractAspect*);
0466     /*!
0467      * \brief aspectAboutToBeRemoved
0468      * Called from the parent if a child is being removed
0469      */
0470     void childAspectAboutToBeRemoved(const AbstractAspect* child);
0471     void childAspectRemoved(const AbstractAspect* parent, const AbstractAspect* before, const AbstractAspect* child);
0472     /*!
0473      * \brief aspectAboutToBeRemoved
0474      * Called by the aspect itself when it's being removed
0475      */
0476     void aspectAboutToBeRemoved(const AbstractAspect*);
0477     void aspectHiddenAboutToChange(const AbstractAspect*);
0478     void aspectHiddenChanged(const AbstractAspect*);
0479     void statusInfo(const QString&);
0480     void renameRequested();
0481     void contextMenuRequested(AspectType, QMenu*);
0482 
0483     // selection/deselection in model (project explorer)
0484     void selected(const AbstractAspect*);
0485     void deselected(const AbstractAspect*);
0486 
0487     // selection/deselection in view
0488     void childAspectSelectedInView(const AbstractAspect*);
0489     void childAspectDeselectedInView(const AbstractAspect*);
0490 
0491     // Used by the retransformTests
0492 Q_SIGNALS:
0493     void retransformCalledSignal(const AbstractAspect* sender, bool suppressed);
0494 
0495 public:
0496     void resetRetransformCalled() {
0497         mRetransformCalled = 0;
0498     }
0499     int retransformCalled() const {
0500         return mRetransformCalled;
0501     }
0502     int mRetransformCalled{0};
0503 
0504 #define trackRetransformCalled(suppressed)                                                                                                                     \
0505     Q_EMIT q->retransformCalledSignal(q, suppressed);                                                                                                          \
0506     if (!suppressed)                                                                                                                                           \
0507         q->mRetransformCalled += 1;
0508 
0509     friend class AbstractAspectTest;
0510 };
0511 
0512 Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractAspect::ChildIndexFlags)
0513 
0514 #endif // ifndef ABSTRACT_ASPECT_H