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