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