##// END OF EJS Templates
Additional fixes to label localization...
Miikka Heikkinen -
r2709:682630e62d58
parent child
Show More
@@ -1,400 +1,402
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2014 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "chartaxiselement_p.h"
22 22 #include "qabstractaxis_p.h"
23 23 #include "chartpresenter_p.h"
24 24 #include "abstractchartlayout_p.h"
25 25 #include <qmath.h>
26 26 #include <QDateTime>
27 27 #include <QTextDocument>
28 28
29 29 QTCOMMERCIALCHART_BEGIN_NAMESPACE
30 30
31 31 static const char *labelFormatMatchString = "%[\\-\\+#\\s\\d\\.lhjztL]*([dicuoxfegXFEG])";
32 static const char *labelFormatMatchLocalizedString = "^([^%]*)%\\.?(\\d)*([defgEG])(.*)$";
32 static const char *labelFormatMatchLocalizedString = "^([^%]*)%\\.?(\\d)*([defgiEG])(.*)$";
33 33 static QRegExp *labelFormatMatcher = 0;
34 34 static QRegExp *labelFormatMatcherLocalized = 0;
35 35 class StaticLabelFormatMatcherDeleter
36 36 {
37 37 public:
38 38 StaticLabelFormatMatcherDeleter() {}
39 39 ~StaticLabelFormatMatcherDeleter() {
40 40 delete labelFormatMatcher;
41 41 delete labelFormatMatcherLocalized;
42 42 }
43 43 };
44 44 static StaticLabelFormatMatcherDeleter staticLabelFormatMatcherDeleter;
45 45
46 46 ChartAxisElement::ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
47 47 : ChartElement(item),
48 48 m_axis(axis),
49 49 m_animation(0),
50 50 m_grid(new QGraphicsItemGroup(item)),
51 51 m_arrow(new QGraphicsItemGroup(item)),
52 52 m_shades(new QGraphicsItemGroup(item)),
53 53 m_labels(new QGraphicsItemGroup(item)),
54 54 m_title(new QGraphicsTextItem(item)),
55 55 m_intervalAxis(intervalAxis)
56 56
57 57 {
58 58 //initial initialization
59 59 m_arrow->setHandlesChildEvents(false);
60 60 m_arrow->setZValue(ChartPresenter::AxisZValue);
61 61 m_labels->setZValue(ChartPresenter::AxisZValue);
62 62 m_shades->setZValue(ChartPresenter::ShadesZValue);
63 63 m_grid->setZValue(ChartPresenter::GridZValue);
64 64 m_title->setZValue(ChartPresenter::GridZValue);
65 65 m_title->document()->setDocumentMargin(ChartPresenter::textMargin());
66 66 handleVisibleChanged(axis->isVisible());
67 67 connectSlots();
68 68
69 69 setFlag(QGraphicsItem::ItemHasNoContents, true);
70 70 }
71 71
72 72 ChartAxisElement::~ChartAxisElement()
73 73 {
74 74 }
75 75
76 76 void ChartAxisElement::connectSlots()
77 77 {
78 78 QObject::connect(axis(), SIGNAL(visibleChanged(bool)), this, SLOT(handleVisibleChanged(bool)));
79 79 QObject::connect(axis(), SIGNAL(lineVisibleChanged(bool)), this, SLOT(handleArrowVisibleChanged(bool)));
80 80 QObject::connect(axis(), SIGNAL(gridVisibleChanged(bool)), this, SLOT(handleGridVisibleChanged(bool)));
81 81 QObject::connect(axis(), SIGNAL(labelsVisibleChanged(bool)), this, SLOT(handleLabelsVisibleChanged(bool)));
82 82 QObject::connect(axis(), SIGNAL(shadesVisibleChanged(bool)), this, SLOT(handleShadesVisibleChanged(bool)));
83 83 QObject::connect(axis(), SIGNAL(labelsAngleChanged(int)), this, SLOT(handleLabelsAngleChanged(int)));
84 84 QObject::connect(axis(), SIGNAL(linePenChanged(const QPen&)), this, SLOT(handleArrowPenChanged(const QPen&)));
85 85 QObject::connect(axis(), SIGNAL(labelsPenChanged(const QPen&)), this, SLOT(handleLabelsPenChanged(const QPen&)));
86 86 QObject::connect(axis(), SIGNAL(labelsBrushChanged(const QBrush&)), this, SLOT(handleLabelsBrushChanged(const QBrush&)));
87 87 QObject::connect(axis(), SIGNAL(labelsFontChanged(const QFont&)), this, SLOT(handleLabelsFontChanged(const QFont&)));
88 88 QObject::connect(axis(), SIGNAL(gridLinePenChanged(const QPen&)), this, SLOT(handleGridPenChanged(const QPen&)));
89 89 QObject::connect(axis(), SIGNAL(shadesPenChanged(const QPen&)), this, SLOT(handleShadesPenChanged(const QPen&)));
90 90 QObject::connect(axis(), SIGNAL(shadesBrushChanged(const QBrush&)), this, SLOT(handleShadesBrushChanged(const QBrush&)));
91 91 QObject::connect(axis(), SIGNAL(titleTextChanged(const QString&)), this, SLOT(handleTitleTextChanged(const QString&)));
92 92 QObject::connect(axis(), SIGNAL(titleFontChanged(const QFont&)), this, SLOT(handleTitleFontChanged(const QFont&)));
93 93 QObject::connect(axis(), SIGNAL(titlePenChanged(const QPen&)), this, SLOT(handleTitlePenChanged(const QPen&)));
94 94 QObject::connect(axis(), SIGNAL(titleBrushChanged(const QBrush&)), this, SLOT(handleTitleBrushChanged(const QBrush&)));
95 95 QObject::connect(axis(), SIGNAL(titleVisibleChanged(bool)), this, SLOT(handleTitleVisibleChanged(bool)));
96 96 QObject::connect(axis()->d_ptr.data(), SIGNAL(rangeChanged(qreal, qreal)), this, SLOT(handleRangeChanged(qreal, qreal)));
97 97 }
98 98
99 99 void ChartAxisElement::handleArrowVisibleChanged(bool visible)
100 100 {
101 101 m_arrow->setVisible(visible);
102 102 }
103 103
104 104 void ChartAxisElement::handleGridVisibleChanged(bool visible)
105 105 {
106 106 m_grid->setVisible(visible);
107 107 }
108 108
109 109 void ChartAxisElement::handleLabelsVisibleChanged(bool visible)
110 110 {
111 111 QGraphicsLayoutItem::updateGeometry();
112 112 presenter()->layout()->invalidate();
113 113 m_labels->setVisible(visible);
114 114 }
115 115
116 116 void ChartAxisElement::handleShadesVisibleChanged(bool visible)
117 117 {
118 118 m_shades->setVisible(visible);
119 119 }
120 120
121 121 void ChartAxisElement::handleTitleVisibleChanged(bool visible)
122 122 {
123 123 QGraphicsLayoutItem::updateGeometry();
124 124 presenter()->layout()->invalidate();
125 125 m_title->setVisible(visible);
126 126 }
127 127
128 128 void ChartAxisElement::handleLabelsAngleChanged(int angle)
129 129 {
130 130 foreach (QGraphicsItem *item, m_labels->childItems())
131 131 item->setRotation(angle);
132 132
133 133 QGraphicsLayoutItem::updateGeometry();
134 134 presenter()->layout()->invalidate();
135 135 }
136 136
137 137 void ChartAxisElement::handleLabelsPenChanged(const QPen &pen)
138 138 {
139 139 Q_UNUSED(pen)
140 140 }
141 141
142 142 void ChartAxisElement::handleLabelsBrushChanged(const QBrush &brush)
143 143 {
144 144 foreach (QGraphicsItem *item, m_labels->childItems())
145 145 static_cast<QGraphicsTextItem *>(item)->setDefaultTextColor(brush.color());
146 146 }
147 147
148 148 void ChartAxisElement::handleLabelsFontChanged(const QFont &font)
149 149 {
150 150 foreach (QGraphicsItem *item, m_labels->childItems())
151 151 static_cast<QGraphicsTextItem *>(item)->setFont(font);
152 152 QGraphicsLayoutItem::updateGeometry();
153 153 presenter()->layout()->invalidate();
154 154 }
155 155
156 156 void ChartAxisElement::handleTitleTextChanged(const QString &title)
157 157 {
158 158 QGraphicsLayoutItem::updateGeometry();
159 159 presenter()->layout()->invalidate();
160 160 if (title.isEmpty() || !m_title->isVisible())
161 161 m_title->setHtml(title);
162 162 }
163 163
164 164 void ChartAxisElement::handleTitlePenChanged(const QPen &pen)
165 165 {
166 166 Q_UNUSED(pen)
167 167 }
168 168
169 169 void ChartAxisElement::handleTitleBrushChanged(const QBrush &brush)
170 170 {
171 171 m_title->setDefaultTextColor(brush.color());
172 172 }
173 173
174 174 void ChartAxisElement::handleTitleFontChanged(const QFont &font)
175 175 {
176 176 if (m_title->font() != font) {
177 177 m_title->setFont(font);
178 178 QGraphicsLayoutItem::updateGeometry();
179 179 presenter()->layout()->invalidate();
180 180 }
181 181 }
182 182
183 183 void ChartAxisElement::handleVisibleChanged(bool visible)
184 184 {
185 185 setVisible(visible);
186 186 if (!visible) {
187 187 m_grid->setVisible(visible);
188 188 m_arrow->setVisible(visible);
189 189 m_shades->setVisible(visible);
190 190 m_labels->setVisible(visible);
191 191 m_title->setVisible(visible);
192 192 } else {
193 193 m_grid->setVisible(axis()->isGridLineVisible());
194 194 m_arrow->setVisible(axis()->isLineVisible());
195 195 m_shades->setVisible(axis()->shadesVisible());
196 196 m_labels->setVisible(axis()->labelsVisible());
197 197 m_title->setVisible(axis()->isTitleVisible());
198 198 }
199 199
200 200 if (presenter()) presenter()->layout()->invalidate();
201 201 }
202 202
203 203 void ChartAxisElement::handleRangeChanged(qreal min, qreal max)
204 204 {
205 205 Q_UNUSED(min);
206 206 Q_UNUSED(max);
207 207
208 208 if (!isEmpty()) {
209 209 QVector<qreal> layout = calculateLayout();
210 210 updateLayout(layout);
211 211 QSizeF before = effectiveSizeHint(Qt::PreferredSize);
212 212 QSizeF after = sizeHint(Qt::PreferredSize);
213 213
214 214 if (before != after) {
215 215 QGraphicsLayoutItem::updateGeometry();
216 216 // We don't want to call invalidate on layout, since it will change minimum size of
217 217 // component, which we would like to avoid since it causes nasty flips when scrolling
218 218 // or zooming, instead recalculate layout and use plotArea for extra space.
219 219 presenter()->layout()->setGeometry(presenter()->layout()->geometry());
220 220 }
221 221 }
222 222 }
223 223
224 224 bool ChartAxisElement::isEmpty()
225 225 {
226 226 return axisGeometry().isEmpty()
227 227 || gridGeometry().isEmpty()
228 228 || qFuzzyCompare(min(), max());
229 229 }
230 230
231 231 qreal ChartAxisElement::min() const
232 232 {
233 233 return m_axis->d_ptr->min();
234 234 }
235 235
236 236 qreal ChartAxisElement::max() const
237 237 {
238 238 return m_axis->d_ptr->max();
239 239 }
240 240
241 241 QString ChartAxisElement::formatLabel(const QString &formatSpec, const QByteArray &array,
242 242 qreal value, int precision, const QString &preStr,
243 243 const QString &postStr) const
244 244 {
245 245 QString retVal;
246 246 if (!formatSpec.isEmpty()) {
247 247 if (formatSpec.at(0) == QLatin1Char('d')
248 248 || formatSpec.at(0) == QLatin1Char('i')
249 249 || formatSpec.at(0) == QLatin1Char('c')) {
250 250 if (presenter()->localizeNumbers())
251 251 retVal = preStr + presenter()->locale().toString(qint64(value)) + postStr;
252 252 else
253 253 retVal = QString().sprintf(array, qint64(value));
254 254 } else if (formatSpec.at(0) == QLatin1Char('u')
255 255 || formatSpec.at(0) == QLatin1Char('o')
256 256 || formatSpec.at(0) == QLatin1Char('x')
257 257 || formatSpec.at(0) == QLatin1Char('X')) {
258 258 // These formats are not supported by localized numbers
259 259 retVal = QString().sprintf(array, quint64(value));
260 260 } else if (formatSpec.at(0) == QLatin1Char('f')
261 261 || formatSpec.at(0) == QLatin1Char('F')
262 262 || formatSpec.at(0) == QLatin1Char('e')
263 263 || formatSpec.at(0) == QLatin1Char('E')
264 264 || formatSpec.at(0) == QLatin1Char('g')
265 265 || formatSpec.at(0) == QLatin1Char('G')) {
266 266 if (presenter()->localizeNumbers()) {
267 267 retVal = preStr
268 268 + presenter()->locale().toString(value, formatSpec.at(0).toLatin1(),
269 269 precision)
270 270 + postStr;
271 271 } else {
272 272 retVal = QString().sprintf(array, value);
273 273 }
274 274 }
275 275 }
276 276 return retVal;
277 277 }
278 278
279 279 QStringList ChartAxisElement::createValueLabels(qreal min, qreal max, int ticks,
280 280 const QString &format) const
281 281 {
282 282 QStringList labels;
283 283
284 284 if (max <= min || ticks < 1)
285 285 return labels;
286 286
287 287 if (format.isNull()) {
288 288 int n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0) + 1;
289 289 for (int i = 0; i < ticks; i++) {
290 290 qreal value = min + (i * (max - min) / (ticks - 1));
291 291 labels << presenter()->numberToString(value, 'f', n);
292 292 }
293 293 } else {
294 294 QByteArray array = format.toLatin1();
295 295 QString formatSpec;
296 296 QString preStr;
297 297 QString postStr;
298 int precision = 0;
298 int precision = 6; // Six is the default precision in Qt API
299 299 if (presenter()->localizeNumbers()) {
300 300 if (!labelFormatMatcherLocalized)
301 301 labelFormatMatcherLocalized = new QRegExp(labelFormatMatchLocalizedString);
302 302 if (labelFormatMatcherLocalized->indexIn(format, 0) != -1) {
303 303 preStr = labelFormatMatcherLocalized->cap(1);
304 precision = labelFormatMatcherLocalized->cap(2).toInt();
304 if (!labelFormatMatcherLocalized->cap(2).isEmpty())
305 precision = labelFormatMatcherLocalized->cap(2).toInt();
305 306 formatSpec = labelFormatMatcherLocalized->cap(3);
306 307 postStr = labelFormatMatcherLocalized->cap(4);
307 308 }
308 309 } else {
309 310 if (!labelFormatMatcher)
310 311 labelFormatMatcher = new QRegExp(labelFormatMatchString);
311 312 if (labelFormatMatcher->indexIn(format, 0) != -1)
312 313 formatSpec = labelFormatMatcher->cap(1);
313 314 }
314 315 for (int i = 0; i < ticks; i++) {
315 316 qreal value = min + (i * (max - min) / (ticks - 1));
316 317 labels << formatLabel(formatSpec, array, value, precision, preStr, postStr);
317 318 }
318 319 }
319 320
320 321 return labels;
321 322 }
322 323
323 324 QStringList ChartAxisElement::createLogValueLabels(qreal min, qreal max, qreal base, int ticks,
324 325 const QString &format) const
325 326 {
326 327 QStringList labels;
327 328
328 329 if (max <= min || ticks < 1)
329 330 return labels;
330 331
331 332 int firstTick;
332 333 if (base > 1)
333 334 firstTick = ceil(log10(min) / log10(base));
334 335 else
335 336 firstTick = ceil(log10(max) / log10(base));
336 337
337 338 if (format.isNull()) {
338 339 int n = 0;
339 340 if (ticks > 1)
340 341 n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0);
341 342 n++;
342 343 for (int i = firstTick; i < ticks + firstTick; i++) {
343 344 qreal value = qPow(base, i);
344 345 labels << presenter()->numberToString(value, 'f', n);
345 346 }
346 347 } else {
347 348 QByteArray array = format.toLatin1();
348 349 QString formatSpec;
349 350 QString preStr;
350 351 QString postStr;
351 int precision = 0;
352 int precision = 6; // Six is the default precision in Qt API
352 353 if (presenter()->localizeNumbers()) {
353 354 if (!labelFormatMatcherLocalized)
354 355 labelFormatMatcherLocalized = new QRegExp(labelFormatMatchLocalizedString);
355 356 if (labelFormatMatcherLocalized->indexIn(format, 0) != -1) {
356 357 preStr = labelFormatMatcherLocalized->cap(1);
357 precision = labelFormatMatcherLocalized->cap(2).toInt();
358 if (!labelFormatMatcherLocalized->cap(2).isEmpty())
359 precision = labelFormatMatcherLocalized->cap(2).toInt();
358 360 formatSpec = labelFormatMatcherLocalized->cap(3);
359 361 postStr = labelFormatMatcherLocalized->cap(4);
360 362 }
361 363 } else {
362 364 if (!labelFormatMatcher)
363 365 labelFormatMatcher = new QRegExp(labelFormatMatchString);
364 366 if (labelFormatMatcher->indexIn(format, 0) != -1)
365 367 formatSpec = labelFormatMatcher->cap(1);
366 368 }
367 369 for (int i = firstTick; i < ticks + firstTick; i++) {
368 370 qreal value = qPow(base, i);
369 371 labels << formatLabel(formatSpec, array, value, precision, preStr, postStr);
370 372 }
371 373 }
372 374
373 375 return labels;
374 376 }
375 377
376 378 QStringList ChartAxisElement::createDateTimeLabels(qreal min, qreal max,int ticks,
377 379 const QString &format) const
378 380 {
379 381 QStringList labels;
380 382
381 383 if (max <= min || ticks < 1)
382 384 return labels;
383 385
384 386 int n = qMax(int(-floor(log10((max - min) / (ticks - 1)))), 0);
385 387 n++;
386 388 for (int i = 0; i < ticks; i++) {
387 389 qreal value = min + (i * (max - min) / (ticks - 1));
388 390 labels << presenter()->locale().toString(QDateTime::fromMSecsSinceEpoch(value), format);
389 391 }
390 392 return labels;
391 393 }
392 394
393 395 void ChartAxisElement::axisSelected()
394 396 {
395 397 emit clicked();
396 398 }
397 399
398 400 #include "moc_chartaxiselement_p.cpp"
399 401
400 402 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,451 +1,451
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2014 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "qvalueaxis.h"
22 22 #include "qvalueaxis_p.h"
23 23 #include "chartvalueaxisx_p.h"
24 24 #include "chartvalueaxisy_p.h"
25 25 #include "abstractdomain_p.h"
26 26 #include "polarchartvalueaxisangular_p.h"
27 27 #include "polarchartvalueaxisradial_p.h"
28 28 #include "chartdataset_p.h"
29 29 #include "chartpresenter_p.h"
30 30 #include "charttheme_p.h"
31 31
32 32
33 33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
34 34 /*!
35 35 \class QValueAxis
36 36 \inmodule Qt Charts
37 37 \brief The QValueAxis class is used for manipulating chart's axis.
38 38 \mainclass
39 39
40 40 ValueAxis can be setup to show axis line with tick marks, grid lines and shades.
41 41 Values of axis are drawn to position of ticks.
42 42
43 43 Example code on how to use QValueAxis.
44 44 \code
45 45 QChartView *chartView = new QChartView;
46 46 QLineSeries *series = new QLineSeries;
47 47 // ...
48 48 chartView->chart()->addSeries(series);
49 49
50 50 QValueAxis *axisX = new QValueAxis;
51 51 axisX->setRange(10, 20.5);
52 52 axisX->setTickCount(10);
53 53 axisX->setLabelFormat("%.2f");
54 54 chartView->chart()->setAxisX(axisX, series);
55 55 \endcode
56 56 */
57 57 #ifdef QDOC_QT5
58 58 /*!
59 59 \qmltype ValueAxis
60 60 \instantiates QValueAxis
61 61 \inqmlmodule QtCommercial.Chart
62 62
63 63 \include doc/src/valueaxis.qdocinc
64 64 */
65 65 #else
66 66 /*!
67 67 \qmlclass ValueAxis QValueAxis
68 68
69 69 \include ../doc/src/valueaxis.qdocinc
70 70 */
71 71 #endif
72 72
73 73 /*!
74 74 \property QValueAxis::min
75 75 Defines the minimum value on the axis.
76 76 When setting this property the max is adjusted if necessary, to ensure that the range remains valid.
77 77 */
78 78 /*!
79 79 \qmlproperty real ValueAxis::min
80 80 Defines the minimum value on the axis.
81 81 When setting this property the max is adjusted if necessary, to ensure that the range remains valid.
82 82 */
83 83
84 84 /*!
85 85 \property QValueAxis::max
86 86 Defines the maximum value on the axis.
87 87 When setting this property the min is adjusted if necessary, to ensure that the range remains valid.
88 88 */
89 89 /*!
90 90 \qmlproperty real ValueAxis::max
91 91 Defines the maximum value on the axis.
92 92 When setting this property the min is adjusted if necessary, to ensure that the range remains valid.
93 93 */
94 94
95 95 /*!
96 96 \property QValueAxis::tickCount
97 97 Defines the number of ticks on the axis. This indicates how many grid lines are draw on the chart.
98 98 The default value is 5, and it can not be below 2.
99 99 */
100 100 /*!
101 101 \qmlproperty real ValueAxis::tickCount
102 102 Defines the number of ticks on the axis. This indicates how many grid lines are draw on the chart.
103 103 The default value is 5, and it can not be below 2.
104 104 */
105 105
106 106 /*!
107 107 \property QValueAxis::labelFormat
108 108 Defines the label format of the axis.
109 109 Supported specifiers are: d, i, o, x, X, f, F, e, E, g, G, and c.
110 110 See QString::sprintf() for additional details.
111 111
112 112 If the QChart::localizeNumbers is \c{true}, the supported specifiers are limited to: d, e, E, f,
113 g, and G. Also, only the precision modifier is supported. The rest of the formatting comes from
113 g, G, and i. Also, only the precision modifier is supported. The rest of the formatting comes from
114 114 the default QLocale of the application.
115 115 */
116 116 /*!
117 117 \qmlproperty real ValueAxis::labelFormat
118 118 Defines the label format of the axis.
119 119 Supported specifiers are: d, i, o, x, X, f, F, e, E, g, G, and c.
120 120 See QString::sprintf() for additional details.
121 121
122 122 If the ChartView::localizeNumbers is \c{true}, the supported specifiers are limited to: d, e, E, f,
123 g, and G. Also, only the precision modifier is supported. The rest of the formatting comes from
123 g, G, and i. Also, only the precision modifier is supported. The rest of the formatting comes from
124 124 the default QLocale of the application.
125 125 */
126 126
127 127 /*!
128 128 \fn void QValueAxis::minChanged(qreal min)
129 129 Axis emits signal when \a min of axis has changed.
130 130 */
131 131 /*!
132 132 \qmlsignal ValueAxis::onMinChanged(real min)
133 133 Axis emits signal when \a min of axis has changed.
134 134 */
135 135
136 136 /*!
137 137 \fn void QValueAxis::maxChanged(qreal max)
138 138 Axis emits signal when \a max of axis has changed.
139 139 */
140 140 /*!
141 141 \qmlsignal ValueAxis::onMaxChanged(real max)
142 142 Axis emits signal when \a max of axis has changed.
143 143 */
144 144
145 145 /*!
146 146 \fn void QValueAxis::tickCountChanged(int tickCount)
147 147 Axis emits signal when \a tickCount of axis has changed.
148 148 */
149 149 /*!
150 150 \qmlsignal ValueAxis::tickCountChanged(int tickCount)
151 151 Axis emits signal when \a tickCount of axis has changed.
152 152 */
153 153
154 154 /*!
155 155 \fn void QValueAxis::rangeChanged(qreal min, qreal max)
156 156 Axis emits signal when \a min or \a max of axis has changed.
157 157 */
158 158
159 159 /*!
160 160 \fn void QValueAxis::labelFormatChanged(const QString &format)
161 161 Axis emits signal when \a format of axis labels has changed.
162 162 */
163 163 /*!
164 164 \qmlsignal ValueAxis::labelFormatChanged(const QString &format)
165 165 Axis emits signal when \a format of axis labels has changed.
166 166 */
167 167
168 168 /*!
169 169 \property QValueAxis::niceNumbersEnabled
170 170 \obsolete
171 171 Using this function can lead to unexpected behavior. Use applyNiceNumbers() instead.
172 172 */
173 173
174 174 /*!
175 175 \qmlproperty bool ValueAxis::niceNumbersEnabled
176 176 Deprecated; Using this function can lead to unexpected behavior. Use applyNiceNumbers() instead.
177 177 */
178 178
179 179 /*!
180 180 Constructs an axis object which is a child of \a parent.
181 181 */
182 182 QValueAxis::QValueAxis(QObject *parent) :
183 183 QAbstractAxis(*new QValueAxisPrivate(this), parent)
184 184 {
185 185
186 186 }
187 187
188 188 /*!
189 189 \internal
190 190 */
191 191 QValueAxis::QValueAxis(QValueAxisPrivate &d, QObject *parent)
192 192 : QAbstractAxis(d, parent)
193 193 {
194 194
195 195 }
196 196
197 197 /*!
198 198 Destroys the object
199 199 */
200 200 QValueAxis::~QValueAxis()
201 201 {
202 202 Q_D(QValueAxis);
203 203 if (d->m_chart)
204 204 d->m_chart->removeAxis(this);
205 205 }
206 206
207 207 void QValueAxis::setMin(qreal min)
208 208 {
209 209 Q_D(QValueAxis);
210 210 setRange(min, qMax(d->m_max, min));
211 211 }
212 212
213 213 qreal QValueAxis::min() const
214 214 {
215 215 Q_D(const QValueAxis);
216 216 return d->m_min;
217 217 }
218 218
219 219 void QValueAxis::setMax(qreal max)
220 220 {
221 221 Q_D(QValueAxis);
222 222 setRange(qMin(d->m_min, max), max);
223 223 }
224 224
225 225 qreal QValueAxis::max() const
226 226 {
227 227 Q_D(const QValueAxis);
228 228 return d->m_max;
229 229 }
230 230
231 231 /*!
232 232 Sets range from \a min to \a max on the axis.
233 233 If min is greater than max then this function returns without making any changes.
234 234 */
235 235 void QValueAxis::setRange(qreal min, qreal max)
236 236 {
237 237 Q_D(QValueAxis);
238 238 d->setRange(min,max);
239 239 }
240 240
241 241 void QValueAxis::setTickCount(int count)
242 242 {
243 243 Q_D(QValueAxis);
244 244 if (d->m_tickCount != count && count >= 2) {
245 245 d->m_tickCount = count;
246 246 emit tickCountChanged(count);
247 247 }
248 248 }
249 249
250 250 int QValueAxis::tickCount() const
251 251 {
252 252 Q_D(const QValueAxis);
253 253 return d->m_tickCount;
254 254 }
255 255
256 256 void QValueAxis::setNiceNumbersEnabled(bool enable)
257 257 {
258 258 Q_D(QValueAxis);
259 259 qWarning() << "Deprecated; Using this function can lead to unexpected behavior. " \
260 260 "Use applyNiceNumbers() instead.";
261 261 if(enable) {
262 262 QObject::connect(this,SIGNAL(rangeChanged(qreal,qreal)),this,SLOT(applyNiceNumbers()));
263 263 QObject::connect(this,SIGNAL(tickCountChanged(int)),this,SLOT(applyNiceNumbers()));
264 264 applyNiceNumbers();
265 265 }
266 266 else {
267 267 QObject::disconnect(this,SIGNAL(rangeChanged(qreal,qreal)),this,SLOT(applyNiceNumbers()));
268 268 QObject::disconnect(this,SIGNAL(tickCountChanged(int)),this,SLOT(applyNiceNumbers()));
269 269 }
270 270 d->m_niceNumbersEnabled=enable;
271 271 }
272 272
273 273 bool QValueAxis::niceNumbersEnabled() const
274 274 {
275 275 Q_D(const QValueAxis);
276 276 qWarning() << "Deprecated; Using this function can lead to unexpected behavior. " \
277 277 "Use applyNiceNumbers() instead.";
278 278 return d->m_niceNumbersEnabled;
279 279 }
280 280
281 281 void QValueAxis::setLabelFormat(const QString &format)
282 282 {
283 283 Q_D(QValueAxis);
284 284 d->m_format = format;
285 285 emit labelFormatChanged(format);
286 286 }
287 287
288 288 QString QValueAxis::labelFormat() const
289 289 {
290 290 Q_D(const QValueAxis);
291 291 return d->m_format;
292 292 }
293 293
294 294 /*!
295 295 Returns the type of the axis
296 296 */
297 297 QAbstractAxis::AxisType QValueAxis::type() const
298 298 {
299 299 return AxisTypeValue;
300 300 }
301 301
302 302 /*!
303 303 This method modifies range and number of ticks on the axis to look "nice". Algorithm considers numbers that
304 304 can be expressed as form of 1*10^n, 2* 10^n or 5*10^n as a nice numbers. These numbers are used for spacing the ticks.
305 305 This method will modify the current range and number of ticks.
306 306 \sa setRange(), setTickCount()
307 307 */
308 308 void QValueAxis::applyNiceNumbers()
309 309 {
310 310 Q_D(QValueAxis);
311 311 if(d->m_applying) return;
312 312 qreal min = d->m_min;
313 313 qreal max = d->m_max;
314 314 int ticks = d->m_tickCount;
315 315 AbstractDomain::looseNiceNumbers(min,max,ticks);
316 316 d->m_applying=true;
317 317 d->setRange(min,max);
318 318 setTickCount(ticks);
319 319 d->m_applying=false;
320 320 }
321 321
322 322 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
323 323
324 324 QValueAxisPrivate::QValueAxisPrivate(QValueAxis *q)
325 325 : QAbstractAxisPrivate(q),
326 326 m_min(0),
327 327 m_max(0),
328 328 m_tickCount(5),
329 329 m_format(QString::null),
330 330 m_applying(false),
331 331 m_niceNumbersEnabled(false)
332 332 {
333 333
334 334 }
335 335
336 336 QValueAxisPrivate::~QValueAxisPrivate()
337 337 {
338 338
339 339 }
340 340
341 341 void QValueAxisPrivate::setMin(const QVariant &min)
342 342 {
343 343 Q_Q(QValueAxis);
344 344 bool ok;
345 345 qreal value = min.toReal(&ok);
346 346 if (ok)
347 347 q->setMin(value);
348 348 }
349 349
350 350 void QValueAxisPrivate::setMax(const QVariant &max)
351 351 {
352 352 Q_Q(QValueAxis);
353 353 bool ok;
354 354 qreal value = max.toReal(&ok);
355 355 if (ok)
356 356 q->setMax(value);
357 357 }
358 358
359 359 void QValueAxisPrivate::setRange(const QVariant &min, const QVariant &max)
360 360 {
361 361 Q_Q(QValueAxis);
362 362 bool ok1;
363 363 bool ok2;
364 364 qreal value1 = min.toReal(&ok1);
365 365 qreal value2 = max.toReal(&ok2);
366 366 if (ok1 && ok2)
367 367 q->setRange(value1, value2);
368 368 }
369 369
370 370 void QValueAxisPrivate::setRange(qreal min, qreal max)
371 371 {
372 372 Q_Q(QValueAxis);
373 373 bool changed = false;
374 374
375 375 if (min > max)
376 376 return;
377 377
378 378 bool changeMin = false;
379 379 if (m_min == 0 || min == 0)
380 380 changeMin = !qFuzzyCompare(1 + m_min, 1 + min);
381 381 else
382 382 changeMin = !qFuzzyCompare(m_min, min);
383 383
384 384 bool changeMax = false;
385 385 if (m_max == 0 || max == 0)
386 386 changeMax = !qFuzzyCompare(1 + m_max, 1 + max);
387 387 else
388 388 changeMax = !qFuzzyCompare(m_max, max);
389 389
390 390 if (changeMin) {
391 391 m_min = min;
392 392 changed = true;
393 393 emit q->minChanged(min);
394 394 }
395 395
396 396 if (changeMax) {
397 397 m_max = max;
398 398 changed = true;
399 399 emit q->maxChanged(max);
400 400 }
401 401
402 402 if (changed) {
403 403 emit rangeChanged(min,max);
404 404 emit q->rangeChanged(min, max);
405 405 }
406 406 }
407 407
408 408 void QValueAxisPrivate::initializeGraphics(QGraphicsItem *parent)
409 409 {
410 410 Q_Q(QValueAxis);
411 411 ChartAxisElement *axis(0);
412 412
413 413 if (m_chart->chartType() == QChart::ChartTypeCartesian) {
414 414 if (orientation() == Qt::Vertical)
415 415 axis = new ChartValueAxisY(q,parent);
416 416 if (orientation() == Qt::Horizontal)
417 417 axis = new ChartValueAxisX(q,parent);
418 418 }
419 419
420 420 if (m_chart->chartType() == QChart::ChartTypePolar) {
421 421 if (orientation() == Qt::Vertical)
422 422 axis = new PolarChartValueAxisRadial(q, parent);
423 423 if (orientation() == Qt::Horizontal)
424 424 axis = new PolarChartValueAxisAngular(q, parent);
425 425 }
426 426
427 427 m_item.reset(axis);
428 428 QAbstractAxisPrivate::initializeGraphics(parent);
429 429 }
430 430
431 431
432 432 void QValueAxisPrivate::initializeDomain(AbstractDomain *domain)
433 433 {
434 434 if (orientation() == Qt::Vertical) {
435 435 if (!qFuzzyIsNull(m_max - m_min))
436 436 domain->setRangeY(m_min, m_max);
437 437 else
438 438 setRange(domain->minY(), domain->maxY());
439 439 }
440 440 if (orientation() == Qt::Horizontal) {
441 441 if (!qFuzzyIsNull(m_max - m_min))
442 442 domain->setRangeX(m_min, m_max);
443 443 else
444 444 setRange(domain->minX(), domain->maxX());
445 445 }
446 446 }
447 447
448 448 #include "moc_qvalueaxis.cpp"
449 449 #include "moc_qvalueaxis_p.cpp"
450 450
451 451 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,1028 +1,1028
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2014 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "qabstractbarseries.h"
22 22 #include "qabstractbarseries_p.h"
23 23 #include "qbarset.h"
24 24 #include "qbarset_p.h"
25 25 #include "abstractdomain_p.h"
26 26 #include "chartdataset_p.h"
27 27 #include "charttheme_p.h"
28 28 #include "qvalueaxis.h"
29 29 #include "qbarcategoryaxis.h"
30 30 #include "qbarlegendmarker.h"
31 31 #include "baranimation_p.h"
32 32 #include "abstractbarchartitem_p.h"
33 33 #include "qchart_p.h"
34 34
35 35 QTCOMMERCIALCHART_BEGIN_NAMESPACE
36 36
37 37 /*!
38 38 \class QAbstractBarSeries
39 39 \inmodule Qt Charts
40 40 \brief Series for creating a bar chart.
41 41 \mainclass
42 42
43 43 QAbstractBarSeries represents a series of data shown as bars. The purpose of this class is to draw bars to
44 44 the position defined by data. Single bar is defined by QPointF, where x value is the x-coordinate of the bar
45 45 and y-value is the height of the bar. The category names are ignored with this series and x-axis
46 46 shows the x-values.
47 47
48 48 See the \l {BarChart Example} {bar chart example} to learn how to create a simple bar chart.
49 49 \image examples_barchart.png
50 50
51 51 \sa QBarSet, QStackedBarSeries, QPercentBarSeries
52 52 */
53 53 #ifdef QDOC_QT5
54 54 /*!
55 55 \qmltype AbstractBarSeries
56 56 \instantiates QAbstractBarSeries
57 57 \inqmlmodule QtCommercial.Chart
58 58
59 59 \include doc/src/abstractbarseries.qdocinc
60 60 */
61 61 #else
62 62 /*!
63 63 \qmlclass AbstractBarSeries QAbstractBarSeries
64 64
65 65 \include ../doc/src/abstractbarseries.qdocinc
66 66 */
67 67 #endif
68 68
69 69 /*!
70 70 \qmlproperty AbstractAxis AbstractBarSeries::axisX
71 71 The x axis used for the series. If you leave both axisX and axisXTop undefined, a BarCategoriesAxis is created for
72 72 the series.
73 73 \sa axisXTop
74 74 */
75 75
76 76 /*!
77 77 \qmlproperty AbstractAxis AbstractBarSeries::axisY
78 78 The y axis used for the series. If you leave both axisY and axisYRight undefined, a ValueAxis is created for
79 79 the series.
80 80 \sa axisYRight
81 81 */
82 82
83 83 /*!
84 84 \qmlproperty AbstractAxis AbstractBarSeries::axisXTop
85 85 The x axis used for the series, drawn on top of the chart view. Note that you can only provide either axisX or
86 86 axisXTop, but not both.
87 87 \sa axisX
88 88 */
89 89
90 90 /*!
91 91 \qmlproperty AbstractAxis AbstractBarSeries::axisYRight
92 92 The y axis used for the series, drawn to the right on the chart view. Note that you can only provide either axisY
93 93 or axisYRight, but not both.
94 94 \sa axisY
95 95 */
96 96
97 97 /*!
98 98 \property QAbstractBarSeries::barWidth
99 99 The width of the bars of the series. The unit of \a width is the unit of x-axis. The minimum width for bars
100 100 is zero and negative values are treated as zero. Setting the width to zero means that width of the bar on screen
101 101 is one pixel no matter what the scale of x-axis is. Bars wider than zero are scaled with x-axis.
102 102 Note that with QBarSeries this value means the width of one group of bars instead of just one bar.
103 103 \sa QBarSeries
104 104 */
105 105 /*!
106 106 \qmlproperty real AbstractBarSeries::barWidth
107 107 The width of the bars of the series. The unit of width is the unit of x-axis. The minimum width for bars
108 108 is zero and negative values are treated as zero. Setting the width to zero means that width of the bar on screen
109 109 is one pixel no matter what the scale of x-axis is. Bars wider than zero are scaled with x-axis.
110 110 Note that with QBarSeries this value means the width of one group of bars instead of just one bar.
111 111 */
112 112
113 113 /*!
114 114 \property QAbstractBarSeries::count
115 115 Holds the number of sets in series.
116 116 */
117 117 /*!
118 118 \qmlproperty int AbstractBarSeries::count
119 119 Holds the number of sets in series.
120 120 */
121 121
122 122 /*!
123 123 \property QAbstractBarSeries::labelsVisible
124 124 Defines the visibility of the labels in series
125 125 */
126 126 /*!
127 127 \qmlproperty bool AbstractBarSeries::labelsVisible
128 128 Defines the visibility of the labels in series
129 129 */
130 130
131 131 /*!
132 132 \property QAbstractBarSeries::labelsFormat
133 133 The \a format used for showing labels in series.
134 134
135 135 QAbstractBarSeries supports the following format tag:
136 136 \table
137 137 \row
138 138 \li @value \li The value of the bar
139 139 \endtable
140 140
141 141 For example, the following usage of the format tags would produce labels that show the value
142 142 followed by unit ('u'):
143 143 \code
144 144 series->setLabelsFormat("@value u");
145 145 \endcode
146 146
147 147 By default, the labels shows the value of the bar. For percent bar series '%' is added after
148 148 the value. The labels are shown on the plot area, labels on the edge of the plot area are cut.
149 149 If the bars are close to each other the labels may overlap.
150 150
151 151 \sa QAbstractBarSeries::labelsVisible, QAbstractBarSeries::labelsPosition
152 152 */
153 153 /*!
154 154 \qmlproperty string AbstractBarSeries::labelsFormat
155 155 The format used for showing labels in series.
156 156
157 157 \sa QAbstractBarSeries::labelsFormat, labelsVisible, labelsPosition
158 158 */
159 159 /*!
160 160 \fn void QAbstractBarSeries::labelsFormatChanged(const QString &format)
161 161 Signal is emitted when the \a format of data value labels is changed.
162 162 */
163 163 /*!
164 164 \qmlsignal XYSeries::onLabelsFormatChanged(string format)
165 165 Signal is emitted when the \a format of data value labels is changed.
166 166 */
167 167
168 168 /*!
169 169 \enum QAbstractBarSeries::LabelsPosition
170 170
171 171 This enum describes the position of the data value labels.
172 172
173 173 \value LabelsCenter Label is in the center of the bar.
174 174 \value LabelsInsideEnd Label is inside the bar at the high end of it.
175 175 \value LabelsInsideBase Label is inside the bar at the low end of it.
176 176 \value LabelsOutsideEnd Label is outside the bar at the high end of it.
177 177 */
178 178
179 179 /*!
180 180 \property QAbstractBarSeries::labelsPosition
181 181 Defines the \a position of value labels.
182 182
183 183 \sa QAbstractBarSeries::labelsVisible, QAbstractBarSeries::labelsFormat
184 184 */
185 185 /*!
186 186 \qmlproperty string AbstractBarSeries::labelsPosition
187 187 Defines the \a position of value labels.
188 188
189 189 \sa labelsVisible, labelsFormat
190 190 */
191 191 /*!
192 192 \fn void QAbstractBarSeries::labelsPositionChanged(QAbstractBarSeries::LabelsPosition position)
193 193 Signal is emitted when the \a position of value labels is changed.
194 194 */
195 195 /*!
196 196 \qmlsignal AbstractBarSeries::onLabelsPositionChanged(LabelsPosition position)
197 197 Signal is emitted when the \a position of value labels is changed.
198 198 */
199 199
200 200 /*!
201 201 \fn void QAbstractBarSeries::clicked(int index, QBarSet *barset)
202 202 The signal is emitted if the user clicks with a mouse on top of QBarSet \a barset.
203 203 Clicked bar inside set is indexed by \a index
204 204 */
205 205 /*!
206 206 \qmlsignal AbstractBarSeries::onClicked(int index, BarSet barset)
207 207 The signal is emitted if the user clicks with a mouse on top of BarSet.
208 208 Clicked bar inside set is indexed by \a index
209 209 */
210 210
211 211 /*!
212 212 \fn void QAbstractBarSeries::hovered(bool status, QBarSet* barset)
213 213
214 214 The signal is emitted if mouse is hovered on top of series.
215 215 Parameter \a barset is the pointer of barset, where hover happened.
216 216 Parameter \a status is true, if mouse entered on top of series, false if mouse left from top of series.
217 217 */
218 218
219 219 /*!
220 220 \fn void QAbstractBarSeries::hovered(bool status, int index, QBarSet* barset)
221 221
222 222 The signal is emitted if mouse is hovered on top of series.
223 223 Parameter \a barset is the pointer of barset, where hover happened.
224 224 Parameter \a status is true, if mouse entered on top of series, false if mouse left from top of series.
225 225 Hovered bar inside the set is indexed by \a index.
226 226 */
227 227 /*!
228 228 \qmlsignal AbstractBarSeries::onHovered(bool status, int index, BarSet barset)
229 229
230 230 The signal is emitted if mouse is hovered on top of series.
231 231 Parameter \a barset is the pointer of barset, where hover happened.
232 232 Parameter \a status is true, if mouse entered on top of series, false if mouse left from top of series.
233 233 Hovered bar inside the set is indexed by \a index.
234 234 */
235 235
236 236 /*!
237 237 \fn void QAbstractBarSeries::countChanged()
238 238 This signal is emitted when barset count has been changed, for example by append or remove.
239 239 */
240 240 /*!
241 241 \qmlsignal AbstractBarSeries::onCountChanged()
242 242 This signal is emitted when barset count has been changed, for example by append or remove.
243 243 */
244 244
245 245 /*!
246 246 \fn void QAbstractBarSeries::labelsVisibleChanged()
247 247 This signal is emitted when labels visibility have changed.
248 248 \sa isLabelsVisible(), setLabelsVisible()
249 249 */
250 250
251 251 /*!
252 252 \fn void QAbstractBarSeries::barsetsAdded(QList<QBarSet*> sets)
253 253 This signal is emitted when \a sets have been added to the series.
254 254 \sa append(), insert()
255 255 */
256 256 /*!
257 257 \qmlsignal AbstractBarSeries::onBarsetsAdded(BarSet barset)
258 258 Emitted when \a barset has been added to the series.
259 259 */
260 260
261 261 /*!
262 262 \fn void QAbstractBarSeries::barsetsRemoved(QList<QBarSet*> sets)
263 263 This signal is emitted when \a sets have been removed from the series.
264 264 \sa remove()
265 265 */
266 266 /*!
267 267 \qmlsignal AbstractBarSeries::onBarsetsRemoved(BarSet barset)
268 268 Emitted when \a barset has been removed from the series.
269 269 */
270 270
271 271 /*!
272 272 \qmlmethod BarSet AbstractBarSeries::at(int index)
273 273 Returns bar set at \a index. Returns null if the index is not valid.
274 274 */
275 275
276 276 /*!
277 277 \qmlmethod BarSet AbstractBarSeries::append(string label, VariantList values)
278 278 Adds a new bar set with \a label and \a values to \a index. Values is a list of reals.
279 279 For example:
280 280 \code
281 281 myBarSeries.append("set 1", [0, 0.2, 0.2, 0.5, 0.4, 1.5, 0.9]);
282 282 \endcode
283 283 */
284 284
285 285 /*!
286 286 \qmlmethod BarSet AbstractBarSeries::insert(int index, string label, VariantList values)
287 287 Inserts a new bar set with \a label and \a values to \a index. Values can be a list of reals or a list of XYPoints.
288 288 If index is zero or smaller, the new barset is prepended. If the index is count or bigger, the new barset is
289 289 appended.
290 290 \sa AbstractBarSeries::append()
291 291 */
292 292
293 293 /*!
294 294 \qmlmethod bool AbstractBarSeries::remove(BarSet barset)
295 295 Removes the barset from the series. Returns true if successful, false otherwise.
296 296 */
297 297
298 298 /*!
299 299 \qmlmethod AbstractBarSeries::clear()
300 300 Removes all barsets from the series.
301 301 */
302 302
303 303 /*!
304 304 Destructs abstractbarseries and owned barsets.
305 305 */
306 306 QAbstractBarSeries::~QAbstractBarSeries()
307 307 {
308 308
309 309 }
310 310
311 311 /*!
312 312 \internal
313 313 */
314 314 QAbstractBarSeries::QAbstractBarSeries(QAbstractBarSeriesPrivate &o, QObject *parent)
315 315 : QAbstractSeries(o, parent)
316 316 {
317 317 Q_D(QAbstractSeries);
318 318 QObject::connect(this, SIGNAL(countChanged()), d, SIGNAL(countChanged()));
319 319 }
320 320
321 321 /*!
322 322 Sets the width of the bars of the series. The unit of \a width is the unit of x-axis. The minimum width for bars
323 323 is zero and negative values are treated as zero. Setting the width to zero means that width of the bar on screen
324 324 is one pixel no matter what the scale of x-axis is. Bars wider than zero are scaled with x-axis.
325 325 Note that with \link QBarSeries \endlink this value means the width of one group of bars instead of just one bar.
326 326 */
327 327 void QAbstractBarSeries::setBarWidth(qreal width)
328 328 {
329 329 Q_D(QAbstractBarSeries);
330 330 d->setBarWidth(width);
331 331 }
332 332
333 333 /*!
334 334 Returns the width of the bars of the series.
335 335 \sa setBarWidth()
336 336 */
337 337 qreal QAbstractBarSeries::barWidth() const
338 338 {
339 339 Q_D(const QAbstractBarSeries);
340 340 return d->barWidth();
341 341 }
342 342
343 343 /*!
344 344 Adds a set of bars to series. Takes ownership of \a set. If the set is null or is already in series, it won't be appended.
345 345 Returns true, if appending succeeded.
346 346 */
347 347 bool QAbstractBarSeries::append(QBarSet *set)
348 348 {
349 349 Q_D(QAbstractBarSeries);
350 350 bool success = d->append(set);
351 351 if (success) {
352 352 QList<QBarSet *> sets;
353 353 sets.append(set);
354 354 set->setParent(this);
355 355 emit barsetsAdded(sets);
356 356 emit countChanged();
357 357 }
358 358 return success;
359 359 }
360 360
361 361 /*!
362 362 Removes barset from series. Releases ownership of \a set. Deletes the set, if remove
363 363 was successful.
364 364 Returns true, if set was removed.
365 365 */
366 366 bool QAbstractBarSeries::remove(QBarSet *set)
367 367 {
368 368 Q_D(QAbstractBarSeries);
369 369 bool success = d->remove(set);
370 370 if (success) {
371 371 QList<QBarSet *> sets;
372 372 sets.append(set);
373 373 set->setParent(0);
374 374 emit barsetsRemoved(sets);
375 375 emit countChanged();
376 376 delete set;
377 377 set = 0;
378 378 }
379 379 return success;
380 380 }
381 381
382 382 /*!
383 383 Takes a single \a set from the series. Does not delete the barset object.
384 384
385 385 NOTE: The series remains as the barset's parent object. You must set the
386 386 parent object to take full ownership.
387 387
388 388 Returns true if take was successful.
389 389 */
390 390 bool QAbstractBarSeries::take(QBarSet *set)
391 391 {
392 392 Q_D(QAbstractBarSeries);
393 393 bool success = d->remove(set);
394 394 if (success) {
395 395 QList<QBarSet *> sets;
396 396 sets.append(set);
397 397 emit barsetsRemoved(sets);
398 398 emit countChanged();
399 399 }
400 400 return success;
401 401 }
402 402
403 403 /*!
404 404 Adds a list of barsets to series. Takes ownership of \a sets.
405 405 Returns true, if all sets were appended successfully. If any of the sets is null or is already appended to series,
406 406 nothing is appended and function returns false. If any of the sets is in list more than once, nothing is appended
407 407 and function returns false.
408 408 */
409 409 bool QAbstractBarSeries::append(QList<QBarSet *> sets)
410 410 {
411 411 Q_D(QAbstractBarSeries);
412 412 bool success = d->append(sets);
413 413 if (success) {
414 414 emit barsetsAdded(sets);
415 415 emit countChanged();
416 416 }
417 417 return success;
418 418 }
419 419
420 420 /*!
421 421 Insert a set of bars to series at \a index postion. Takes ownership of \a set. If the set is null or is already in series, it won't be appended.
422 422 Returns true, if inserting succeeded.
423 423
424 424 */
425 425 bool QAbstractBarSeries::insert(int index, QBarSet *set)
426 426 {
427 427 Q_D(QAbstractBarSeries);
428 428 bool success = d->insert(index, set);
429 429 if (success) {
430 430 QList<QBarSet *> sets;
431 431 sets.append(set);
432 432 emit barsetsAdded(sets);
433 433 emit countChanged();
434 434 }
435 435 return success;
436 436 }
437 437
438 438 /*!
439 439 Removes all barsets from the series. Deletes removed sets.
440 440 */
441 441 void QAbstractBarSeries::clear()
442 442 {
443 443 Q_D(QAbstractBarSeries);
444 444 QList<QBarSet *> sets = barSets();
445 445 bool success = d->remove(sets);
446 446 if (success) {
447 447 emit barsetsRemoved(sets);
448 448 emit countChanged();
449 449 foreach (QBarSet *set, sets)
450 450 delete set;
451 451 }
452 452 }
453 453
454 454 /*!
455 455 Returns number of sets in series.
456 456 */
457 457 int QAbstractBarSeries::count() const
458 458 {
459 459 Q_D(const QAbstractBarSeries);
460 460 return d->m_barSets.count();
461 461 }
462 462
463 463 /*!
464 464 Returns a list of sets in series. Keeps ownership of sets.
465 465 */
466 466 QList<QBarSet *> QAbstractBarSeries::barSets() const
467 467 {
468 468 Q_D(const QAbstractBarSeries);
469 469 return d->m_barSets;
470 470 }
471 471
472 472 /*!
473 473 Sets the visibility of labels in series to \a visible
474 474 */
475 475 void QAbstractBarSeries::setLabelsVisible(bool visible)
476 476 {
477 477 Q_D(QAbstractBarSeries);
478 478 if (d->m_labelsVisible != visible) {
479 479 d->setLabelsVisible(visible);
480 480 emit labelsVisibleChanged();
481 481 }
482 482 }
483 483
484 484 /*!
485 485 Returns the visibility of labels
486 486 */
487 487 bool QAbstractBarSeries::isLabelsVisible() const
488 488 {
489 489 Q_D(const QAbstractBarSeries);
490 490 return d->m_labelsVisible;
491 491 }
492 492
493 493 void QAbstractBarSeries::setLabelsFormat(const QString &format)
494 494 {
495 495 Q_D(QAbstractBarSeries);
496 496 if (d->m_labelsFormat != format) {
497 497 d->m_labelsFormat = format;
498 498 emit labelsFormatChanged(format);
499 499 }
500 500 }
501 501
502 502 QString QAbstractBarSeries::labelsFormat() const
503 503 {
504 504 Q_D(const QAbstractBarSeries);
505 505 return d->m_labelsFormat;
506 506 }
507 507
508 508 void QAbstractBarSeries::setLabelsPosition(QAbstractBarSeries::LabelsPosition position)
509 509 {
510 510 Q_D(QAbstractBarSeries);
511 511 if (d->m_labelsPosition != position) {
512 512 d->m_labelsPosition = position;
513 513 emit labelsPositionChanged(position);
514 514 }
515 515 }
516 516
517 517 QAbstractBarSeries::LabelsPosition QAbstractBarSeries::labelsPosition() const
518 518 {
519 519 Q_D(const QAbstractBarSeries);
520 520 return d->m_labelsPosition;
521 521 }
522 522
523 523 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
524 524
525 525 QAbstractBarSeriesPrivate::QAbstractBarSeriesPrivate(QAbstractBarSeries *q) :
526 526 QAbstractSeriesPrivate(q),
527 527 m_barWidth(0.5), // Default value is 50% of category width
528 528 m_labelsVisible(false),
529 529 m_visible(true),
530 530 m_blockBarUpdate(false),
531 531 m_labelsFormat(),
532 532 m_labelsPosition(QAbstractBarSeries::LabelsCenter)
533 533 {
534 534 }
535 535
536 536 int QAbstractBarSeriesPrivate::categoryCount() const
537 537 {
538 538 // No categories defined. return count of longest set.
539 539 int count = 0;
540 540 for (int i = 0; i < m_barSets.count(); i++) {
541 541 if (m_barSets.at(i)->count() > count)
542 542 count = m_barSets.at(i)->count();
543 543 }
544 544
545 545 return count;
546 546 }
547 547
548 548 void QAbstractBarSeriesPrivate::setBarWidth(qreal width)
549 549 {
550 550 if (width < 0.0)
551 551 width = 0.0;
552 552 m_barWidth = width;
553 553 emit updatedLayout();
554 554 }
555 555
556 556 qreal QAbstractBarSeriesPrivate::barWidth() const
557 557 {
558 558 return m_barWidth;
559 559 }
560 560
561 561 QBarSet *QAbstractBarSeriesPrivate::barsetAt(int index)
562 562 {
563 563 return m_barSets.at(index);
564 564 }
565 565
566 566 void QAbstractBarSeriesPrivate::setVisible(bool visible)
567 567 {
568 568 m_visible = visible;
569 569 emit visibleChanged();
570 570 }
571 571
572 572 void QAbstractBarSeriesPrivate::setLabelsVisible(bool visible)
573 573 {
574 574 m_labelsVisible = visible;
575 575 emit labelsVisibleChanged(visible);
576 576 }
577 577
578 578 qreal QAbstractBarSeriesPrivate::min()
579 579 {
580 580 if (m_barSets.count() <= 0)
581 581 return 0;
582 582
583 583 qreal min = INT_MAX;
584 584
585 585 for (int i = 0; i < m_barSets.count(); i++) {
586 586 int categoryCount = m_barSets.at(i)->count();
587 587 for (int j = 0; j < categoryCount; j++) {
588 588 qreal temp = m_barSets.at(i)->at(j);
589 589 if (temp < min)
590 590 min = temp;
591 591 }
592 592 }
593 593 return min;
594 594 }
595 595
596 596 qreal QAbstractBarSeriesPrivate::max()
597 597 {
598 598 if (m_barSets.count() <= 0)
599 599 return 0;
600 600
601 601 qreal max = INT_MIN;
602 602
603 603 for (int i = 0; i < m_barSets.count(); i++) {
604 604 int categoryCount = m_barSets.at(i)->count();
605 605 for (int j = 0; j < categoryCount; j++) {
606 606 qreal temp = m_barSets.at(i)->at(j);
607 607 if (temp > max)
608 608 max = temp;
609 609 }
610 610 }
611 611
612 612 return max;
613 613 }
614 614
615 615 qreal QAbstractBarSeriesPrivate::valueAt(int set, int category)
616 616 {
617 617 if ((set < 0) || (set >= m_barSets.count()))
618 618 return 0; // No set, no value.
619 619 else if ((category < 0) || (category >= m_barSets.at(set)->count()))
620 620 return 0; // No category, no value.
621 621
622 622 return m_barSets.at(set)->at(category);
623 623 }
624 624
625 625 qreal QAbstractBarSeriesPrivate::percentageAt(int set, int category)
626 626 {
627 627 if ((set < 0) || (set >= m_barSets.count()))
628 628 return 0; // No set, no value.
629 629 else if ((category < 0) || (category >= m_barSets.at(set)->count()))
630 630 return 0; // No category, no value.
631 631
632 632 qreal value = m_barSets.at(set)->at(category);
633 633 qreal sum = categorySum(category);
634 634 if (qFuzzyCompare(sum, 0))
635 635 return 0;
636 636
637 637 return value / sum;
638 638 }
639 639
640 640 qreal QAbstractBarSeriesPrivate::categorySum(int category)
641 641 {
642 642 qreal sum(0);
643 643 int count = m_barSets.count(); // Count sets
644 644 for (int set = 0; set < count; set++) {
645 645 if (category < m_barSets.at(set)->count())
646 646 sum += m_barSets.at(set)->at(category);
647 647 }
648 648 return sum;
649 649 }
650 650
651 651 qreal QAbstractBarSeriesPrivate::absoluteCategorySum(int category)
652 652 {
653 653 qreal sum(0);
654 654 int count = m_barSets.count(); // Count sets
655 655 for (int set = 0; set < count; set++) {
656 656 if (category < m_barSets.at(set)->count())
657 657 sum += qAbs(m_barSets.at(set)->at(category));
658 658 }
659 659 return sum;
660 660 }
661 661
662 662 qreal QAbstractBarSeriesPrivate::maxCategorySum()
663 663 {
664 664 qreal max = INT_MIN;
665 665 int count = categoryCount();
666 666 for (int i = 0; i < count; i++) {
667 667 qreal sum = categorySum(i);
668 668 if (sum > max)
669 669 max = sum;
670 670 }
671 671 return max;
672 672 }
673 673
674 674 qreal QAbstractBarSeriesPrivate::minX()
675 675 {
676 676 if (m_barSets.count() <= 0)
677 677 return 0;
678 678
679 679 qreal min = INT_MAX;
680 680
681 681 for (int i = 0; i < m_barSets.count(); i++) {
682 682 int categoryCount = m_barSets.at(i)->count();
683 683 for (int j = 0; j < categoryCount; j++) {
684 684 qreal temp = m_barSets.at(i)->d_ptr.data()->m_values.at(j).x();
685 685 if (temp < min)
686 686 min = temp;
687 687 }
688 688 }
689 689 return min;
690 690 }
691 691
692 692 qreal QAbstractBarSeriesPrivate::maxX()
693 693 {
694 694 if (m_barSets.count() <= 0)
695 695 return 0;
696 696
697 697 qreal max = INT_MIN;
698 698
699 699 for (int i = 0; i < m_barSets.count(); i++) {
700 700 int categoryCount = m_barSets.at(i)->count();
701 701 for (int j = 0; j < categoryCount; j++) {
702 702 qreal temp = m_barSets.at(i)->d_ptr.data()->m_values.at(j).x();
703 703 if (temp > max)
704 704 max = temp;
705 705 }
706 706 }
707 707
708 708 return max;
709 709 }
710 710
711 711 qreal QAbstractBarSeriesPrivate::categoryTop(int category)
712 712 {
713 713 // Returns top (sum of all positive values) of category.
714 714 // Returns 0, if all values are negative
715 715 qreal top(0);
716 716 int count = m_barSets.count();
717 717 for (int set = 0; set < count; set++) {
718 718 if (category < m_barSets.at(set)->count()) {
719 719 qreal temp = m_barSets.at(set)->at(category);
720 720 if (temp > 0) {
721 721 top += temp;
722 722 }
723 723 }
724 724 }
725 725 return top;
726 726 }
727 727
728 728 qreal QAbstractBarSeriesPrivate::categoryBottom(int category)
729 729 {
730 730 // Returns bottom (sum of all negative values) of category
731 731 // Returns 0, if all values are positive
732 732 qreal bottom(0);
733 733 int count = m_barSets.count();
734 734 for (int set = 0; set < count; set++) {
735 735 if (category < m_barSets.at(set)->count()) {
736 736 qreal temp = m_barSets.at(set)->at(category);
737 737 if (temp < 0) {
738 738 bottom += temp;
739 739 }
740 740 }
741 741 }
742 742 return bottom;
743 743 }
744 744
745 745 qreal QAbstractBarSeriesPrivate::top()
746 746 {
747 747 // Returns top of all categories
748 748 qreal top(0);
749 749 int count = categoryCount();
750 750 for (int i = 0; i < count; i++) {
751 751 qreal temp = categoryTop(i);
752 752 if (temp > top)
753 753 top = temp;
754 754 }
755 755 return top;
756 756 }
757 757
758 758 qreal QAbstractBarSeriesPrivate::bottom()
759 759 {
760 760 // Returns bottom of all categories
761 761 qreal bottom(0);
762 762 int count = categoryCount();
763 763 for (int i = 0; i < count; i++) {
764 764 qreal temp = categoryBottom(i);
765 765 if (temp < bottom)
766 766 bottom = temp;
767 767 }
768 768 return bottom;
769 769 }
770 770
771 771 bool QAbstractBarSeriesPrivate::blockBarUpdate()
772 772 {
773 773 return m_blockBarUpdate;
774 774 }
775 775
776 776 void QAbstractBarSeriesPrivate::initializeDomain()
777 777 {
778 778 qreal minX(domain()->minX());
779 779 qreal minY(domain()->minY());
780 780 qreal maxX(domain()->maxX());
781 781 qreal maxY(domain()->maxY());
782 782
783 783 qreal seriesMinX = this->minX();
784 784 qreal seriesMaxX = this->maxX();
785 785 qreal y = max();
786 786 minX = qMin(minX, seriesMinX - (qreal)0.5);
787 787 minY = qMin(minY, y);
788 788 maxX = qMax(maxX, seriesMaxX + (qreal)0.5);
789 789 maxY = qMax(maxY, y);
790 790
791 791 domain()->setRange(minX, maxX, minY, maxY);
792 792 }
793 793
794 794 QList<QLegendMarker*> QAbstractBarSeriesPrivate::createLegendMarkers(QLegend* legend)
795 795 {
796 796 Q_Q(QAbstractBarSeries);
797 797 QList<QLegendMarker*> markers;
798 798
799 799 foreach(QBarSet* set, q->barSets()) {
800 800 QBarLegendMarker* marker = new QBarLegendMarker(q,set,legend);
801 801 markers << marker;
802 802 }
803 803 return markers;
804 804 }
805 805
806 806
807 807 bool QAbstractBarSeriesPrivate::append(QBarSet *set)
808 808 {
809 809 if ((m_barSets.contains(set)) || (set == 0))
810 810 return false; // Fail if set is already in list or set is null.
811 811
812 812 m_barSets.append(set);
813 813 QObject::connect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout()));
814 814 QObject::connect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SIGNAL(updatedBars()));
815 815 QObject::connect(set->d_ptr.data(), SIGNAL(restructuredBars()), this, SIGNAL(restructuredBars()));
816 816
817 817 emit restructuredBars(); // this notifies barchartitem
818 818 return true;
819 819 }
820 820
821 821 bool QAbstractBarSeriesPrivate::remove(QBarSet *set)
822 822 {
823 823 if (!m_barSets.contains(set))
824 824 return false; // Fail if set is not in list
825 825
826 826 m_barSets.removeOne(set);
827 827 QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout()));
828 828 QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SIGNAL(updatedBars()));
829 829 QObject::disconnect(set->d_ptr.data(), SIGNAL(restructuredBars()), this, SIGNAL(restructuredBars()));
830 830
831 831 emit restructuredBars(); // this notifies barchartitem
832 832 return true;
833 833 }
834 834
835 835 bool QAbstractBarSeriesPrivate::append(QList<QBarSet * > sets)
836 836 {
837 837 foreach (QBarSet *set, sets) {
838 838 if ((set == 0) || (m_barSets.contains(set)))
839 839 return false; // Fail if any of the sets is null or is already appended.
840 840 if (sets.count(set) != 1)
841 841 return false; // Also fail if same set is more than once in given list.
842 842 }
843 843
844 844 foreach (QBarSet *set, sets) {
845 845 m_barSets.append(set);
846 846 QObject::connect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout()));
847 847 QObject::connect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SIGNAL(updatedBars()));
848 848 QObject::connect(set->d_ptr.data(), SIGNAL(restructuredBars()), this, SIGNAL(restructuredBars()));
849 849 }
850 850
851 851 emit restructuredBars(); // this notifies barchartitem
852 852 return true;
853 853 }
854 854
855 855 bool QAbstractBarSeriesPrivate::remove(QList<QBarSet * > sets)
856 856 {
857 857 if (sets.count() == 0)
858 858 return false;
859 859
860 860 foreach (QBarSet *set, sets) {
861 861 if ((set == 0) || (!m_barSets.contains(set)))
862 862 return false; // Fail if any of the sets is null or is not in series
863 863 if (sets.count(set) != 1)
864 864 return false; // Also fail if same set is more than once in given list.
865 865 }
866 866
867 867 foreach (QBarSet *set, sets) {
868 868 m_barSets.removeOne(set);
869 869 QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout()));
870 870 QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SIGNAL(updatedBars()));
871 871 QObject::disconnect(set->d_ptr.data(), SIGNAL(restructuredBars()), this, SIGNAL(restructuredBars()));
872 872 }
873 873
874 874 emit restructuredBars(); // this notifies barchartitem
875 875
876 876 return true;
877 877 }
878 878
879 879 bool QAbstractBarSeriesPrivate::insert(int index, QBarSet *set)
880 880 {
881 881 if ((m_barSets.contains(set)) || (set == 0))
882 882 return false; // Fail if set is already in list or set is null.
883 883
884 884 m_barSets.insert(index, set);
885 885 QObject::connect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout()));
886 886 QObject::connect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SIGNAL(updatedBars()));
887 887 QObject::connect(set->d_ptr.data(), SIGNAL(restructuredBars()), this, SIGNAL(restructuredBars()));
888 888
889 889 emit restructuredBars(); // this notifies barchartitem
890 890 return true;
891 891 }
892 892
893 893 void QAbstractBarSeriesPrivate::initializeAxes()
894 894 {
895 895 Q_Q(QAbstractBarSeries);
896 896
897 897 foreach(QAbstractAxis* axis, m_axes) {
898 898
899 899 if (axis->type() == QAbstractAxis::AxisTypeBarCategory) {
900 900 switch (q->type()) {
901 901 case QAbstractSeries::SeriesTypeHorizontalBar:
902 902 case QAbstractSeries::SeriesTypeHorizontalPercentBar:
903 903 case QAbstractSeries::SeriesTypeHorizontalStackedBar:
904 904 if (axis->orientation() == Qt::Vertical)
905 905 populateCategories(qobject_cast<QBarCategoryAxis *>(axis));
906 906 break;
907 907 case QAbstractSeries::SeriesTypeBar:
908 908 case QAbstractSeries::SeriesTypePercentBar:
909 909 case QAbstractSeries::SeriesTypeStackedBar:
910 910 case QAbstractSeries::SeriesTypeBoxPlot:
911 911 if (axis->orientation() == Qt::Horizontal)
912 912 populateCategories(qobject_cast<QBarCategoryAxis *>(axis));
913 913 break;
914 914 default:
915 915 qWarning() << "Unexpected series type";
916 916 break;
917 917 }
918 918 }
919 919 }
920 920 }
921 921
922 922 QAbstractAxis::AxisType QAbstractBarSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
923 923 {
924 924 Q_Q(const QAbstractBarSeries);
925 925
926 926 switch (q->type()) {
927 927 case QAbstractSeries::SeriesTypeHorizontalBar:
928 928 case QAbstractSeries::SeriesTypeHorizontalPercentBar:
929 929 case QAbstractSeries::SeriesTypeHorizontalStackedBar:
930 930 if (orientation == Qt::Vertical)
931 931 return QAbstractAxis::AxisTypeBarCategory;
932 932 break;
933 933 case QAbstractSeries::SeriesTypeBar:
934 934 case QAbstractSeries::SeriesTypePercentBar:
935 935 case QAbstractSeries::SeriesTypeStackedBar:
936 936 case QAbstractSeries::SeriesTypeBoxPlot:
937 937 if (orientation == Qt::Horizontal)
938 938 return QAbstractAxis::AxisTypeBarCategory;
939 939 break;
940 940 default:
941 941 qWarning() << "Unexpected series type";
942 942 break;
943 943 }
944 944 return QAbstractAxis::AxisTypeValue;
945 945
946 946 }
947 947
948 948 void QAbstractBarSeriesPrivate::populateCategories(QBarCategoryAxis *axis)
949 949 {
950 950 QStringList categories;
951 951 if (axis->categories().isEmpty()) {
952 952 for (int i(1); i < categoryCount() + 1; i++)
953 categories << QString::number(i);
953 categories << presenter()->numberToString(i);
954 954 axis->append(categories);
955 955 }
956 956 }
957 957
958 958 QAbstractAxis* QAbstractBarSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
959 959 {
960 960 if (defaultAxisType(orientation) == QAbstractAxis::AxisTypeBarCategory)
961 961 return new QBarCategoryAxis;
962 962 else
963 963 return new QValueAxis;
964 964 }
965 965
966 966 void QAbstractBarSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
967 967 {
968 968 m_blockBarUpdate = true; // Ensures that the bars are not updated before the theme is ready
969 969
970 970 const QList<QGradient> gradients = theme->seriesGradients();
971 971
972 972 qreal takeAtPos = 0.5;
973 973 qreal step = 0.2;
974 974 if (m_barSets.count() > 1) {
975 975 step = 1.0 / (qreal) m_barSets.count();
976 976 if (m_barSets.count() % gradients.count())
977 977 step *= gradients.count();
978 978 else
979 979 step *= (gradients.count() - 1);
980 980 }
981 981
982 982 for (int i(0); i < m_barSets.count(); i++) {
983 983 int colorIndex = (index + i) % gradients.count();
984 984 if (i > 0 && i %gradients.count() == 0) {
985 985 // There is no dedicated base color for each sets, generate more colors
986 986 takeAtPos += step;
987 987 if (takeAtPos == 1.0)
988 988 takeAtPos += step;
989 989 takeAtPos -= (int) takeAtPos;
990 990 }
991 991 if (forced || QChartPrivate::defaultBrush() == m_barSets.at(i)->d_ptr->m_brush)
992 992 m_barSets.at(i)->setBrush(ChartThemeManager::colorAt(gradients.at(colorIndex), takeAtPos));
993 993
994 994 // Pick label color from the opposite end of the gradient.
995 995 // 0.3 as a boundary seems to work well.
996 996 if (forced || QChartPrivate::defaultBrush() == m_barSets.at(i)->d_ptr->m_labelBrush) {
997 997 if (takeAtPos < 0.3)
998 998 m_barSets.at(i)->setLabelBrush(ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 1));
999 999 else
1000 1000 m_barSets.at(i)->setLabelBrush(ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 0));
1001 1001 }
1002 1002 if (forced || QChartPrivate::defaultPen() == m_barSets.at(i)->d_ptr->m_pen) {
1003 1003 QColor c = ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 0.0);
1004 1004 m_barSets.at(i)->setPen(c);
1005 1005 }
1006 1006 }
1007 1007 m_blockBarUpdate = false;
1008 1008 emit updatedBars();
1009 1009 }
1010 1010
1011 1011 void QAbstractBarSeriesPrivate::initializeAnimations(QChart::AnimationOptions options)
1012 1012 {
1013 1013 AbstractBarChartItem *bar = static_cast<AbstractBarChartItem *>(m_item.data());
1014 1014 Q_ASSERT(bar);
1015 1015 if (bar->animation())
1016 1016 bar->animation()->stopAndDestroyLater();
1017 1017
1018 1018 if (options.testFlag(QChart::SeriesAnimations))
1019 1019 bar->setAnimation(new BarAnimation(bar));
1020 1020 else
1021 1021 bar->setAnimation(0);
1022 1022 QAbstractSeriesPrivate::initializeAnimations(options);
1023 1023 }
1024 1024
1025 1025 #include "moc_qabstractbarseries.cpp"
1026 1026 #include "moc_qabstractbarseries_p.cpp"
1027 1027
1028 1028 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,690 +1,690
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2014 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "qboxplotseries.h"
22 22 #include "qboxplotseries_p.h"
23 23 #include "qboxplotlegendmarker.h"
24 24 #include "qbarcategoryaxis.h"
25 25 #include "boxplotchartitem_p.h"
26 26 #include "chartdataset_p.h"
27 27 #include "charttheme_p.h"
28 28 #include "qvalueaxis.h"
29 29 #include "charttheme_p.h"
30 30 #include "boxplotanimation_p.h"
31 31 #include "qchart_p.h"
32 32 #include "qboxset.h"
33 33 #include "qboxset_p.h"
34 34
35 35 QTCOMMERCIALCHART_BEGIN_NAMESPACE
36 36
37 37 /*!
38 38 \class QBoxPlotSeries
39 39 \inmodule Qt Charts
40 40 \brief Series for creating box-and-whiskers chart
41 41 \mainclass
42 42
43 43 QBoxPlotSeries represents a series of data shown as box-and-whisker bars. The purpose of this class is to act as
44 44 a container for single box-and-whisker items. Each item is drawn to own slot. If chart includes multiple instances of
45 45 QBoxPlotSeries then box-and-whiskers items with the same index are drawn to same slot.
46 46
47 47 See the \l {Box and Whiskers Example} {box-and-whiskers chart example} to learn how to create a box-and-whiskers chart.
48 48 \image examples_boxplotchart.png
49 49
50 50 \sa QBoxSet
51 51 */
52 52 /*!
53 53 \fn QBoxPlotSeries::boxsetsAdded(QList<QBoxSet *> sets)
54 54 \brief Signal is emitted when a new \a sets of box-and-whiskers data is added to the series.
55 55 */
56 56 /*!
57 57 \fn QBoxPlotSeries::boxsetsRemoved(QList<QBoxSet *> sets)
58 58 \brief Signal is emitted when \a sets of box-and-whiskers data is removed from the series.
59 59 */
60 60 /*!
61 61 \fn QBoxPlotSeries::clicked(QBoxSet *boxset)
62 62 \brief Signal is emitted when the user clicks the \a boxset on the chart.
63 63 */
64 64 /*!
65 65 \fn QBoxPlotSeries::hovered(bool status, QBoxSet *boxset)
66 66 \brief Signal is emitted when there is change in hover \a status over \a boxset.
67 67 */
68 68 /*!
69 69 \fn QBoxPlotSeries::countChanged()
70 70 \brief Signal is emitted when there is change in count of box-and-whiskers items in the series.
71 71 */
72 72 /*!
73 73 \property QBoxPlotSeries::boxOutlineVisible
74 74 \brief This property configures the visibility of the middle box outline.
75 75 */
76 76 /*!
77 77 \property QBoxPlotSeries::boxWidth
78 78 \brief This property configures the width of the box-and-whiskers item. The value signifies the relative
79 79 width of the box-and-whiskers item inside its own slot. The value can between 0.0 and 1.0. Negative values
80 80 are clamped to 0.0 and values over 1.0 are clamped to 1.0.
81 81 */
82 82 /*!
83 83 \property QBoxPlotSeries::pen
84 84 \brief This property configures the pen of the box-and-whiskers items.
85 85 */
86 86 /*!
87 87 \property QBoxPlotSeries::brush
88 88 \brief This property configures the brush of the box-and-whiskers items.
89 89 */
90 90 /*!
91 91 \property QBoxPlotSeries::count
92 92 \brief The count of sets in series.
93 93 */
94 94
95 95 /*!
96 96 \qmlproperty QString BoxPlotSeries::brushFilename
97 97 The name of the file used as a brush for the series.
98 98 */
99 99
100 100 /*!
101 101 \fn void QBoxPlotSeries::boxOutlineVisibilityChanged()
102 102 Signal is emitted when the middle box outline visibility is changed.
103 103 */
104 104 /*!
105 105 \fn void QBoxPlotSeries::boxWidthChanged()
106 106 Signal is emitted when the width of the box-and-whiskers item is changed.
107 107 */
108 108 /*!
109 109 \fn void QBoxPlotSeries::penChanged()
110 110 This signal is emitted when the pen of the box-and-whiskers has changed.
111 111 \sa brush
112 112 */
113 113 /*!
114 114 \fn void QBoxPlotSeries::brushChanged()
115 115 This signal is emitted when the brush of the box-and-whiskers has changed.
116 116 \sa brush
117 117 */
118 118 /*!
119 119 \fn virtual SeriesType QBoxPlotSeries::type() const
120 120 \brief Returns type of series.
121 121 \sa QAbstractSeries, SeriesType
122 122 */
123 123
124 124 /*!
125 125 Constructs empty QBoxPlotSeries.
126 126 QBoxPlotSeries is QObject which is a child of a \a parent.
127 127 */
128 128 QBoxPlotSeries::QBoxPlotSeries(QObject *parent)
129 129 : QAbstractSeries(*new QBoxPlotSeriesPrivate(this), parent)
130 130 {
131 131 }
132 132
133 133 /*!
134 134 Destructor. Removes series from chart.
135 135 */
136 136 QBoxPlotSeries::~QBoxPlotSeries()
137 137 {
138 138 Q_D(QBoxPlotSeries);
139 139 if (d->m_chart)
140 140 d->m_chart->removeSeries(this);
141 141 }
142 142
143 143 /*!
144 144 Adds a single box and whiskers set to series. Takes ownership of the \a set. If the set is null or is already in series, it won't be appended.
145 145 Returns true, if appending succeeded.
146 146 */
147 147 bool QBoxPlotSeries::append(QBoxSet *set)
148 148 {
149 149 Q_D(QBoxPlotSeries);
150 150
151 151 bool success = d->append(set);
152 152 if (success) {
153 153 QList<QBoxSet *> sets;
154 154 sets.append(set);
155 155 set->setParent(this);
156 156 emit boxsetsAdded(sets);
157 157 emit countChanged();
158 158 }
159 159 return success;
160 160 }
161 161
162 162 /*!
163 163 Removes boxset from the series. Deletes the \a set and returns true if successful.
164 164 */
165 165 bool QBoxPlotSeries::remove(QBoxSet *set)
166 166 {
167 167 Q_D(QBoxPlotSeries);
168 168 bool success = d->remove(set);
169 169 if (success) {
170 170 QList<QBoxSet *> sets;
171 171 sets.append(set);
172 172 set->setParent(0);
173 173 emit boxsetsRemoved(sets);
174 174 emit countChanged();
175 175 delete set;
176 176 set = 0;
177 177 }
178 178 return success;
179 179 }
180 180
181 181 /*!
182 182 Takes a single \a set from the series. Does not delete the boxset object.
183 183
184 184 NOTE: The series remains as the boxset's parent object. You must set the
185 185 parent object to take full ownership.
186 186
187 187 Returns true if take was successful.
188 188 */
189 189 bool QBoxPlotSeries::take(QBoxSet *set)
190 190 {
191 191 Q_D(QBoxPlotSeries);
192 192
193 193 bool success = d->remove(set);
194 194 if (success) {
195 195 QList<QBoxSet *> sets;
196 196 sets.append(set);
197 197 emit boxsetsRemoved(sets);
198 198 emit countChanged();
199 199 }
200 200 return success;
201 201 }
202 202
203 203 /*!
204 204 Adds a list of boxsets to series. Takes ownership of the \a sets.
205 205 Returns true, if all sets were appended successfully. If any of the sets is null or is already appended to series,
206 206 nothing is appended and function returns false. If any of the sets is in list more than once, nothing is appended
207 207 and function returns false.
208 208 */
209 209 bool QBoxPlotSeries::append(QList<QBoxSet *> sets)
210 210 {
211 211 Q_D(QBoxPlotSeries);
212 212 bool success = d->append(sets);
213 213 if (success) {
214 214 emit boxsetsAdded(sets);
215 215 emit countChanged();
216 216 }
217 217 return success;
218 218 }
219 219
220 220 /*!
221 221 Insert a box-and-whiskers set to the series at \a index postion. Takes ownership of the \a set. If the set is null or
222 222 is already in series, it won't be appended. Returns true, if inserting succeeded.
223 223
224 224 */
225 225 bool QBoxPlotSeries::insert(int index, QBoxSet *set)
226 226 {
227 227 Q_D(QBoxPlotSeries);
228 228 bool success = d->insert(index, set);
229 229 if (success) {
230 230 QList<QBoxSet *> sets;
231 231 sets.append(set);
232 232 emit boxsetsAdded(sets);
233 233 emit countChanged();
234 234 }
235 235 return success;
236 236 }
237 237
238 238 /*!
239 239 Removes all boxsets from the series. Deletes removed sets.
240 240 */
241 241 void QBoxPlotSeries::clear()
242 242 {
243 243 Q_D(QBoxPlotSeries);
244 244 QList<QBoxSet *> sets = boxSets();
245 245 bool success = d->remove(sets);
246 246 if (success) {
247 247 emit boxsetsRemoved(sets);
248 248 emit countChanged();
249 249 foreach (QBoxSet *set, sets)
250 250 delete set;
251 251 }
252 252 }
253 253
254 254 /*!
255 255 Returns number of sets in series.
256 256 */
257 257 int QBoxPlotSeries::count() const
258 258 {
259 259 Q_D(const QBoxPlotSeries);
260 260 return d->m_boxSets.count();
261 261 }
262 262
263 263 /*!
264 264 Returns a list of sets in series. Keeps ownership of sets.
265 265 */
266 266 QList<QBoxSet *> QBoxPlotSeries::boxSets() const
267 267 {
268 268 Q_D(const QBoxPlotSeries);
269 269 return d->m_boxSets;
270 270 }
271 271
272 272 /*
273 273 Returns QAbstractSeries::SeriesTypeBoxPlot.
274 274 */
275 275 QAbstractSeries::SeriesType QBoxPlotSeries::type() const
276 276 {
277 277 return QAbstractSeries::SeriesTypeBoxPlot;
278 278 }
279 279
280 280 void QBoxPlotSeries::setBoxOutlineVisible(bool visible)
281 281 {
282 282 Q_D(QBoxPlotSeries);
283 283
284 284 if (d->m_boxOutlineVisible != visible) {
285 285 d->m_boxOutlineVisible = visible;
286 286 emit d->updated();
287 287 emit boxOutlineVisibilityChanged();
288 288 }
289 289 }
290 290
291 291 bool QBoxPlotSeries::boxOutlineVisible()
292 292 {
293 293 Q_D(QBoxPlotSeries);
294 294
295 295 return d->m_boxOutlineVisible;
296 296 }
297 297
298 298 void QBoxPlotSeries::setBoxWidth(qreal width)
299 299 {
300 300 Q_D(QBoxPlotSeries);
301 301
302 302 if (width != d->m_boxWidth) {
303 303 if (width < 0.0)
304 304 width = 0.0;
305 305 if (width > 1.0)
306 306 width = 1.0;
307 307 d->m_boxWidth = width;
308 308 emit d->updatedLayout();
309 309 emit boxWidthChanged();
310 310 }
311 311 }
312 312
313 313 qreal QBoxPlotSeries::boxWidth()
314 314 {
315 315 Q_D(QBoxPlotSeries);
316 316
317 317 return d->m_boxWidth;
318 318 }
319 319
320 320 void QBoxPlotSeries::setBrush(const QBrush &brush)
321 321 {
322 322 Q_D(QBoxPlotSeries);
323 323
324 324 if (d->m_brush != brush) {
325 325 d->m_brush = brush;
326 326 emit d->updated();
327 327 emit brushChanged();
328 328 }
329 329 }
330 330
331 331 QBrush QBoxPlotSeries::brush() const
332 332 {
333 333 Q_D(const QBoxPlotSeries);
334 334
335 335 return d->m_brush;
336 336 }
337 337
338 338 void QBoxPlotSeries::setPen(const QPen &pen)
339 339 {
340 340 Q_D(QBoxPlotSeries);
341 341
342 342 if (d->m_pen != pen) {
343 343 d->m_pen = pen;
344 344 emit d->updated();
345 345 emit penChanged();
346 346 }
347 347 }
348 348
349 349 QPen QBoxPlotSeries::pen() const
350 350 {
351 351 Q_D(const QBoxPlotSeries);
352 352
353 353 return d->m_pen;
354 354 }
355 355
356 356 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
357 357
358 358 QBoxPlotSeriesPrivate::QBoxPlotSeriesPrivate(QBoxPlotSeries *q)
359 359 : QAbstractSeriesPrivate(q),
360 360 m_pen(QChartPrivate::defaultPen()),
361 361 m_brush(QChartPrivate::defaultBrush()),
362 362 m_boxOutlineVisible(true),
363 363 m_boxWidth(0.5)
364 364 {
365 365 }
366 366
367 367 QBoxPlotSeriesPrivate::~QBoxPlotSeriesPrivate()
368 368 {
369 369 disconnect(this, 0, 0, 0);
370 370 }
371 371
372 372 void QBoxPlotSeriesPrivate::initializeDomain()
373 373 {
374 374 qreal minX(domain()->minX());
375 375 qreal minY(domain()->minY());
376 376 qreal maxX(domain()->maxX());
377 377 qreal maxY(domain()->maxY());
378 378
379 379 qreal x = m_boxSets.count();
380 380 minX = qMin(minX, qreal(-0.5));
381 381 minY = qMin(minY, min());
382 382 maxX = qMax(maxX, x - qreal(0.5));
383 383 maxY = qMax(maxY, max());
384 384
385 385 domain()->setRange(minX, maxX, minY, maxY);
386 386 }
387 387
388 388 void QBoxPlotSeriesPrivate::initializeAxes()
389 389 {
390 390 foreach (QAbstractAxis* axis, m_axes) {
391 391 if (axis->type() == QAbstractAxis::AxisTypeBarCategory) {
392 392 if (axis->orientation() == Qt::Horizontal)
393 393 populateCategories(qobject_cast<QBarCategoryAxis *>(axis));
394 394 }
395 395 }
396 396 }
397 397
398 398 QAbstractAxis::AxisType QBoxPlotSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
399 399 {
400 400 if (orientation == Qt::Horizontal)
401 401 return QAbstractAxis::AxisTypeBarCategory;
402 402
403 403 return QAbstractAxis::AxisTypeValue;
404 404 }
405 405
406 406 QAbstractAxis* QBoxPlotSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
407 407 {
408 408 if (defaultAxisType(orientation) == QAbstractAxis::AxisTypeBarCategory)
409 409 return new QBarCategoryAxis;
410 410 else
411 411 return new QValueAxis;
412 412 }
413 413
414 414 void QBoxPlotSeriesPrivate::populateCategories(QBarCategoryAxis *axis)
415 415 {
416 416 QStringList categories;
417 417 if (axis->categories().isEmpty()) {
418 418 for (int i(1); i < m_boxSets.count() + 1; i++) {
419 419 QBoxSet *set = m_boxSets.at(i - 1);
420 420 if (set->label().isEmpty())
421 categories << QString::number(i);
421 categories << presenter()->numberToString(i);
422 422 else
423 423 categories << set->label();
424 424 }
425 425 axis->append(categories);
426 426 }
427 427 }
428 428
429 429 void QBoxPlotSeriesPrivate::initializeGraphics(QGraphicsItem *parent)
430 430 {
431 431 Q_Q(QBoxPlotSeries);
432 432
433 433 BoxPlotChartItem *boxPlot = new BoxPlotChartItem(q, parent);
434 434 m_item.reset(boxPlot);
435 435 QAbstractSeriesPrivate::initializeGraphics(parent);
436 436
437 437 if (m_chart) {
438 438 connect(m_chart->d_ptr->m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)), this, SLOT(handleSeriesChange(QAbstractSeries*)) );
439 439 connect(m_chart->d_ptr->m_dataset, SIGNAL(seriesRemoved(QAbstractSeries*)), this, SLOT(handleSeriesRemove(QAbstractSeries*)) );
440 440
441 441 QList<QAbstractSeries *> serieses = m_chart->series();
442 442
443 443 // Tries to find this series from the Chart's list of series and deduce the index
444 444 int index = 0;
445 445 foreach (QAbstractSeries *s, serieses) {
446 446 if (s->type() == QAbstractSeries::SeriesTypeBoxPlot) {
447 447 if (q == static_cast<QBoxPlotSeries *>(s)) {
448 448 boxPlot->m_seriesIndex = index;
449 449 m_index = index;
450 450 }
451 451 index++;
452 452 }
453 453 }
454 454 boxPlot->m_seriesCount = index;
455 455 }
456 456
457 457 // Make BoxPlotChartItem to instantiate box & whisker items
458 458 boxPlot->handleDataStructureChanged();
459 459 }
460 460
461 461 void QBoxPlotSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
462 462 {
463 463 Q_Q(QBoxPlotSeries);
464 464
465 465 const QList<QGradient> gradients = theme->seriesGradients();
466 466
467 467 if (forced || QChartPrivate::defaultBrush() == m_brush) {
468 468 QColor brushColor = ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 0.5);
469 469 q->setBrush(brushColor);
470 470 }
471 471
472 472 if (forced || QChartPrivate::defaultPen() == m_pen) {
473 473 QPen pen = theme->outlinePen();
474 474 pen.setCosmetic(true);
475 475 q->setPen(pen);
476 476 }
477 477 }
478 478
479 479 void QBoxPlotSeriesPrivate::initializeAnimations(QChart::AnimationOptions options)
480 480 {
481 481 BoxPlotChartItem *item = static_cast<BoxPlotChartItem *>(m_item.data());
482 482 Q_ASSERT(item);
483 483 if (item->animation())
484 484 item->animation()->stopAndDestroyLater();
485 485
486 486 if (options.testFlag(QChart::SeriesAnimations))
487 487 m_animation = new BoxPlotAnimation(item);
488 488 else
489 489 m_animation = 0;
490 490 item->setAnimation(m_animation);
491 491
492 492 QAbstractSeriesPrivate::initializeAnimations(options);
493 493 }
494 494
495 495 QList<QLegendMarker*> QBoxPlotSeriesPrivate::createLegendMarkers(QLegend *legend)
496 496 {
497 497 Q_Q(QBoxPlotSeries);
498 498 QList<QLegendMarker *> list;
499 499 return list << new QBoxPlotLegendMarker(q, legend);
500 500 }
501 501
502 502 void QBoxPlotSeriesPrivate::handleSeriesRemove(QAbstractSeries *series)
503 503 {
504 504 Q_Q(QBoxPlotSeries);
505 505
506 506 QBoxPlotSeries *removedSeries = static_cast<QBoxPlotSeries *>(series);
507 507
508 508 if (q == removedSeries && m_animation) {
509 509 m_animation->stopAll();
510 510 QObject::disconnect(m_chart->d_ptr->m_dataset, 0, removedSeries->d_func(), 0);
511 511 }
512 512
513 513 // Test if series removed is me, then don't do anything
514 514 if (q != removedSeries) {
515 515 BoxPlotChartItem *item = static_cast<BoxPlotChartItem *>(m_item.data());
516 516 if (item) {
517 517 item->m_seriesCount = item->m_seriesCount - 1;
518 518 if (removedSeries->d_func()->m_index < m_index) {
519 519 m_index--;
520 520 item->m_seriesIndex = m_index;
521 521 }
522 522
523 523 item->handleDataStructureChanged();
524 524 }
525 525 }
526 526 }
527 527
528 528 void QBoxPlotSeriesPrivate::handleSeriesChange(QAbstractSeries *series)
529 529 {
530 530 Q_UNUSED(series);
531 531
532 532 Q_Q(QBoxPlotSeries);
533 533
534 534 BoxPlotChartItem *boxPlot = static_cast<BoxPlotChartItem *>(m_item.data());
535 535
536 536 if (m_chart) {
537 537 QList<QAbstractSeries *> serieses = m_chart->series();
538 538
539 539 // Tries to find this series from the Chart's list of series and deduce the index
540 540 int index = 0;
541 541 foreach (QAbstractSeries *s, serieses) {
542 542 if (s->type() == QAbstractSeries::SeriesTypeBoxPlot) {
543 543 if (q == static_cast<QBoxPlotSeries *>(s)) {
544 544 boxPlot->m_seriesIndex = index;
545 545 m_index = index;
546 546 }
547 547 index++;
548 548 }
549 549 }
550 550 boxPlot->m_seriesCount = index;
551 551 }
552 552
553 553 boxPlot->handleDataStructureChanged();
554 554 }
555 555
556 556 bool QBoxPlotSeriesPrivate::append(QBoxSet *set)
557 557 {
558 558 if (m_boxSets.contains(set) || (set == 0) || set->d_ptr->m_series)
559 559 return false; // Fail if set is already in list or set is null.
560 560
561 561 m_boxSets.append(set);
562 562 QObject::connect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout()));
563 563 QObject::connect(set->d_ptr.data(), SIGNAL(updatedBox()), this, SIGNAL(updatedBoxes()));
564 564 QObject::connect(set->d_ptr.data(), SIGNAL(restructuredBox()), this, SIGNAL(restructuredBoxes()));
565 565 set->d_ptr->m_series = this;
566 566
567 567 emit restructuredBoxes(); // this notifies boxplotchartitem
568 568 return true;
569 569 }
570 570
571 571 bool QBoxPlotSeriesPrivate::remove(QBoxSet *set)
572 572 {
573 573 if (!m_boxSets.contains(set))
574 574 return false; // Fail if set is not in list
575 575
576 576 set->d_ptr->m_series = 0;
577 577 m_boxSets.removeOne(set);
578 578 QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout()));
579 579 QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedBox()), this, SIGNAL(updatedBoxes()));
580 580 QObject::disconnect(set->d_ptr.data(), SIGNAL(restructuredBox()), this, SIGNAL(restructuredBoxes()));
581 581
582 582 emit restructuredBoxes(); // this notifies boxplotchartitem
583 583 return true;
584 584 }
585 585
586 586 bool QBoxPlotSeriesPrivate::append(QList<QBoxSet *> sets)
587 587 {
588 588 foreach (QBoxSet *set, sets) {
589 589 if ((set == 0) || m_boxSets.contains(set) || set->d_ptr->m_series)
590 590 return false; // Fail if any of the sets is null or is already appended.
591 591 if (sets.count(set) != 1)
592 592 return false; // Also fail if same set is more than once in given list.
593 593 }
594 594
595 595 foreach (QBoxSet *set, sets) {
596 596 m_boxSets.append(set);
597 597 QObject::connect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout()));
598 598 QObject::connect(set->d_ptr.data(), SIGNAL(updatedBox()), this, SIGNAL(updatedBoxes()));
599 599 QObject::connect(set->d_ptr.data(), SIGNAL(restructuredBox()), this, SIGNAL(restructuredBoxes()));
600 600 set->d_ptr->m_series = this;
601 601 }
602 602
603 603 emit restructuredBoxes(); // this notifies boxplotchartitem
604 604 return true;
605 605 }
606 606
607 607 bool QBoxPlotSeriesPrivate::remove(QList<QBoxSet *> sets)
608 608 {
609 609 if (sets.count() == 0)
610 610 return false;
611 611
612 612 foreach (QBoxSet *set, sets) {
613 613 if ((set == 0) || (!m_boxSets.contains(set)))
614 614 return false; // Fail if any of the sets is null or is not in series
615 615 if (sets.count(set) != 1)
616 616 return false; // Also fail if same set is more than once in given list.
617 617 }
618 618
619 619 foreach (QBoxSet *set, sets) {
620 620 set->d_ptr->m_series = 0;
621 621 m_boxSets.removeOne(set);
622 622 QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout()));
623 623 QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedBox()), this, SIGNAL(updatedBoxes()));
624 624 QObject::disconnect(set->d_ptr.data(), SIGNAL(restructuredBox()), this, SIGNAL(restructuredBoxes()));
625 625 }
626 626
627 627 emit restructuredBoxes(); // this notifies boxplotchartitem
628 628
629 629 return true;
630 630 }
631 631
632 632 bool QBoxPlotSeriesPrivate::insert(int index, QBoxSet *set)
633 633 {
634 634 if ((m_boxSets.contains(set)) || (set == 0) || set->d_ptr->m_series)
635 635 return false; // Fail if set is already in list or set is null.
636 636
637 637 m_boxSets.insert(index, set);
638 638 set->d_ptr->m_series = this;
639 639 QObject::connect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout()));
640 640 QObject::connect(set->d_ptr.data(), SIGNAL(updatedBox()), this, SIGNAL(updatedBoxes()));
641 641 QObject::connect(set->d_ptr.data(), SIGNAL(restructuredBox()), this, SIGNAL(restructuredBoxes()));
642 642
643 643 emit restructuredBoxes(); // this notifies boxplotchartitem
644 644 return true;
645 645 }
646 646
647 647 QBoxSet *QBoxPlotSeriesPrivate::boxSetAt(int index)
648 648 {
649 649 return m_boxSets.at(index);
650 650 }
651 651
652 652 qreal QBoxPlotSeriesPrivate::min()
653 653 {
654 654 if (m_boxSets.count() <= 0)
655 655 return 0;
656 656
657 657 qreal min = m_boxSets.at(0)->at(0);
658 658
659 659 foreach (QBoxSet *set, m_boxSets) {
660 660 for (int i = 0; i < 5; i++) {
661 661 if (set->at(i) < min)
662 662 min = set->at(i);
663 663 }
664 664 }
665 665
666 666 return min;
667 667 }
668 668
669 669 qreal QBoxPlotSeriesPrivate::max()
670 670 {
671 671 if (m_boxSets.count() <= 0)
672 672 return 0;
673 673
674 674 qreal max = m_boxSets.at(0)->at(0);
675 675
676 676 foreach (QBoxSet *set, m_boxSets) {
677 677 for (int i = 0; i < 5; i++) {
678 678 if (set->at(i) > max)
679 679 max = set->at(i);
680 680 }
681 681 }
682 682
683 683 return max;
684 684 }
685 685
686 686 #include "moc_qboxplotseries.cpp"
687 687 #include "moc_qboxplotseries_p.cpp"
688 688
689 689 QTCOMMERCIALCHART_END_NAMESPACE
690 690
@@ -1,501 +1,509
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2014 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20 #include "chartpresenter_p.h"
21 21 #include "qchart.h"
22 22 #include "chartitem_p.h"
23 23 #include "qchart_p.h"
24 24 #include "qabstractaxis.h"
25 25 #include "qabstractaxis_p.h"
26 26 #include "chartdataset_p.h"
27 27 #include "chartanimation_p.h"
28 28 #include "qabstractseries_p.h"
29 29 #include "qareaseries.h"
30 30 #include "chartaxiselement_p.h"
31 31 #include "chartbackground_p.h"
32 32 #include "cartesianchartlayout_p.h"
33 33 #include "polarchartlayout_p.h"
34 34 #include "charttitle_p.h"
35 35 #include <QTimer>
36 36 #include <QTextDocument>
37 37
38 38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
39 39
40 40 ChartPresenter::ChartPresenter(QChart *chart, QChart::ChartType type)
41 41 : QObject(chart),
42 42 m_chart(chart),
43 43 m_options(QChart::NoAnimation),
44 44 m_state(ShowState),
45 45 m_background(0),
46 46 m_plotAreaBackground(0),
47 47 m_title(0),
48 48 m_localizeNumbers(true)
49 49 {
50 50 if (type == QChart::ChartTypeCartesian)
51 51 m_layout = new CartesianChartLayout(this);
52 52 else if (type == QChart::ChartTypePolar)
53 53 m_layout = new PolarChartLayout(this);
54 54 Q_ASSERT(m_layout);
55 55 }
56 56
57 57 ChartPresenter::~ChartPresenter()
58 58 {
59 59
60 60 }
61 61
62 62 void ChartPresenter::setGeometry(const QRectF rect)
63 63 {
64 64 if (m_rect != rect) {
65 65 m_rect = rect;
66 66 foreach (ChartItem *chart, m_chartItems) {
67 67 chart->domain()->setSize(rect.size());
68 68 chart->setPos(rect.topLeft());
69 69 }
70 70 }
71 71 }
72 72
73 73 QRectF ChartPresenter::geometry() const
74 74 {
75 75 return m_rect;
76 76 }
77 77
78 78 void ChartPresenter::handleAxisAdded(QAbstractAxis *axis)
79 79 {
80 80 axis->d_ptr->initializeGraphics(rootItem());
81 81 axis->d_ptr->initializeAnimations(m_options);
82 82 ChartAxisElement *item = axis->d_ptr->axisItem();
83 83 item->setPresenter(this);
84 84 item->setThemeManager(m_chart->d_ptr->m_themeManager);
85 85 m_axisItems<<item;
86 86 m_axes<<axis;
87 87 m_layout->invalidate();
88 88 }
89 89
90 90 void ChartPresenter::handleAxisRemoved(QAbstractAxis *axis)
91 91 {
92 92 ChartAxisElement *item = axis->d_ptr->m_item.take();
93 93 item->hide();
94 94 item->disconnect();
95 95 item->deleteLater();
96 96 m_axisItems.removeAll(item);
97 97 m_axes.removeAll(axis);
98 98 m_layout->invalidate();
99 99 }
100 100
101 101
102 102 void ChartPresenter::handleSeriesAdded(QAbstractSeries *series)
103 103 {
104 104 series->d_ptr->initializeGraphics(rootItem());
105 105 series->d_ptr->initializeAnimations(m_options);
106 106 series->d_ptr->setPresenter(this);
107 107 ChartItem *chart = series->d_ptr->chartItem();
108 108 chart->setPresenter(this);
109 109 chart->setThemeManager(m_chart->d_ptr->m_themeManager);
110 110 chart->domain()->setSize(m_rect.size());
111 111 chart->setPos(m_rect.topLeft());
112 112 chart->handleDomainUpdated(); //this could be moved to intializeGraphics when animator is refactored
113 113 m_chartItems<<chart;
114 114 m_series<<series;
115 115 m_layout->invalidate();
116 116 }
117 117
118 118 void ChartPresenter::handleSeriesRemoved(QAbstractSeries *series)
119 119 {
120 120 ChartItem *chart = series->d_ptr->m_item.take();
121 121 chart->hide();
122 122 chart->disconnect();
123 123 chart->deleteLater();
124 124 m_chartItems.removeAll(chart);
125 125 m_series.removeAll(series);
126 126 m_layout->invalidate();
127 127 }
128 128
129 129 void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
130 130 {
131 131 if (m_options != options) {
132 132 QChart::AnimationOptions oldOptions = m_options;
133 133 m_options = options;
134 134 if (options.testFlag(QChart::SeriesAnimations) != oldOptions.testFlag(QChart::SeriesAnimations)) {
135 135 foreach (QAbstractSeries *series, m_series)
136 136 series->d_ptr->initializeAnimations(m_options);
137 137 }
138 138 if (options.testFlag(QChart::GridAxisAnimations) != oldOptions.testFlag(QChart::GridAxisAnimations)) {
139 139 foreach (QAbstractAxis *axis, m_axes)
140 140 axis->d_ptr->initializeAnimations(m_options);
141 141 }
142 142 m_layout->invalidate(); // So that existing animations don't just stop halfway
143 143 }
144 144 }
145 145
146 146 void ChartPresenter::setState(State state,QPointF point)
147 147 {
148 148 m_state=state;
149 149 m_statePoint=point;
150 150 }
151 151
152 152 QChart::AnimationOptions ChartPresenter::animationOptions() const
153 153 {
154 154 return m_options;
155 155 }
156 156
157 157 void ChartPresenter::createBackgroundItem()
158 158 {
159 159 if (!m_background) {
160 160 m_background = new ChartBackground(rootItem());
161 161 m_background->setPen(Qt::NoPen); // Theme doesn't touch pen so don't use default
162 162 m_background->setBrush(QChartPrivate::defaultBrush());
163 163 m_background->setZValue(ChartPresenter::BackgroundZValue);
164 164 }
165 165 }
166 166
167 167 void ChartPresenter::createPlotAreaBackgroundItem()
168 168 {
169 169 if (!m_plotAreaBackground) {
170 170 if (m_chart->chartType() == QChart::ChartTypeCartesian)
171 171 m_plotAreaBackground = new QGraphicsRectItem(rootItem());
172 172 else
173 173 m_plotAreaBackground = new QGraphicsEllipseItem(rootItem());
174 174 // Use transparent pen instead of Qt::NoPen, as Qt::NoPen causes
175 175 // antialising artifacts with axis lines for some reason.
176 176 m_plotAreaBackground->setPen(QPen(Qt::transparent));
177 177 m_plotAreaBackground->setBrush(Qt::NoBrush);
178 178 m_plotAreaBackground->setZValue(ChartPresenter::PlotAreaZValue);
179 179 m_plotAreaBackground->setVisible(false);
180 180 }
181 181 }
182 182
183 183 void ChartPresenter::createTitleItem()
184 184 {
185 185 if (!m_title) {
186 186 m_title = new ChartTitle(rootItem());
187 187 m_title->setZValue(ChartPresenter::BackgroundZValue);
188 188 }
189 189 }
190 190
191 191 void ChartPresenter::startAnimation(ChartAnimation *animation)
192 192 {
193 193 animation->stop();
194 194 QTimer::singleShot(0, animation, SLOT(startChartAnimation()));
195 195 }
196 196
197 197 void ChartPresenter::setBackgroundBrush(const QBrush &brush)
198 198 {
199 199 createBackgroundItem();
200 200 m_background->setBrush(brush);
201 201 m_layout->invalidate();
202 202 }
203 203
204 204 QBrush ChartPresenter::backgroundBrush() const
205 205 {
206 206 if (!m_background)
207 207 return QBrush();
208 208 return m_background->brush();
209 209 }
210 210
211 211 void ChartPresenter::setBackgroundPen(const QPen &pen)
212 212 {
213 213 createBackgroundItem();
214 214 m_background->setPen(pen);
215 215 m_layout->invalidate();
216 216 }
217 217
218 218 QPen ChartPresenter::backgroundPen() const
219 219 {
220 220 if (!m_background)
221 221 return QPen();
222 222 return m_background->pen();
223 223 }
224 224
225 225 void ChartPresenter::setBackgroundRoundness(qreal diameter)
226 226 {
227 227 createBackgroundItem();
228 228 m_background->setDiameter(diameter);
229 229 m_layout->invalidate();
230 230 }
231 231
232 232 qreal ChartPresenter::backgroundRoundness() const
233 233 {
234 234 if (!m_background)
235 235 return 0;
236 236 return m_background->diameter();
237 237 }
238 238
239 239 void ChartPresenter::setPlotAreaBackgroundBrush(const QBrush &brush)
240 240 {
241 241 createPlotAreaBackgroundItem();
242 242 m_plotAreaBackground->setBrush(brush);
243 243 m_layout->invalidate();
244 244 }
245 245
246 246 QBrush ChartPresenter::plotAreaBackgroundBrush() const
247 247 {
248 248 if (!m_plotAreaBackground)
249 249 return QBrush();
250 250 return m_plotAreaBackground->brush();
251 251 }
252 252
253 253 void ChartPresenter::setPlotAreaBackgroundPen(const QPen &pen)
254 254 {
255 255 createPlotAreaBackgroundItem();
256 256 m_plotAreaBackground->setPen(pen);
257 257 m_layout->invalidate();
258 258 }
259 259
260 260 QPen ChartPresenter::plotAreaBackgroundPen() const
261 261 {
262 262 if (!m_plotAreaBackground)
263 263 return QPen();
264 264 return m_plotAreaBackground->pen();
265 265 }
266 266
267 267 void ChartPresenter::setTitle(const QString &title)
268 268 {
269 269 createTitleItem();
270 270 m_title->setText(title);
271 271 m_layout->invalidate();
272 272 }
273 273
274 274 QString ChartPresenter::title() const
275 275 {
276 276 if (!m_title)
277 277 return QString();
278 278 return m_title->text();
279 279 }
280 280
281 281 void ChartPresenter::setTitleFont(const QFont &font)
282 282 {
283 283 createTitleItem();
284 284 m_title->setFont(font);
285 285 m_layout->invalidate();
286 286 }
287 287
288 288 QFont ChartPresenter::titleFont() const
289 289 {
290 290 if (!m_title)
291 291 return QFont();
292 292 return m_title->font();
293 293 }
294 294
295 295 void ChartPresenter::setTitleBrush(const QBrush &brush)
296 296 {
297 297 createTitleItem();
298 298 m_title->setDefaultTextColor(brush.color());
299 299 m_layout->invalidate();
300 300 }
301 301
302 302 QBrush ChartPresenter::titleBrush() const
303 303 {
304 304 if (!m_title)
305 305 return QBrush();
306 306 return QBrush(m_title->defaultTextColor());
307 307 }
308 308
309 309 void ChartPresenter::setBackgroundVisible(bool visible)
310 310 {
311 311 createBackgroundItem();
312 312 m_background->setVisible(visible);
313 313 }
314 314
315 315
316 316 bool ChartPresenter::isBackgroundVisible() const
317 317 {
318 318 if (!m_background)
319 319 return false;
320 320 return m_background->isVisible();
321 321 }
322 322
323 323 void ChartPresenter::setPlotAreaBackgroundVisible(bool visible)
324 324 {
325 325 createPlotAreaBackgroundItem();
326 326 m_plotAreaBackground->setVisible(visible);
327 327 }
328 328
329 329 bool ChartPresenter::isPlotAreaBackgroundVisible() const
330 330 {
331 331 if (!m_plotAreaBackground)
332 332 return false;
333 333 return m_plotAreaBackground->isVisible();
334 334 }
335 335
336 336 void ChartPresenter::setBackgroundDropShadowEnabled(bool enabled)
337 337 {
338 338 createBackgroundItem();
339 339 m_background->setDropShadowEnabled(enabled);
340 340 }
341 341
342 342 bool ChartPresenter::isBackgroundDropShadowEnabled() const
343 343 {
344 344 if (!m_background)
345 345 return false;
346 346 return m_background->isDropShadowEnabled();
347 347 }
348 348
349 349 void ChartPresenter::setLocalizeNumbers(bool localize)
350 350 {
351 351 m_localizeNumbers = localize;
352 352 m_layout->invalidate();
353 353 }
354 354
355 355 void ChartPresenter::setLocale(const QLocale &locale)
356 356 {
357 357 m_locale = locale;
358 358 m_layout->invalidate();
359 359 }
360 360
361 361 AbstractChartLayout *ChartPresenter::layout()
362 362 {
363 363 return m_layout;
364 364 }
365 365
366 366 QLegend *ChartPresenter::legend()
367 367 {
368 368 return m_chart->legend();
369 369 }
370 370
371 371 void ChartPresenter::setVisible(bool visible)
372 372 {
373 373 m_chart->setVisible(visible);
374 374 }
375 375
376 376 ChartBackground *ChartPresenter::backgroundElement()
377 377 {
378 378 return m_background;
379 379 }
380 380
381 381 QAbstractGraphicsShapeItem *ChartPresenter::plotAreaElement()
382 382 {
383 383 return m_plotAreaBackground;
384 384 }
385 385
386 386 QList<ChartAxisElement *> ChartPresenter::axisItems() const
387 387 {
388 388 return m_axisItems;
389 389 }
390 390
391 391 QList<ChartItem *> ChartPresenter::chartItems() const
392 392 {
393 393 return m_chartItems;
394 394 }
395 395
396 396 ChartTitle *ChartPresenter::titleElement()
397 397 {
398 398 return m_title;
399 399 }
400 400
401 401 QRectF ChartPresenter::textBoundingRect(const QFont &font, const QString &text, qreal angle)
402 402 {
403 403 static QGraphicsTextItem dummyTextItem;
404 404 static bool initMargin = true;
405 405 if (initMargin) {
406 406 dummyTextItem.document()->setDocumentMargin(textMargin());
407 407 initMargin = false;
408 408 }
409 409
410 410 dummyTextItem.setFont(font);
411 411 dummyTextItem.setHtml(text);
412 412 QRectF boundingRect = dummyTextItem.boundingRect();
413 413
414 414 // Take rotation into account
415 415 if (angle) {
416 416 QTransform transform;
417 417 transform.rotate(angle);
418 418 boundingRect = transform.mapRect(boundingRect);
419 419 }
420 420
421 421 return boundingRect;
422 422 }
423 423
424 424 // boundingRect parameter returns the rotated bounding rect of the text
425 425 QString ChartPresenter::truncatedText(const QFont &font, const QString &text, qreal angle,
426 426 qreal maxWidth, qreal maxHeight, QRectF &boundingRect)
427 427 {
428 428 QString truncatedString(text);
429 429 boundingRect = textBoundingRect(font, truncatedString, angle);
430 430 if (boundingRect.width() > maxWidth || boundingRect.height() > maxHeight) {
431 431 // It can be assumed that almost any amount of string manipulation is faster
432 432 // than calculating one bounding rectangle, so first prepare a list of truncated strings
433 433 // to try.
434 434 static const char *truncateMatchString = "&#?[0-9a-zA-Z]*;$";
435 435 static QRegExp truncateMatcher(truncateMatchString);
436 436
437 437 QVector<QString> testStrings(text.length());
438 438 int count(0);
439 439 static QLatin1Char closeTag('>');
440 440 static QLatin1Char openTag('<');
441 441 static QLatin1Char semiColon(';');
442 442 static QLatin1String ellipsis("...");
443 443 while (truncatedString.length() > 1) {
444 444 int chopIndex(-1);
445 445 int chopCount(1);
446 446 QChar lastChar(truncatedString.at(truncatedString.length() - 1));
447 447
448 448 if (lastChar == closeTag)
449 449 chopIndex = truncatedString.lastIndexOf(openTag);
450 450 else if (lastChar == semiColon)
451 451 chopIndex = truncateMatcher.indexIn(truncatedString, 0);
452 452
453 453 if (chopIndex != -1)
454 454 chopCount = truncatedString.length() - chopIndex;
455 455 truncatedString.chop(chopCount);
456 456 testStrings[count] = truncatedString + ellipsis;
457 457 count++;
458 458 }
459 459
460 460 // Binary search for best fit
461 461 int minIndex(0);
462 462 int maxIndex(count - 1);
463 463 int bestIndex(count);
464 464 QRectF checkRect;
465 465
466 466 while (maxIndex >= minIndex) {
467 467 int mid = (maxIndex + minIndex) / 2;
468 468 checkRect = textBoundingRect(font, testStrings.at(mid), angle);
469 469 if (checkRect.width() > maxWidth || checkRect.height() > maxHeight) {
470 470 // Checked index too large, all under this are also too large
471 471 minIndex = mid + 1;
472 472 } else {
473 473 // Checked index fits, all over this also fit
474 474 maxIndex = mid - 1;
475 475 bestIndex = mid;
476 476 boundingRect = checkRect;
477 477 }
478 478 }
479 479 // Default to "..." if nothing fits
480 480 if (bestIndex == count) {
481 481 boundingRect = textBoundingRect(font, ellipsis, angle);
482 482 truncatedString = ellipsis;
483 483 } else {
484 484 truncatedString = testStrings.at(bestIndex);
485 485 }
486 486 }
487 487
488 488 return truncatedString;
489 489 }
490 490
491 491 QString ChartPresenter::numberToString(double value, char f, int prec)
492 492 {
493 493 if (m_localizeNumbers)
494 494 return m_locale.toString(value, f, prec);
495 495 else
496 496 return QString::number(value, f, prec);
497 497 }
498 498
499 QString ChartPresenter::numberToString(int value)
500 {
501 if (m_localizeNumbers)
502 return m_locale.toString(value);
503 else
504 return QString::number(value);
505 }
506
499 507 #include "moc_chartpresenter_p.cpp"
500 508
501 509 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,191 +1,192
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2014 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef CHARTPRESENTER_H
31 31 #define CHARTPRESENTER_H
32 32
33 33 #include "qchartglobal.h"
34 34 #include "qchart.h" //because of QChart::ChartThemeId
35 35 #include <QRectF>
36 36 #include <QMargins>
37 37 #include <QLocale>
38 38
39 39 QTCOMMERCIALCHART_BEGIN_NAMESPACE
40 40
41 41 class ChartItem;
42 42 class AxisItem;
43 43 class QAbstractSeries;
44 44 class ChartDataSet;
45 45 class AbstractDomain;
46 46 class ChartAxisElement;
47 47 class ChartAnimator;
48 48 class ChartBackground;
49 49 class ChartTitle;
50 50 class ChartAnimation;
51 51 class AbstractChartLayout;
52 52
53 53 class ChartPresenter: public QObject
54 54 {
55 55 Q_OBJECT
56 56 public:
57 57 enum ZValues {
58 58 BackgroundZValue = -1,
59 59 PlotAreaZValue,
60 60 ShadesZValue,
61 61 GridZValue,
62 62 AxisZValue,
63 63 SeriesZValue,
64 64 LineChartZValue = SeriesZValue,
65 65 SplineChartZValue = SeriesZValue,
66 66 BarSeriesZValue = SeriesZValue,
67 67 ScatterSeriesZValue = SeriesZValue,
68 68 PieSeriesZValue = SeriesZValue,
69 69 BoxPlotSeriesZValue = SeriesZValue,
70 70 LegendZValue,
71 71 TopMostZValue
72 72 };
73 73
74 74 enum State {
75 75 ShowState,
76 76 ScrollUpState,
77 77 ScrollDownState,
78 78 ScrollLeftState,
79 79 ScrollRightState,
80 80 ZoomInState,
81 81 ZoomOutState
82 82 };
83 83
84 84 ChartPresenter(QChart *chart, QChart::ChartType type);
85 85 virtual ~ChartPresenter();
86 86
87 87
88 88 void setGeometry(QRectF rect);
89 89 QRectF geometry() const;
90 90
91 91 QGraphicsItem *rootItem(){ return m_chart; }
92 92 ChartBackground *backgroundElement();
93 93 QAbstractGraphicsShapeItem *plotAreaElement();
94 94 ChartTitle *titleElement();
95 95 QList<ChartAxisElement *> axisItems() const;
96 96 QList<ChartItem *> chartItems() const;
97 97
98 98 QLegend *legend();
99 99
100 100 void setBackgroundBrush(const QBrush &brush);
101 101 QBrush backgroundBrush() const;
102 102
103 103 void setBackgroundPen(const QPen &pen);
104 104 QPen backgroundPen() const;
105 105
106 106 void setBackgroundRoundness(qreal diameter);
107 107 qreal backgroundRoundness() const;
108 108
109 109 void setPlotAreaBackgroundBrush(const QBrush &brush);
110 110 QBrush plotAreaBackgroundBrush() const;
111 111
112 112 void setPlotAreaBackgroundPen(const QPen &pen);
113 113 QPen plotAreaBackgroundPen() const;
114 114
115 115 void setTitle(const QString &title);
116 116 QString title() const;
117 117
118 118 void setTitleFont(const QFont &font);
119 119 QFont titleFont() const;
120 120
121 121 void setTitleBrush(const QBrush &brush);
122 122 QBrush titleBrush() const;
123 123
124 124 void setBackgroundVisible(bool visible);
125 125 bool isBackgroundVisible() const;
126 126
127 127 void setPlotAreaBackgroundVisible(bool visible);
128 128 bool isPlotAreaBackgroundVisible() const;
129 129
130 130 void setBackgroundDropShadowEnabled(bool enabled);
131 131 bool isBackgroundDropShadowEnabled() const;
132 132
133 133 void setLocalizeNumbers(bool localize);
134 134 inline bool localizeNumbers() const { return m_localizeNumbers; }
135 135 void setLocale(const QLocale &locale);
136 136 inline const QLocale &locale() const { return m_locale; }
137 137
138 138 void setVisible(bool visible);
139 139
140 140 void setAnimationOptions(QChart::AnimationOptions options);
141 141 QChart::AnimationOptions animationOptions() const;
142 142
143 143 void startAnimation(ChartAnimation *animation);
144 144
145 145 void setState(State state,QPointF point);
146 146 State state() const { return m_state; }
147 147 QPointF statePoint() const { return m_statePoint; }
148 148 AbstractChartLayout *layout();
149 149
150 150 QChart::ChartType chartType() const { return m_chart->chartType(); }
151 151 QChart *chart() { return m_chart; }
152 152
153 153 static QRectF textBoundingRect(const QFont &font, const QString &text, qreal angle = 0.0);
154 154 static QString truncatedText(const QFont &font, const QString &text, qreal angle,
155 155 qreal maxWidth, qreal maxHeight, QRectF &boundingRect);
156 156 inline static qreal textMargin() { return qreal(0.5); }
157 157
158 158 QString numberToString(double value, char f = 'g', int prec = 6);
159 QString numberToString(int value);
159 160
160 161 private:
161 162 void createBackgroundItem();
162 163 void createPlotAreaBackgroundItem();
163 164 void createTitleItem();
164 165
165 166 public Q_SLOTS:
166 167 void handleSeriesAdded(QAbstractSeries *series);
167 168 void handleSeriesRemoved(QAbstractSeries *series);
168 169 void handleAxisAdded(QAbstractAxis *axis);
169 170 void handleAxisRemoved(QAbstractAxis *axis);
170 171
171 172 private:
172 173 QChart *m_chart;
173 174 QList<ChartItem *> m_chartItems;
174 175 QList<ChartAxisElement *> m_axisItems;
175 176 QList<QAbstractSeries *> m_series;
176 177 QList<QAbstractAxis *> m_axes;
177 178 QChart::AnimationOptions m_options;
178 179 State m_state;
179 180 QPointF m_statePoint;
180 181 AbstractChartLayout *m_layout;
181 182 ChartBackground *m_background;
182 183 QAbstractGraphicsShapeItem *m_plotAreaBackground;
183 184 ChartTitle *m_title;
184 185 QRectF m_rect;
185 186 bool m_localizeNumbers;
186 187 QLocale m_locale;
187 188 };
188 189
189 190 QTCOMMERCIALCHART_END_NAMESPACE
190 191
191 192 #endif /* CHARTPRESENTER_H */
General Comments 0
You need to be logged in to leave comments. Login now