Warning, file /office/calligra/filters/libodf2/chart/Charting.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Sebastian Sauer <sebsauer@kdab.com>
0003  *  SPDX-FileCopyrightText: 2010 Carlos Licea <carlos@kdab.com>
0004  *  SPDX-FileCopyrightText: 2014 Inge Wallin <inge@lysator.liu.se>
0005  *
0006  *  SPDX-License-Identifier: LGPL-2.1-or-later
0007  */
0008 
0009 #ifndef CHARTING_H
0010 #define CHARTING_H
0011 
0012 #include <QString>
0013 #include <QRect>
0014 #include <QMap>
0015 #include <QHash>
0016 #include <QVector>
0017 #include <QColor>
0018 
0019 
0020 namespace KoChart
0021 {
0022   
0023 class Value
0024 {
0025  public:
0026     enum DataId {
0027     SeriesLegendOrTrendlineName = 0x00, ///< Referenced data specifies the series, legend entry, or trendline name. Error bars name MUST be empty.
0028     HorizontalValues = 0x01, ///< Referenced data specifies the values or horizontal values on bubble and scatter chart groups of the series and error bars.
0029     VerticalValues = 0x02, ///< Referenced data specifies the categories or vertical values on bubble and scatter chart groups of the series and error bars.
0030     BubbleSizeValues = 0x03 ///< Referenced data specifies the bubble size values of the series.
0031     };
0032     DataId m_dataId;
0033 
0034     enum DataType {
0035     AutoGeneratedName = 0x00, ///< The data source is a category (3) name, series name or bubble size that was automatically generated.
0036     TextOrValue = 0x01, ///< The data source is the text or value as specified by the formula field.
0037     CellRange = 0x02 ///< The data source is the value from a range of cells in a sheet specified by the formula field.
0038     };
0039     DataType m_type;
0040 
0041     bool m_isUnlinkedFormat; ///< false=data uses the number formatting of the referenced data, true=data uses the custom formatting specified via m_numberFormat.
0042     unsigned m_numberFormat; ///< specifies the number format to use for the data.
0043     QString m_formula; ///< the optional formula. could be for example "[Sheet1.$D$2:$F$2]"
0044 
0045     Value(DataId dataId, DataType type,
0046       const QString& formula = QString(),
0047       bool isUnlinkedFormat = false, unsigned numberFormat = 0)
0048     : m_dataId(dataId)
0049     , m_type(type)
0050     , m_isUnlinkedFormat(isUnlinkedFormat)
0051     , m_numberFormat(numberFormat)
0052     , m_formula(formula)
0053     {}
0054     virtual ~Value() {}
0055 };
0056 
0057 
0058 // ----------------------------------------------------------------
0059 //                             Formats
0060 
0061 
0062 class Format
0063 {
0064  public:
0065     Format() {}
0066     virtual ~Format() {}
0067 };
0068 
0069 class LineFormat : public Format
0070 {
0071  public:
0072     enum Style {
0073     Solid = 0x0000,
0074     Dash = 0x0001,
0075     Dot = 0x0002,
0076     DashDot = 0x0003,
0077     DashDotDot = 0x0004,
0078     None = 0x0005,
0079     DarkGrayPattern = 0x0006,
0080     MediumGrayPattern = 0x0007,
0081     LightGrayPattern = 0x0008
0082     };
0083 
0084     enum Thickness {
0085     Hairline = 0xFFFF,
0086     NarrowSingle = 0x0000,
0087     MediumDouble = 0x0001,
0088     WideTriple = 0x0002
0089     };
0090 
0091     Style     m_style;
0092     Thickness m_thickness;
0093 
0094     explicit LineFormat(const Style& style = None, const Thickness& thickness = Hairline)
0095     : Format()
0096     , m_style(style)
0097     , m_thickness(thickness)
0098     {} 
0099 };
0100     
0101  class PieFormat : public Format
0102  {
0103  public:
0104     int m_pcExplode; // from PieFormat
0105 
0106     explicit PieFormat(int pcExplode = 0)
0107     : Format()
0108     , m_pcExplode(pcExplode)
0109     {}
0110  };
0111     
0112  class AreaFormat : public Format
0113  {
0114  public:
0115     QColor m_foreground;
0116     QColor m_background;
0117     bool m_fill;
0118  
0119     explicit AreaFormat(const QColor &foreground = QColor(), const QColor &background = QColor(),
0120             bool fill = false)
0121     : Format()
0122     , m_foreground(foreground)
0123     , m_background(background)
0124     , m_fill(fill)
0125     {}
0126  };
0127 
0128 class Gradient
0129 {
0130  public:
0131     Gradient() { angle =  0.0; }
0132 
0133     class GradientStop
0134     {
0135     public:
0136     void reset()
0137     {
0138         position = 1.0;
0139         knownColorValue = QColor();
0140         tintVal = 0;
0141         satVal = 0;
0142         shadeVal = 0;
0143         referenceColor.clear();
0144     }
0145 
0146     qreal position;
0147     QColor knownColorValue;
0148     qreal tintVal;
0149     qreal satVal;
0150     qreal shadeVal;
0151     QString referenceColor;
0152     };
0153 
0154     QVector< GradientStop > gradientStops;
0155     qreal angle;
0156 };
0157 
0158 class Fill
0159 {
0160  public:        
0161     enum FillType {Blip, Gradient, Group, None, Pattern, Solid};
0162 
0163     Fill()
0164     : type(None)
0165     , valid(false)
0166     {}
0167 
0168     void setColor(const QColor& color){ solidColor = color; valid = true; type = Solid; }
0169     void setType(FillType type){ this->type = type; valid = true; }
0170 
0171     QColor solidColor;
0172     QString pixmapFile;
0173     KoChart::Gradient gradient;
0174     FillType type;
0175     bool valid;
0176 };
0177     
0178 class ShapeProperties
0179 {
0180  public:
0181     int lineWidth;
0182     Fill lineFill;
0183     Fill areaFill;
0184 };
0185 
0186 
0187 // ----------------------------------------------------------------
0188 //                         Chart types
0189 
0190 
0191 class ChartImpl
0192 {
0193  public:
0194     ChartImpl() {}
0195     virtual ~ChartImpl() {}
0196     virtual QByteArray name() const = 0;
0197 };
0198 
0199 class PieImpl : public ChartImpl
0200 {
0201  public:
0202     /// Starting angle of the first data point clockwise from the top of the circle.
0203     int m_anStart;
0204 
0205     explicit PieImpl(int anStart = 0)
0206     : ChartImpl()
0207     , m_anStart(anStart)
0208     {}
0209 
0210     QByteArray name() const override { return "circle"; }
0211 };
0212 
0213 class RingImpl : public PieImpl
0214 {
0215  public:
0216     /// Size of the center hole in a doughnut chart group as a percentage of the plot area size.
0217     int m_pcDonut;
0218 
0219     explicit RingImpl(int anStart = 0, int pcDonut = 0)
0220     : PieImpl(anStart)
0221     , m_pcDonut(pcDonut)
0222     {}
0223 
0224     QByteArray name() const override { return "ring"; }
0225 };
0226 
0227 class BarImpl : public ChartImpl
0228 {
0229  public:
0230     QByteArray name() const override { return "bar"; }
0231 };
0232     
0233 class LineImpl : public ChartImpl
0234 {
0235  public:
0236     QByteArray name() const override { return "line"; }
0237 };
0238     
0239 class RadarImpl : public ChartImpl
0240 {
0241  public:
0242     /// If true then the radar-chart is filled (a RadarArea chart), else not.
0243     bool m_filled;
0244 
0245     explicit RadarImpl(bool filled = false)
0246     : ChartImpl()
0247     , m_filled(filled)
0248     {}
0249 
0250     QByteArray name() const override { return m_filled ? "filled-radar" : "radar"; }
0251 };
0252 
0253 class AreaImpl : public ChartImpl
0254 {
0255  public:
0256     AreaImpl() : ChartImpl() {}
0257 
0258     QByteArray name() const override { return "area"; }
0259 };
0260 
0261 class StockImpl : public ChartImpl
0262 {
0263  public:
0264     StockImpl() : ChartImpl() {}
0265 
0266     QByteArray name() const override { return "stock"; }
0267 };
0268 
0269 class ScatterImpl : public ChartImpl
0270 {
0271  public:
0272     enum ScatterStyle { None, Line, LineMarker, Marker, Smooth, SmoothMarker };
0273     ScatterStyle style;
0274 
0275     ScatterImpl()
0276     : ChartImpl()
0277     , style(LineMarker)
0278     {}
0279 
0280     QByteArray name() const override { return "scatter"; }
0281 };
0282 
0283 class BubbleImpl : public ChartImpl
0284 {
0285  public:
0286     enum SizeType {
0287     Area = 0x0001, ///< The area of the data point represents the value.
0288     Width = 0x0002 ///< The width of the data point represents the value.
0289     };
0290     /// Specifies how the default size of the data points represents the value.
0291     SizeType m_sizeType;
0292 
0293     /// The size of the data points as a percentage of their default size. A
0294     /// value of 100 shows all the data points in their default size, as
0295     /// determined by the application.
0296     unsigned int m_sizeRatio;
0297 
0298     /// Specifies whether data points with negative values are shown.
0299     bool m_showNegativeBubbles;
0300 
0301     explicit BubbleImpl(SizeType sizeType = Area, unsigned int sizeRatio = 100,
0302             bool showNegativeBubbles = true)
0303     : ChartImpl()
0304     , m_sizeType(sizeType)
0305     , m_sizeRatio(sizeRatio)
0306     , m_showNegativeBubbles(showNegativeBubbles)
0307     {}
0308 
0309     QByteArray name() const override { return "bubble"; }
0310 };
0311 
0312 class SurfaceImpl : public ChartImpl
0313 {
0314  public:
0315     /// Specifies that the surface is either filled or a wireframe.
0316     bool m_fill;
0317 
0318     explicit SurfaceImpl(bool fill = false) : ChartImpl(), m_fill(fill) {}
0319 
0320     QByteArray name() const override { return "surface"; }
0321 };
0322 
0323 
0324 // ----------------------------------------------------------------
0325 //                 Objects within the chart
0326 
0327 
0328 class Obj
0329 {
0330  public:
0331     unsigned int m_mdTopLt;
0332     unsigned int m_mdBotRt;
0333     unsigned int m_x1;
0334     unsigned int m_y1;
0335     unsigned int m_x2;
0336     unsigned int m_y2;
0337     KoChart::AreaFormat *m_areaFormat;
0338 
0339     explicit Obj()
0340     : m_mdTopLt(0)
0341     , m_mdBotRt(0)
0342     , m_x1(0)
0343     , m_y1(0)
0344     , m_x2(0)
0345     , m_y2(0)
0346     , m_areaFormat(0)
0347     {}
0348     virtual ~Obj() { delete m_areaFormat; }
0349 };
0350 
0351 class Text : public Obj
0352 {
0353  public:
0354     QString m_text;
0355 
0356     explicit Text(const QString &text = QString())
0357     : Obj()
0358     , m_text(text)
0359     {}
0360     ~Text() override {}
0361 };
0362     
0363 class Axis : public Obj
0364 {
0365  public:
0366     enum Type {
0367     HorizontalValueAxis = 0x0000,
0368     VerticalValueAxis = 0x0001,
0369     SeriesAxis = 0x0002
0370     };
0371     Type m_type;
0372 
0373     class Gridline
0374     {
0375     public:
0376     LineFormat m_format;
0377     explicit Gridline(const LineFormat &format = LineFormat())
0378         : m_format(format)
0379     {}
0380     };
0381 
0382     Gridline m_majorGridlines;
0383     Gridline m_minorGridlines;
0384 
0385     LineFormat m_format;
0386 
0387     QString m_numberFormat;
0388 
0389     bool m_reversed;
0390     bool m_logarithmic;
0391 
0392     bool m_autoMinimum;
0393     bool m_autoMaximum;
0394     qreal m_minimum;
0395     qreal m_maximum;
0396 
0397     explicit Axis(Type type)
0398     : Obj()
0399     , m_type(type)
0400     , m_reversed(false)
0401     , m_logarithmic(false)
0402     , m_autoMinimum(true)
0403     , m_autoMaximum(true)
0404     , m_minimum(0)
0405     , m_maximum(0)
0406     {}
0407     ~Axis() override {}
0408 };
0409 
0410 class Cell
0411 {
0412  public:
0413     int m_column;
0414     int m_row;
0415     QString m_value;
0416     QString m_valueType;
0417 
0418     Cell(int columnIndex, int rowIndex)
0419     : m_column(columnIndex)
0420     , m_row(rowIndex)
0421     , m_valueType("string")
0422     {}
0423 };
0424 
0425 
0426 /// cell data representation of internal table
0427 class InternalTable
0428 {
0429  public:
0430     InternalTable()
0431     : m_maxRow(0)
0432     , m_maxColumn(0)
0433     {}
0434     ~InternalTable()
0435     {
0436     qDeleteAll(m_cells);
0437     }
0438 
0439     Cell* cell(int columnIndex, int rowIndex, bool autoCreate)
0440     {
0441     const uint maximumSpreadsheetColumns = 0x7FFF; // MSOOXML::maximumSpreadsheetColumns()
0442     const unsigned hashed = (rowIndex + 1) * maximumSpreadsheetColumns + columnIndex + 1;
0443 
0444     Cell* c = m_cells[hashed];
0445     if (!c && autoCreate) {
0446         c = new Cell(columnIndex, rowIndex);
0447         m_cells[hashed] = c;
0448 
0449         if (rowIndex > m_maxRow)
0450         m_maxRow = rowIndex;
0451         if (columnIndex > m_maxColumn)
0452         m_maxColumn = columnIndex;
0453         if (!m_maxCellsInRow.contains(rowIndex) || columnIndex > m_maxCellsInRow[rowIndex])
0454         m_maxCellsInRow[rowIndex] = columnIndex;
0455     }
0456 
0457     return c;
0458     }
0459 
0460     int maxCellsInRow(int rowIndex) const { return m_maxCellsInRow[rowIndex]; }
0461     int maxRow() const { return m_maxRow; }
0462     int maxColumn() const { return m_maxColumn; }
0463 
0464  private:
0465     int m_maxRow;
0466     int m_maxColumn;
0467     QHash<unsigned, Cell*> m_cells;
0468     QHash<int, int> m_maxCellsInRow;
0469 };
0470 
0471 
0472 /// Different types of markers.
0473 enum MarkerType {
0474     NoMarker,
0475     AutoMarker,
0476     SquareMarker,
0477     DiamondMarker,
0478     StarMarker,
0479     DotMarker,
0480     DashMarker,
0481     PlusMarker,
0482     CircleMarker,
0483     SymbolXMarker,
0484     TriangleMarker
0485     // TODO fill the missing marker types in
0486 };
0487 
0488 class DataPoint : public Obj
0489 {
0490  public:
0491 };
0492 
0493 class Series : public Obj
0494 {
0495  public:
0496     /// the type of data in categories, or horizontal values on bubble and
0497     /// scatter chart groups, in the series. MUST be either 0x0001=numeric or
0498     /// 0x0003=text.
0499     int m_dataTypeX;
0500 
0501     /// the count of categories (3), or horizontal values on bubble and
0502     /// scatter chart groups, in the series.
0503     int m_countXValues;
0504 
0505     /// the count of values, or vertical values on bubble and scatter chart
0506     /// groups, in the series.
0507     int m_countYValues;
0508 
0509     /// the count of bubble size values in the series.
0510     int m_countBubbleSizeValues;
0511 
0512     /// determines if the data values are shown in raw values as labels
0513     bool m_showDataLabelValues;
0514 
0515     /// determines if the data values are shown in percent as labels or not
0516     bool m_showDataLabelPercent;
0517 
0518     /// determines if the category data is shown as labels or not
0519     bool m_showDataLabelCategory;
0520 
0521     /// determines if the name of the series is shown as labels
0522     bool m_showDataLabelSeries;
0523 
0524     /// range that contains the values that should be visualized by the dataSeries.
0525     QString m_valuesCellRangeAddress;
0526 
0527     /// Ranges that contain the values that should be visualized by the dataSeries.
0528     QStringList m_domainValuesCellRangeAddress;
0529 
0530     /// The referenced values used in the chart
0531     QMap<Value::DataId, Value*> m_datasetValue;
0532 
0533     /// The data-points in the series.
0534     QList<DataPoint*> m_dataPoints;
0535 
0536     /// The formatting for the referenced values
0537     QList<Format*> m_datasetFormat;
0538 
0539     /// List of text records attached to the series.
0540     QList<Text*> m_texts;
0541 
0542     /// range that contains label
0543     QString m_labelCell;
0544 
0545     /// marker type
0546     MarkerType m_markerType;
0547     ShapeProperties* spPr;
0548     QString m_numberFormat;
0549 
0550     explicit Series()
0551     : Obj()
0552     , m_dataTypeX(0)
0553     , m_countXValues(0)
0554     , m_countYValues(0)
0555     , m_countBubbleSizeValues(0)
0556     , m_showDataLabelValues(false)
0557     , m_showDataLabelPercent(false)
0558     , m_showDataLabelCategory(false)
0559     , m_showDataLabelSeries(false)
0560     , m_markerType(NoMarker)
0561     ,spPr(0)
0562     {}
0563     ~Series() override
0564     {
0565     qDeleteAll(m_datasetValue);
0566     qDeleteAll(m_dataPoints);
0567     qDeleteAll(m_datasetFormat);
0568 
0569     delete spPr;
0570     }
0571 };
0572 
0573 class PlotArea : public Obj
0574 {
0575  public:
0576     explicit PlotArea()
0577     : Obj()
0578     {}
0579     ~PlotArea() override {}
0580 };
0581 
0582 class Legend : public Obj
0583 {
0584  public:
0585     explicit Legend() : Obj() {}
0586     ~Legend() override {}
0587 };
0588 
0589 /// The main charting class that represents a single chart.
0590 class Chart : public Obj
0591 {
0592  public:
0593     QString m_sheetName;
0594         
0595     /// If true then the chart is a 3d chart else the chart is 2d.
0596     bool m_is3d;
0597 
0598     /// Specifies a counter clockwise rotation of a polar coordinate in a
0599     /// circle, ring or polar chart.
0600     int m_angleOffset;
0601 
0602     //int anRot, anElv, pcDist;
0603 
0604     /// Margins around the chart object
0605     int m_leftMargin;
0606     int m_topMargin;
0607     int m_rightMargin;
0608     int m_bottomMargin;
0609 
0610     /// List of series
0611     QList<Series*> m_series;
0612 
0613     /// List of text records attached to the chart.
0614     QList<Text*> m_texts;
0615 
0616     /// Range of all referenced cells.
0617     QRect m_cellRangeAddress;
0618 
0619     /// Range that contains the vertical values (the categories) for the plot-area.
0620     QString m_verticalCellRangeAddress;
0621 
0622     // The ChartTitle
0623     QString m_title;
0624 
0625     /// The more concrete chart implementation like e.g. a PieImpl for a pie chart.
0626     ChartImpl *m_impl;
0627 
0628     /// The plot-area.
0629     PlotArea *m_plotArea;
0630 
0631     /// The legend.
0632     Legend *m_legend;
0633 
0634     /// List of defined axes.
0635     QList<Axis*> m_axes;
0636 
0637     /// Whether the chart is vertical or not.
0638     bool m_transpose;
0639 
0640     /// Whether the chart is stacked or not.
0641     bool m_stacked;
0642 
0643     /// Whether the chart is percentage or not.
0644     bool m_f100;
0645 
0646     /// style for colors fills, line types, etc
0647     int m_style;
0648 
0649     Gradient* m_fillGradient;
0650     Gradient* m_plotAreaFillGradient;
0651     MarkerType m_markerType;
0652     bool m_showLines;
0653     qreal m_textSize;
0654 
0655     // the chart's internal table
0656     InternalTable m_internalTable;
0657 
0658     explicit Chart()
0659     : Obj()
0660     , m_is3d(false)
0661     , m_angleOffset(0)
0662     , m_leftMargin(0)
0663     , m_topMargin(0)
0664     , m_rightMargin(0)
0665     , m_bottomMargin(0)
0666     , m_impl(0)
0667     , m_plotArea(0)
0668     , m_legend(0)
0669     , m_transpose(false)
0670     , m_stacked(false)
0671     , m_f100(false)
0672     , m_style(2)
0673     , m_fillGradient(0)
0674     , m_plotAreaFillGradient(0)
0675     , m_markerType(NoMarker)
0676     , m_showLines(false)
0677     , m_textSize(10)
0678     {
0679     m_x1 = m_y1 = m_x2 = m_y2 = -1; // -1 means autoposition/autosize
0680     }
0681     ~Chart() override
0682     {
0683     qDeleteAll(m_axes);
0684     qDeleteAll(m_series);
0685     qDeleteAll(m_texts);
0686     delete m_impl;
0687     delete m_plotArea;
0688     delete m_legend;
0689     delete m_fillGradient;
0690     delete m_plotAreaFillGradient;
0691     }
0692         
0693     void addRange(const QRect& range)
0694     {
0695     if (range.isValid()) {
0696         if (m_cellRangeAddress.isValid()) {
0697         if (range.left() < m_cellRangeAddress.left())
0698             m_cellRangeAddress.setLeft(range.left());
0699         if (range.top() < m_cellRangeAddress.top())
0700             m_cellRangeAddress.setTop(range.top());
0701         if (range.right() > m_cellRangeAddress.right())
0702             m_cellRangeAddress.setRight(range.right());
0703         if (range.bottom() > m_cellRangeAddress.bottom())
0704             m_cellRangeAddress.setBottom(range.bottom());
0705         } else {
0706         m_cellRangeAddress = range;
0707         }
0708     }
0709     }
0710 };
0711 
0712 } // namespace Charting
0713 
0714 #endif