KReport

KReportItemChart.cpp
1 /* This file is part of the KDE project
2  * Copyright (C) 2007-2010 by Adam Pigg ([email protected])
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "KReportItemChart.h"
19 
20 #include "KReportRenderObjects.h"
21 #include "KReportUtils.h"
22 
23 #include <KDChartBarDiagram>
24 #include <KDChartThreeDBarAttributes>
25 #include <KDChartLineDiagram>
26 #include <KDChartThreeDLineAttributes>
27 #include <KDChartPieDiagram>
28 #include <KDChartThreeDPieAttributes>
29 #include <KDChartLegend>
30 #include <KDChartCartesianAxis>
31 #include <KDChartChart>
32 #include <KDChartBackgroundAttributes>
33 #include <KDChartAbstractDiagram>
34 #include <KDChartAbstractCoordinatePlane>
35 #include <KDChartPosition>
36 
37 #include <KProperty>
38 #include <KPropertySet>
39 
40 #include "kreportplugin_debug.h"
41 #include <QFontDatabase>
42 
44 
45 KReportItemChart::KReportItemChart()
46  : m_reportData(nullptr)
47 {
48  createProperties();
49 }
50 
51 KReportItemChart::KReportItemChart(QDomNode *element)
52  : KReportItemChart()
53 {
54  QDomElement e = element->toElement();
55  m_name->setValue(KReportUtils::readNameAttribute(e));
56  setItemDataSource(e.attribute("report:item-data-source"));
57  Z = e.attribute("report:z-index").toDouble();
58  m_chartType->setValue(e.attribute("report:chart-type").toInt());
59  m_chartSubType->setValue(e.attribute("report:chart-sub-type").toInt());
60  m_threeD->setValue(e.attribute("report:three-dimensions"));
61 
62  m_colorScheme->setValue(e.attribute("report:chart-color-scheme"));
63  m_aa->setValue(e.attribute("report:antialiased"));
64  m_xTitle->setValue(e.attribute("report:title-x-axis"));
65  m_yTitle->setValue(e.attribute("report:title-y-axis"));
66  m_backgroundColor->setValue(e.attribute("report:background-color"));
67  m_displayLegend->setValue(e.attribute("report:display-legend"));
68  m_legendPosition->setValue(e.attribute("report:legend-position"));
69  m_legendOrientation->setValue(e.attribute("report:legend-orientation"));
70  m_linkMaster->setValue(e.attribute("report:link-master"));
71  m_linkChild->setValue(e.attribute("report:link-child"));
72 
73  parseReportRect(e, &m_pos, &m_size);
74 }
75 
76 
77 KReportItemChart::~KReportItemChart()
78 {
79  delete m_set;
80 }
81 
82 void KReportItemChart::createProperties()
83 {
84  m_chartWidget = 0;
85  m_set = new KPropertySet;
86 
87  createDataSourceProperty();
88 
89  m_font = new KProperty("font", QFontDatabase::systemFont(QFontDatabase::GeneralFont), tr("Font"), tr("Field Font"));
90 
91  QList<QVariant> keys;
92  keys << 1 << 2 << 3 << 4 << 5;
93  QStringList strings;
94  strings << tr("Bar") << tr("Line") << tr("Pie") << tr("Ring") << tr("Polar");
95  KProperty::ListData *typeData = new KProperty::ListData(keys, strings);
96  m_chartType = new KProperty("chart-type", typeData, 1, tr("Chart Type"));
97 
98  keys.clear();
99  strings.clear();
100  keys << 0 << 1 << 2 << 3;
101  strings << tr("Normal") << tr("Stacked") << tr("Percent") << tr("Rows");
102 
103  KProperty::ListData *subData = new KProperty::ListData(keys, strings);
104 
105  m_chartSubType = new KProperty("chart-sub-type", subData, 0, tr("Chart Sub Type"));
106 
107  keys.clear();
108  strings.clear();
109  QStringList stringkeys;
110  stringkeys << "default" << "rainbow" << "subdued";
111  strings << tr("Default") << tr("Rainbow") << tr("Subdued");
112  m_colorScheme = new KProperty("chart-color-scheme", stringkeys, strings, "default", tr("Color Scheme"));
113 
114  m_threeD = new KProperty("three-dimensions", QVariant(false),
115  tr("3D", "Three dimensions"));
116  m_aa = new KProperty("antialiased", QVariant(false), tr("Antialiased"));
117 
118  m_xTitle = new KProperty("title-x-axis", QString(), tr("X Axis Title"));
119  m_yTitle = new KProperty("title-y-axis", QString(), tr("Y Axis Title"));
120 
121  m_displayLegend = new KProperty("display-legend", true, tr("Display Legend"));
122 
123  keys.clear();
124  strings.clear();
125  keys << (int)KDChartEnums::PositionNorth
126  << (int)KDChartEnums::PositionEast
127  << (int)KDChartEnums::PositionSouth
128  << (int)KDChartEnums::PositionWest;
129  QStringList names = KDChart::Position::printableNames();
130  foreach (const QVariant &pos, keys) {
131  strings << names[pos.toInt()-1];
132  }
133  subData = new KProperty::ListData(keys, strings);
134  m_legendPosition = new KProperty("legend-position", subData, (int)KDChartEnums::PositionEast, tr("Legend Position"));
135 
136  keys.clear();
137  strings.clear();
138  keys << Qt::Horizontal << Qt::Vertical;
139  strings << tr("Horizontal") << tr("Vertical");
140  subData = new KProperty::ListData(keys, strings);
141  m_legendOrientation = new KProperty("legend-orientation", subData, Qt::Vertical, tr("Legend Orientation"));
142 
143  m_backgroundColor = new KProperty("background-color", Qt::white,
144  tr("Background Color"));
145 
146  m_linkMaster = new KProperty("link-master", QString(), tr("Link Master"),
147  tr("Fields from master data source"));
148  m_linkChild = new KProperty("link-child", QString(), tr("Link Child"),
149  tr("Fields from child data source"));
150 
151  addDefaultProperties();
152  m_set->addProperty(m_chartType);
153  m_set->addProperty(m_chartSubType);
154  m_set->addProperty(m_font);
155  m_set->addProperty(m_colorScheme);
156  m_set->addProperty(m_threeD);
157  m_set->addProperty(m_aa);
158  m_set->addProperty(m_xTitle);
159  m_set->addProperty(m_yTitle);
160  m_set->addProperty(m_backgroundColor);
161  m_set->addProperty(m_displayLegend);
162  m_set->addProperty(m_legendPosition);
163  m_set->addProperty(m_legendOrientation);
164  m_set->addProperty(m_linkMaster);
165  m_set->addProperty(m_linkChild);
166 
167  set3D(false);
168  setAA(false);
169  setColorScheme("default");
170 }
171 
172 void KReportItemChart::set3D(bool td)
173 {
174  if (m_chartWidget && m_chartWidget->barDiagram()) {
175  KDChart::BarDiagram *bar = m_chartWidget->barDiagram();
176  bar->setPen(QPen(Qt::black));
177 
178  KDChart::ThreeDBarAttributes threed = bar->threeDBarAttributes();
179  threed.setEnabled(td);
180  threed.setDepth(10);
181  threed.setAngle(15);
182  threed.setUseShadowColors(true);
183  bar->setThreeDBarAttributes(threed);
184  }
185 
186 }
187 void KReportItemChart::setAA(bool aa)
188 {
189  if (m_chartWidget && m_chartWidget->diagram()) {
190  m_chartWidget->diagram()->setAntiAliasing(aa);
191  }
192 }
193 
194 void KReportItemChart::setColorScheme(const QString &cs)
195 {
196  if (m_chartWidget && m_chartWidget->diagram()) {
197  if (cs == "rainbow") {
198  m_chartWidget->diagram()->useRainbowColors();
199  } else if (cs == "subdued") {
200  m_chartWidget->diagram()->useSubduedColors();
201  } else {
202  m_chartWidget->diagram()->useDefaultColors();
203  }
204  }
205 }
206 
207 void KReportItemChart::setConnection(const KReportData *c)
208 {
209  m_reportData = c;
210  populateData();
211 }
212 
213 void KReportItemChart::populateData()
214 {
216  QStringList labels;
217 
218  QStringList fn;
219 
220 
221  delete m_chartWidget;
222  m_chartWidget = 0;
223 
224  if (m_reportData) {
225  QString src = itemDataSource();
226 
227  if (!src.isEmpty()) {
228  KReportData *curs = m_reportData->create(src);
229  if (curs) {
230  const QStringList keys = m_links.keys();
231  foreach(const QString& field, keys) {
232  //kreportpluginDebug() << "Adding Expression:" << field << m_links[field];
233  curs->addExpression(field, m_links[field], '=');
234  }
235  }
236  if (curs && curs->open()) {
237  fn = curs->fieldNames();
238  //resize the data lists to match the number of columns
239  int cols = fn.count() - 1;
240  if ( cols > 0 ) {
241  data.resize(cols);
242  }
243 
244  m_chartWidget = new KDChart::Widget();
245  m_chartWidget->setType((KDChart::Widget::ChartType) m_chartType->value().toInt());
246  m_chartWidget->setSubType((KDChart::Widget::SubType) m_chartSubType->value().toInt());
247  set3D(m_threeD->value().toBool());
248  setAA(m_aa->value().toBool());
249  setColorScheme(m_colorScheme->value().toString());
250  setBackgroundColor(m_backgroundColor->value().value<QColor>());
251  curs->moveFirst();
252  //bool status = true;
253  do {
254  labels << curs->value(0).toString();
255  for (int i = 1; i <= cols; ++i) {
256  data[i - 1] << curs->value(i).toDouble();
257  }
258  } while (curs->moveNext());
259 
260  for (int i = 1; i <= cols; ++i) {
261  m_chartWidget->setDataset(i - 1, data[i - 1], fn[i]);
262  }
263 
264  setLegend(m_displayLegend->value().toBool(), fn);
265 
266  //Add the axis
267  setAxis(m_xTitle->value().toString(), m_yTitle->value().toString());
268 
269  //Add the bottom labels
270  if (m_chartWidget->barDiagram() || m_chartWidget->lineDiagram()) {
271  KDChart::AbstractCartesianDiagram *dia = static_cast<KDChart::AbstractCartesianDiagram*>(m_chartWidget->diagram());
272 
273  foreach(KDChart::CartesianAxis* axis, dia->axes()) {
274  if (axis->position() == KDChart::CartesianAxis::Bottom) {
275  axis->setLabels(labels);
276  }
277  }
278  }
279  } else {
280  kreportpluginWarning() << "Unable to open data set";
281  }
282  delete curs;
283  curs = 0;
284  } else {
285  kreportpluginWarning() << "No source set";
286  }
287  } else {
288  kreportpluginWarning() << "No connection!";
289  }
290 }
291 
292 QStringList KReportItemChart::masterFields() const
293 {
294  return m_linkMaster->value().toString().split(',');
295 }
296 
297 void KReportItemChart::setLinkData(QString fld, QVariant val)
298 {
299  //kreportpluginDebug() << "Field: " << fld << "is" << val;
300  m_links[fld] = val;
301 }
302 
303 void KReportItemChart::setAxis(const QString& xa, const QString &ya)
304 {
305  if (!m_chartWidget) {
306  return;
307  }
308  Q_ASSERT(m_chartWidget);
309 
310  if (m_chartWidget->barDiagram() || m_chartWidget->lineDiagram()) {
311  KDChart::AbstractCartesianDiagram *dia = static_cast<KDChart::AbstractCartesianDiagram*>(m_chartWidget->diagram());
312  KDChart::CartesianAxis *xAxis = 0;
313  KDChart::CartesianAxis *yAxis = 0;
314 
315  //delete existing axis
316  foreach(KDChart::CartesianAxis* axis, dia->axes()) {
317  if (axis->position() == KDChart::CartesianAxis::Bottom) {
318  xAxis = axis;
319  }
320  if (axis->position() == KDChart::CartesianAxis::Left) {
321  yAxis = axis;
322  }
323  }
324 
325  if (!xAxis) {
326  xAxis = new KDChart::CartesianAxis(static_cast<KDChart::AbstractCartesianDiagram*>(m_chartWidget->diagram()));
327  xAxis->setPosition(KDChart::CartesianAxis::Bottom);
328  dia->addAxis(xAxis);
329  }
330 
331  if (!yAxis) {
332  yAxis = new KDChart::CartesianAxis(static_cast<KDChart::AbstractCartesianDiagram*>(m_chartWidget->diagram()));
333  yAxis->setPosition(KDChart::CartesianAxis::Left);
334  dia->addAxis(yAxis);
335  }
336 
337  xAxis->setTitleText(xa);
338  yAxis->setTitleText(ya);
339  }
340 }
341 
342 void KReportItemChart::setBackgroundColor(const QColor&)
343 {
344  //Set the background color
345  if (!m_chartWidget) {
346  return;
347  }
348  KDChart::Chart *cht = m_chartWidget->diagram()->coordinatePlane()->parent();
349 
350  KDChart::BackgroundAttributes ba;
351 
352  ba.setVisible(true);
353  ba.setBrush(m_backgroundColor->value().value<QColor>());
354  cht->setBackgroundAttributes(ba);
355 }
356 
357 void KReportItemChart::setLegend(bool le, const QStringList &legends)
358 {
359  //Add the legend
360  if (m_chartWidget) {
361  if (le && ! legends.isEmpty()) {
362  m_chartWidget->addLegend(KDChart::Position((KDChartEnums::PositionValue)m_legendPosition->value().toInt()));
363  m_chartWidget->legend()->setOrientation((Qt::Orientation) m_legendOrientation->value().toInt());
364  m_chartWidget->legend()->setTitleText("Legend");
365  for (int i = 1; i < legends.count(); ++i) {
366  m_chartWidget->legend()->setText(i - 1, legends[i]);
367  }
368 
369  m_chartWidget->legend()->setShowLines(true);
370  } else {
371  if (m_chartWidget->legend()) {
372  m_chartWidget->takeLegend(m_chartWidget->legend());
373  }
374  }
375  }
376 }
377 
378 // RTTI
379 QString KReportItemChart::typeName() const
380 {
381  return "chart";
382 }
383 
384 int KReportItemChart::renderReportData(OROPage *page, OROSection *section, const QPointF &offset,
385  KReportData *data, KReportScriptHandler *script)
386 {
387  Q_UNUSED(script);
388 
389  setConnection(data);
390 
391  QStringList masters = masterFields();
392  for (int i = 0; i < masters.size(); ++i) {
393  if (!masters[i].simplified().isEmpty()) {
394  setLinkData(masters[i], data->value(masters[i]));
395  }
396  }
397  populateData();
398  if (widget()) {
399  OROPicture * pic = new OROPicture();
400  widget()->setFixedSize(m_size.toScene().toSize());
401 
402  QPainter p(pic->picture());
403 
404  widget()->diagram()->coordinatePlane()->parent()->paint(&p, QRect(QPoint(0, 0), m_size.toScene().toSize()));
405 
406  QPointF pos = m_pos.toScene();
407  QSizeF size = m_size.toScene();
408 
409  pos += offset;
410 
411  pic->setPosition(pos);
412  pic->setSize(size);
413  if (page) page->addPrimitive(pic);
414 
415  OROPicture *p2 = static_cast<OROPicture*>(pic->clone());
416  if (p2) {
417  p2->setPosition(m_pos.toPoint());
418  if (section) {
419  section->addPrimitive(p2);
420  }
421  }
422  }
423 
424  return 0;
425 }
QDomElement toElement() const const
int count(const T &value) const const
T value() const const
virtual int renderReportData(OROPage *page, OROSection *section, const QPointF &offset, KReportDataSource *dataSource, KReportScriptHandler *script)
Render a complex item that uses a sub query as a data source.
QFont systemFont(QFontDatabase::SystemFont type)
Represents a single page in a document and may contain zero or more OROPrimitive objects all of which...
QVariant data(int key) const const
int size() const const
Horizontal
bool isEmpty() const const
Defines a picture. A picture is different to an image, in that it is drawn using commands.
int toInt(bool *ok, int base) const const
bool isEmpty() const const
double toDouble(bool *ok) const const
Represents a single a single row in a document and may contain zero or more OROPrimitives.
void clear()
QPointF pos() const const
QString attribute(const QString &name, const QString &defValue) const const
T value(int i) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Feb 7 2023 04:17:37 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.