File indexing completed on 2024-05-12 15:54:11

0001 /*
0002  * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB.  All rights reserved.
0003  *
0004  * This file is part of the KD Chart library.
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public License as
0008  * published by the Free Software Foundation; either version 2 of
0009  * the License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
0018  */
0019 
0020 #ifndef KCHARTABSTRACTCOORDINATEPLANE_H
0021 #define KCHARTABSTRACTCOORDINATEPLANE_H
0022 
0023 #include <QObject>
0024 #include <QList>
0025 
0026 #include "KChartAbstractArea.h"
0027 #include "KChartAbstractDiagram.h"
0028 #include "KChartEnums.h"
0029 
0030 namespace KChart {
0031 
0032     class Chart;
0033     class GridAttributes;
0034     class DataDimension;
0035 
0036     typedef QList<DataDimension> DataDimensionsList;
0037 
0038     /**
0039       * @brief Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane, TernaryCoordinatePlane
0040       */
0041     class KCHART_EXPORT AbstractCoordinatePlane : public AbstractArea
0042     {
0043         Q_OBJECT
0044 
0045         KCHART_DECLARE_PRIVATE_DERIVED_PARENT( AbstractCoordinatePlane, Chart* )
0046 
0047     friend class AbstractGrid;
0048 
0049     public:
0050         enum AxesCalcMode { Linear, Logarithmic };
0051 
0052     protected:
0053         explicit AbstractCoordinatePlane( Chart* parent = nullptr );
0054 
0055     public:
0056         virtual ~AbstractCoordinatePlane();
0057 
0058         /**
0059          * Adds a diagram to this coordinate plane.
0060          * @param diagram The diagram to add.
0061          *
0062          * \sa replaceDiagram, takeDiagram
0063          */
0064         virtual void addDiagram( AbstractDiagram* diagram );
0065 
0066         /**
0067          * Replaces the old diagram, or appends the
0068          * diagram, it there is none yet.
0069          *
0070          * @param diagram The diagram to be used instead of the old diagram.
0071          * This parameter must not be zero, or the method will do nothing.
0072          *
0073          * @param oldDiagram The diagram to be removed by the new diagram. This
0074          * diagram will be deleted automatically. If the parameter is omitted,
0075          * the very first diagram will be replaced. In case, there was no
0076          * diagram yet, the new diagram will just be added.
0077          *
0078          * \note If you want to re-use the old diagram, call takeDiagram and
0079          * addDiagram, instead of using replaceDiagram.
0080          *
0081          * \sa addDiagram, takeDiagram
0082          */
0083         virtual void replaceDiagram( AbstractDiagram* diagram, AbstractDiagram* oldDiagram = nullptr );
0084 
0085         /**
0086          * Removes the diagram from the plane, without deleting it.
0087          *
0088          * The plane no longer owns the diagram, so it is
0089          * the caller's responsibility to delete the diagram.
0090          *
0091          * \sa addDiagram, replaceDiagram
0092         */
0093         virtual void takeDiagram( AbstractDiagram* diagram );
0094 
0095         /**
0096          * @return The first diagram associated with this coordinate plane.
0097          */
0098         AbstractDiagram* diagram();
0099 
0100         /**
0101          * @return The list of diagrams associated with this coordinate plane.
0102          */
0103         AbstractDiagramList diagrams();
0104 
0105         /**
0106          * @return The list of diagrams associated with this coordinate plane.
0107          */
0108         ConstAbstractDiagramList diagrams() const;
0109 
0110         /**
0111          * Distribute the available space among the diagrams and axes.
0112          */
0113         virtual void layoutDiagrams() = 0;
0114 
0115         /**
0116          * Translate the given point in value space coordinates to a position
0117          * in pixel space.
0118          * @param diagramPoint The point in value coordinates.
0119          * @returns The translated point.
0120          */
0121         virtual const QPointF translate( const QPointF& diagramPoint ) const = 0;
0122 
0123         /**
0124          * @return Whether zooming with a rubber band using the mouse is enabled.
0125          */
0126         bool isRubberBandZoomingEnabled() const;
0127 
0128         /**
0129          * Enables or disables zooming with a rubber band using the mouse.
0130          */
0131         void setRubberBandZoomingEnabled( bool enable );
0132 
0133         /**
0134          * @return The zoom factor in horizontal direction, that is applied
0135          * to all coordinate transformations.
0136          */
0137         virtual qreal zoomFactorX() const { return 1.0; }
0138 
0139         /**
0140          * @return The zoom factor in vertical direction, that is applied
0141          * to all coordinate transformations.
0142          */
0143         virtual qreal zoomFactorY() const { return 1.0; }
0144 
0145         /**
0146          * Sets both zoom factors in one go.
0147          * \sa setZoomFactorX,setZoomFactorY
0148          */
0149         virtual void setZoomFactors( qreal factorX, qreal factorY ) { Q_UNUSED( factorX ); Q_UNUSED( factorY ); }
0150 
0151         /**
0152          * Sets the zoom factor in horizontal direction, that is applied
0153          * to all coordinate transformations.
0154          * @param factor The new zoom factor
0155          */
0156         virtual void setZoomFactorX( qreal  factor ) { Q_UNUSED( factor ); }
0157 
0158         /**
0159          * Sets the zoom factor in vertical direction, that is applied
0160          * to all coordinate transformations.
0161          * @param factor The new zoom factor
0162          */
0163         virtual void setZoomFactorY( qreal factor ) { Q_UNUSED( factor ); }
0164 
0165         /**
0166          * @return The center point (in value coordinates) of the
0167          * coordinate plane, that is used for zoom operations.
0168          */
0169         virtual QPointF zoomCenter() const { return QPointF(0.0, 0.0); }
0170 
0171         /**
0172          * Set the point (in value coordinates) to be used as the
0173          * center point in zoom operations.
0174          * @param center The point to use.
0175          */
0176         virtual void setZoomCenter( const QPointF& center ) { Q_UNUSED( center ); }
0177 
0178         /**
0179          * Set the grid attributes to be used by this coordinate plane.
0180          * To disable grid painting, for example, your code should like this:
0181          * \code
0182          * GridAttributes ga = plane->globalGridAttributes();
0183          * ga.setGlobalGridVisible( false );
0184          * plane->setGlobalGridAttributes( ga );
0185          * \endcode
0186          * \sa globalGridAttributes
0187          * \sa CartesianCoordinatePlane::setGridAttributes
0188          */
0189         void setGlobalGridAttributes( const GridAttributes & );
0190 
0191         /**
0192          * @return The grid attributes used by this coordinate plane.
0193          * \sa setGlobalGridAttributes
0194          * \sa CartesianCoordinatePlane::gridAttributes
0195          */
0196         GridAttributes globalGridAttributes() const;
0197 
0198         /**
0199          * Returns the dimensions used for drawing the grid lines.
0200          *
0201          * Returned data is the result of (cached) grid calculations,
0202          * so - if you need that information for your own tasks - make sure to
0203          * call again this function after every data modification that has changed
0204          * the data range, since grid calculation is based upon the data range,
0205          * thus the grid start/end might have changed if the data was changed.
0206          *
0207          * @note Returned list will contain different numbers of DataDimension,
0208          * depending on the kind of coordinate plane used.
0209          * For CartesianCoordinatePlane two DataDimension are returned: the first
0210          * representing grid lines in X direction (matching the Abscissa axes)
0211          * and the second indicating vertical grid lines (or Ordinate axes, resp.).
0212          *
0213          * @return The dimensions used for drawing the grid lines.
0214          * @sa DataDimension
0215          */
0216         DataDimensionsList gridDimensionsList();
0217 
0218         /**
0219          * Set another coordinate plane to be used as the reference plane
0220          * for this one.
0221          * @param plane The coordinate plane to be used the reference plane
0222          * for this one.
0223          * @see referenceCoordinatePlane
0224          */
0225         void setReferenceCoordinatePlane( AbstractCoordinatePlane * plane );
0226 
0227         /**
0228          * There are two ways, in which planes can be caused to interact, in
0229          * where they are put layouting wise: The first is the reference plane. If
0230          * such a reference plane is set, on a plane, it will use the same cell in the
0231          * layout as that one. In addition to this, planes can share an axis. In that case
0232          * they will be laid out in relation to each other as suggested by the position
0233          * of the axis. If, for example Plane1 and Plane2 share an axis at position Left,
0234          * that will result in the layout: Axis Plane1 Plane 2, vertically. If Plane1
0235          * also happens to be Plane2's reference plane, both planes are drawn over each
0236          * other. The reference plane concept allows two planes to share the same space
0237          * even if neither has any axis, and in case there are shared axis, it is used
0238          * to decided, whether the planes should be painted on top of each other or
0239          * laid out vertically or horizontally next to each other.
0240          * @return The reference coordinate plane associated with this one.
0241          */
0242         AbstractCoordinatePlane * referenceCoordinatePlane() const;
0243 
0244         /**
0245          * @return Whether this plane should have spacers in the corners
0246          * formed by the presence of axes.
0247          */
0248         bool isCornerSpacersEnabled() const;
0249 
0250         /**
0251          * Enables or disables the use of spacers in the plane corners.
0252          */
0253         void setCornerSpacersEnabled( bool enable );
0254 
0255         virtual AbstractCoordinatePlane* sharedAxisMasterPlane( QPainter* p = nullptr ); // KChart 3: const method?
0256 
0257 
0258         /** pure virtual in QLayoutItem */
0259         bool isEmpty() const override;
0260         /** pure virtual in QLayoutItem */
0261         Qt::Orientations expandingDirections() const override;
0262         /** pure virtual in QLayoutItem */
0263         QSize maximumSize() const override;
0264         /** pure virtual in QLayoutItem */
0265         QSize minimumSize() const override;
0266         /** pure virtual in QLayoutItem */
0267         QSize sizeHint() const override;
0268         /** pure virtual in QLayoutItem
0269           *
0270           * \note Do not call this function directly, unless you know
0271           * exactly what you are doing.  Geometry management is done
0272           * by KChart's internal layouting measures.
0273           */
0274         void setGeometry( const QRect& r ) override;
0275         /** pure virtual in QLayoutItem */
0276         QRect geometry() const override;
0277 
0278         virtual void mousePressEvent( QMouseEvent* event );
0279         virtual void mouseDoubleClickEvent( QMouseEvent* event );
0280         virtual void mouseMoveEvent( QMouseEvent* event );
0281         virtual void mouseReleaseEvent( QMouseEvent* event );
0282 
0283         /**
0284           * Called internally by KChart::Chart
0285           */
0286         void setParent( Chart* parent );
0287         Chart* parent();
0288         const Chart* parent() const;
0289 
0290         /**
0291          * Tests, if a point is visible on the coordinate plane.
0292          *
0293          * \note Before calling this function the point must have been translated into coordinate plane space.
0294          */
0295 #if defined(Q_COMPILER_MANGLES_RETURN_TYPE)
0296         const bool isVisiblePoint( const QPointF& point ) const;
0297 #else
0298         bool isVisiblePoint( const QPointF& point ) const;
0299 #endif
0300 
0301     public Q_SLOTS:
0302         /**
0303           * Calling update() on the plane triggers the global KChart::Chart::update()
0304           */
0305         void update();
0306         /**
0307           * Calling relayout() on the plane triggers the global KChart::Chart::slotRelayout()
0308           */
0309         void relayout();
0310         /**
0311           * Calling layoutPlanes() on the plane triggers the global KChart::Chart::slotLayoutPlanes()
0312           */
0313         void layoutPlanes();
0314         /**
0315          * Used by the chart to clear the cached grid data.
0316          */
0317         void setGridNeedsRecalculate();
0318 
0319     Q_SIGNALS:
0320         /** Emitted when this coordinate plane is destroyed. */
0321         void destroyedCoordinatePlane( AbstractCoordinatePlane* );
0322 
0323         /** Emitted when plane needs to update its drawings. */
0324         void needUpdate();
0325 
0326         /** Emitted when plane needs to trigger the Chart's layouting. */
0327         void needRelayout();
0328 
0329         /** Emitted when plane needs to trigger the Chart's layouting of the coord. planes. */
0330         void needLayoutPlanes();
0331 
0332         /** Emitted upon change of a property of the Coordinate Plane or any of its components. */
0333         void propertiesChanged();
0334 
0335         void boundariesChanged();
0336 
0337         /** Emitted after the geometry of the Coordinate Plane has been changed.
0338          *  and control has returned to the event loop.
0339          *
0340          * Parameters are the old geometry, the new geometry.
0341         */
0342         void geometryChanged( QRect, QRect );
0343 
0344     private:
0345     Q_SIGNALS:
0346         // Emitted from inside the setGeometry()
0347         // This is connected via QueuedConnection to the geometryChanged() Signal
0348         // that users can connect to safely then.
0349         void internal_geometryChanged( QRect, QRect );
0350         /** Emitted upon change of the view coordinate system */
0351         void viewportCoordinateSystemChanged();
0352 
0353     protected:
0354         virtual DataDimensionsList getDataDimensionsList() const = 0;
0355 
0356         //KCHART_DECLARE_PRIVATE_DERIVED( AbstractCoordinatePlane )
0357     };
0358 
0359     /**
0360      * \brief Helper class for one dimension of data, e.g. for the rows in a data model,
0361      * or for the labels of an axis, or for the vertical lines in a grid.
0362      *
0363      * isCalculated specifies whether this dimension's values are calculated or counted.
0364      * (counted == "Item 1", "Item 2", "Item 3" ...)
0365      *
0366      * sequence is the GranularitySequence, as specified at for the respective
0367      * coordinate plane.
0368      *
0369      * Step width is an optional parameter, to be omitted (or set to Zero, resp.)
0370      * if the step width is unknown.
0371      *
0372      * The default c'tor just gets you counted values from 1..10, using step width 1,
0373      * used by the CartesianGrid, when showing an empty plane without any diagrams.
0374      */
0375     class DataDimension{
0376     public:
0377         DataDimension()
0378             : start( 1.0 )
0379             , end( 10.0 )
0380             , isCalculated( false )
0381             , calcMode( AbstractCoordinatePlane::Linear )
0382             , sequence( KChartEnums::GranularitySequence_10_20 )
0383             , stepWidth( 1.0 )
0384             , subStepWidth( 0.0 )
0385         {}
0386         DataDimension( qreal start_,
0387                        qreal end_,
0388                        bool isCalculated_,
0389                        AbstractCoordinatePlane::AxesCalcMode calcMode_,
0390                        KChartEnums::GranularitySequence sequence_,
0391                        qreal stepWidth_=0.0,
0392                        qreal subStepWidth_=0.0 )
0393             : start( start_ )
0394             , end( end_ )
0395             , isCalculated( isCalculated_ )
0396             , calcMode( calcMode_ )
0397             , sequence( sequence_ )
0398             , stepWidth( stepWidth_ )
0399             , subStepWidth( subStepWidth_ )
0400         {}
0401         /**
0402           * Returns the size of the distance,
0403           * equivalent to the width() (or height(), resp.) of a QRectF.
0404           *
0405           * Note that this value can be negative, e.g. indicating axis labels
0406           * going in reversed direction.
0407           */
0408         qreal distance() const
0409         {
0410             return end-start;
0411         }
0412 
0413         bool operator==( const DataDimension& r ) const
0414         {
0415             return
0416                 (start        == r.start) &&
0417                 (end          == r.end) &&
0418                 (sequence     == r.sequence) &&
0419                 (isCalculated == r.isCalculated) &&
0420                 (calcMode     == r.calcMode) &&
0421                 (stepWidth    == r.stepWidth) &&
0422                 (subStepWidth    == r.subStepWidth);
0423         }
0424 
0425         bool operator!=( const DataDimension& other ) const
0426         { return !operator==( other ); }
0427 
0428 
0429         qreal start;
0430         qreal end;
0431         bool  isCalculated;
0432         AbstractCoordinatePlane::AxesCalcMode calcMode;
0433         KChartEnums::GranularitySequence sequence;
0434         qreal stepWidth;
0435         qreal subStepWidth;
0436     };
0437 
0438 #if !defined(QT_NO_DEBUG_STREAM)
0439     QDebug operator<<( QDebug stream, const DataDimension& r );
0440 #endif
0441 
0442 }
0443 #endif