File indexing completed on 2024-05-12 04:43:20

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2007-2010 by Adam Pigg (adam@piggz.co.uk)
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0012  * Lesser General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Lesser General Public
0015  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #include "KReportItemChart.h"
0019 
0020 #include "KReportRenderObjects.h"
0021 #include "KReportUtils.h"
0022 
0023 #include <KDChartBarDiagram>
0024 #include <KDChartThreeDBarAttributes>
0025 #include <KDChartLineDiagram>
0026 #include <KDChartThreeDLineAttributes>
0027 #include <KDChartPieDiagram>
0028 #include <KDChartThreeDPieAttributes>
0029 #include <KDChartLegend>
0030 #include <KDChartCartesianAxis>
0031 #include <KDChartChart>
0032 #include <KDChartBackgroundAttributes>
0033 #include <KDChartAbstractDiagram>
0034 #include <KDChartAbstractCoordinatePlane>
0035 #include <KDChartPosition>
0036 
0037 #include <KProperty>
0038 #include <KPropertySet>
0039 
0040 #include "kreportplugin_debug.h"
0041 #include <QFontDatabase>
0042 
0043 typedef QVector<double> datalist;
0044 
0045 KReportItemChart::KReportItemChart()
0046     : m_reportData(nullptr)
0047 {
0048     createProperties();
0049 }
0050 
0051 KReportItemChart::KReportItemChart(QDomNode *element)
0052     : KReportItemChart()
0053 {
0054     QDomElement e = element->toElement();
0055     m_name->setValue(KReportUtils::readNameAttribute(e));
0056     setItemDataSource(e.attribute("report:item-data-source"));
0057     Z = e.attribute("report:z-index").toDouble();
0058     m_chartType->setValue(e.attribute("report:chart-type").toInt());
0059     m_chartSubType->setValue(e.attribute("report:chart-sub-type").toInt());
0060     m_threeD->setValue(e.attribute("report:three-dimensions"));
0061 
0062     m_colorScheme->setValue(e.attribute("report:chart-color-scheme"));
0063     m_aa->setValue(e.attribute("report:antialiased"));
0064     m_xTitle->setValue(e.attribute("report:title-x-axis"));
0065     m_yTitle->setValue(e.attribute("report:title-y-axis"));
0066     m_backgroundColor->setValue(e.attribute("report:background-color"));
0067     m_displayLegend->setValue(e.attribute("report:display-legend"));
0068     m_legendPosition->setValue(e.attribute("report:legend-position"));
0069     m_legendOrientation->setValue(e.attribute("report:legend-orientation"));
0070     m_linkMaster->setValue(e.attribute("report:link-master"));
0071     m_linkChild->setValue(e.attribute("report:link-child"));
0072 
0073     parseReportRect(e, &m_pos, &m_size);
0074 }
0075 
0076 
0077 KReportItemChart::~KReportItemChart()
0078 {
0079     delete m_set;
0080 }
0081 
0082 void KReportItemChart::createProperties()
0083 {
0084     m_chartWidget = 0;
0085     m_set = new KPropertySet;
0086 
0087     createDataSourceProperty();
0088 
0089     m_font = new KProperty("font", QFontDatabase::systemFont(QFontDatabase::GeneralFont), tr("Font"), tr("Field Font"));
0090 
0091     QList<QVariant> keys;
0092     keys << 1 << 2 << 3 << 4 << 5;
0093     QStringList strings;
0094     strings << tr("Bar") << tr("Line") << tr("Pie") << tr("Ring") << tr("Polar");
0095     KProperty::ListData *typeData = new KProperty::ListData(keys, strings);
0096     m_chartType = new KProperty("chart-type", typeData, 1, tr("Chart Type"));
0097 
0098     keys.clear();
0099     strings.clear();
0100     keys << 0 << 1 << 2 << 3;
0101     strings << tr("Normal") << tr("Stacked") << tr("Percent") << tr("Rows");
0102 
0103     KProperty::ListData *subData = new KProperty::ListData(keys, strings);
0104 
0105     m_chartSubType = new KProperty("chart-sub-type", subData, 0, tr("Chart Sub Type"));
0106 
0107     keys.clear();
0108     strings.clear();
0109     QStringList stringkeys;
0110     stringkeys << "default" << "rainbow" << "subdued";
0111     strings << tr("Default") << tr("Rainbow") << tr("Subdued");
0112     m_colorScheme = new KProperty("chart-color-scheme", stringkeys, strings, "default", tr("Color Scheme"));
0113 
0114     m_threeD = new KProperty("three-dimensions", QVariant(false),
0115         tr("3D", "Three dimensions"));
0116     m_aa = new KProperty("antialiased", QVariant(false), tr("Antialiased"));
0117 
0118     m_xTitle = new KProperty("title-x-axis", QString(), tr("X Axis Title"));
0119     m_yTitle = new KProperty("title-y-axis", QString(), tr("Y Axis Title"));
0120 
0121     m_displayLegend = new KProperty("display-legend", true, tr("Display Legend"));
0122 
0123     keys.clear();
0124     strings.clear();
0125     keys << (int)KDChartEnums::PositionNorth
0126             << (int)KDChartEnums::PositionEast
0127             << (int)KDChartEnums::PositionSouth
0128             << (int)KDChartEnums::PositionWest;
0129     QStringList names = KDChart::Position::printableNames();
0130     foreach (const QVariant &pos, keys) {
0131         strings << names[pos.toInt()-1];
0132     }
0133     subData = new KProperty::ListData(keys, strings);
0134     m_legendPosition = new KProperty("legend-position", subData, (int)KDChartEnums::PositionEast, tr("Legend Position"));
0135 
0136     keys.clear();
0137     strings.clear();
0138     keys << Qt::Horizontal << Qt::Vertical;
0139     strings << tr("Horizontal") << tr("Vertical");
0140     subData = new KProperty::ListData(keys, strings);
0141     m_legendOrientation = new KProperty("legend-orientation", subData, Qt::Vertical, tr("Legend Orientation"));
0142 
0143     m_backgroundColor = new KProperty("background-color", Qt::white,
0144         tr("Background Color"));
0145 
0146     m_linkMaster = new KProperty("link-master", QString(), tr("Link Master"),
0147         tr("Fields from master data source"));
0148     m_linkChild = new KProperty("link-child", QString(), tr("Link Child"),
0149         tr("Fields from child data source"));
0150 
0151     addDefaultProperties();
0152     m_set->addProperty(m_chartType);
0153     m_set->addProperty(m_chartSubType);
0154     m_set->addProperty(m_font);
0155     m_set->addProperty(m_colorScheme);
0156     m_set->addProperty(m_threeD);
0157     m_set->addProperty(m_aa);
0158     m_set->addProperty(m_xTitle);
0159     m_set->addProperty(m_yTitle);
0160     m_set->addProperty(m_backgroundColor);
0161     m_set->addProperty(m_displayLegend);
0162     m_set->addProperty(m_legendPosition);
0163     m_set->addProperty(m_legendOrientation);
0164     m_set->addProperty(m_linkMaster);
0165     m_set->addProperty(m_linkChild);
0166 
0167     set3D(false);
0168     setAA(false);
0169     setColorScheme("default");
0170 }
0171 
0172 void KReportItemChart::set3D(bool td)
0173 {
0174     if (m_chartWidget && m_chartWidget->barDiagram()) {
0175         KDChart::BarDiagram *bar = m_chartWidget->barDiagram();
0176         bar->setPen(QPen(Qt::black));
0177 
0178         KDChart::ThreeDBarAttributes threed = bar->threeDBarAttributes();
0179         threed.setEnabled(td);
0180         threed.setDepth(10);
0181         threed.setAngle(15);
0182         threed.setUseShadowColors(true);
0183         bar->setThreeDBarAttributes(threed);
0184     }
0185 
0186 }
0187 void KReportItemChart::setAA(bool aa)
0188 {
0189     if (m_chartWidget && m_chartWidget->diagram()) {
0190         m_chartWidget->diagram()->setAntiAliasing(aa);
0191     }
0192 }
0193 
0194 void KReportItemChart::setColorScheme(const QString &cs)
0195 {
0196     if (m_chartWidget && m_chartWidget->diagram()) {
0197         if (cs == "rainbow") {
0198             m_chartWidget->diagram()->useRainbowColors();
0199         } else if (cs == "subdued") {
0200             m_chartWidget->diagram()->useSubduedColors();
0201         } else {
0202             m_chartWidget->diagram()->useDefaultColors();
0203         }
0204     }
0205 }
0206 
0207 void KReportItemChart::setConnection(const KReportData *c)
0208 {
0209     m_reportData = c;
0210     populateData();
0211 }
0212 
0213 void KReportItemChart::populateData()
0214 {
0215     QVector<datalist> data;
0216     QStringList labels;
0217 
0218     QStringList fn;
0219 
0220 
0221     delete m_chartWidget;
0222     m_chartWidget = 0;
0223 
0224     if (m_reportData) {
0225         QString src = itemDataSource();
0226 
0227         if (!src.isEmpty()) {
0228             KReportData *curs = m_reportData->create(src);
0229             if (curs) {
0230                 const QStringList keys = m_links.keys();
0231                 foreach(const QString& field, keys) {
0232                     //kreportpluginDebug() << "Adding Expression:" << field << m_links[field];
0233                     curs->addExpression(field, m_links[field], '=');
0234                 }
0235             }
0236             if (curs && curs->open()) {
0237                 fn = curs->fieldNames();
0238                 //resize the data lists to match the number of columns
0239                 int cols = fn.count() - 1;
0240                 if ( cols > 0 ) {
0241                     data.resize(cols);
0242                 }
0243 
0244                 m_chartWidget = new KDChart::Widget();
0245                 m_chartWidget->setType((KDChart::Widget::ChartType) m_chartType->value().toInt());
0246                 m_chartWidget->setSubType((KDChart::Widget::SubType) m_chartSubType->value().toInt());
0247                 set3D(m_threeD->value().toBool());
0248                 setAA(m_aa->value().toBool());
0249                 setColorScheme(m_colorScheme->value().toString());
0250                 setBackgroundColor(m_backgroundColor->value().value<QColor>());
0251                 curs->moveFirst();
0252                 //bool status = true;
0253                 do {
0254                     labels << curs->value(0).toString();
0255                     for (int i = 1; i <= cols; ++i) {
0256                         data[i - 1] << curs->value(i).toDouble();
0257                     }
0258                 } while (curs->moveNext());
0259 
0260                 for (int i = 1; i <= cols; ++i) {
0261                     m_chartWidget->setDataset(i - 1, data[i - 1], fn[i]);
0262                 }
0263 
0264                 setLegend(m_displayLegend->value().toBool(), fn);
0265 
0266                 //Add the axis
0267                 setAxis(m_xTitle->value().toString(), m_yTitle->value().toString());
0268 
0269                 //Add the bottom labels
0270                 if (m_chartWidget->barDiagram() || m_chartWidget->lineDiagram()) {
0271                     KDChart::AbstractCartesianDiagram *dia = static_cast<KDChart::AbstractCartesianDiagram*>(m_chartWidget->diagram());
0272 
0273                     foreach(KDChart::CartesianAxis* axis, dia->axes()) {
0274                         if (axis->position() == KDChart::CartesianAxis::Bottom) {
0275                             axis->setLabels(labels);
0276                         }
0277                     }
0278                 }
0279             } else {
0280                 kreportpluginWarning() << "Unable to open data set";
0281             }
0282             delete curs;
0283             curs = 0;
0284         } else {
0285             kreportpluginWarning() << "No source set";
0286         }
0287     } else {
0288         kreportpluginWarning() << "No connection!";
0289     }
0290 }
0291 
0292 QStringList KReportItemChart::masterFields() const
0293 {
0294     return m_linkMaster->value().toString().split(',');
0295 }
0296 
0297 void KReportItemChart::setLinkData(QString fld, QVariant val)
0298 {
0299     //kreportpluginDebug() << "Field: " << fld << "is" << val;
0300     m_links[fld] = val;
0301 }
0302 
0303 void KReportItemChart::setAxis(const QString& xa, const QString &ya)
0304 {
0305     if (!m_chartWidget) {
0306         return;
0307     }
0308     Q_ASSERT(m_chartWidget);
0309 
0310     if (m_chartWidget->barDiagram() || m_chartWidget->lineDiagram()) {
0311         KDChart::AbstractCartesianDiagram *dia = static_cast<KDChart::AbstractCartesianDiagram*>(m_chartWidget->diagram());
0312         KDChart::CartesianAxis *xAxis = 0;
0313         KDChart::CartesianAxis *yAxis = 0;
0314 
0315         //delete existing axis
0316         foreach(KDChart::CartesianAxis* axis, dia->axes()) {
0317             if (axis->position() == KDChart::CartesianAxis::Bottom) {
0318                 xAxis = axis;
0319             }
0320             if (axis->position() == KDChart::CartesianAxis::Left) {
0321                 yAxis = axis;
0322             }
0323         }
0324 
0325         if (!xAxis) {
0326             xAxis =  new KDChart::CartesianAxis(static_cast<KDChart::AbstractCartesianDiagram*>(m_chartWidget->diagram()));
0327             xAxis->setPosition(KDChart::CartesianAxis::Bottom);
0328             dia->addAxis(xAxis);
0329         }
0330 
0331         if (!yAxis) {
0332             yAxis = new KDChart::CartesianAxis(static_cast<KDChart::AbstractCartesianDiagram*>(m_chartWidget->diagram()));
0333             yAxis->setPosition(KDChart::CartesianAxis::Left);
0334             dia->addAxis(yAxis);
0335         }
0336 
0337         xAxis->setTitleText(xa);
0338         yAxis->setTitleText(ya);
0339     }
0340 }
0341 
0342 void KReportItemChart::setBackgroundColor(const QColor&)
0343 {
0344     //Set the background color
0345     if (!m_chartWidget) {
0346         return;
0347     }
0348     KDChart::Chart *cht = m_chartWidget->diagram()->coordinatePlane()->parent();
0349 
0350     KDChart::BackgroundAttributes ba;
0351 
0352     ba.setVisible(true);
0353     ba.setBrush(m_backgroundColor->value().value<QColor>());
0354     cht->setBackgroundAttributes(ba);
0355 }
0356 
0357 void KReportItemChart::setLegend(bool le, const QStringList &legends)
0358 {
0359     //Add the legend
0360     if (m_chartWidget) {
0361         if (le && ! legends.isEmpty()) {
0362             m_chartWidget->addLegend(KDChart::Position((KDChartEnums::PositionValue)m_legendPosition->value().toInt()));
0363             m_chartWidget->legend()->setOrientation((Qt::Orientation) m_legendOrientation->value().toInt());
0364             m_chartWidget->legend()->setTitleText("Legend");
0365             for (int i = 1; i < legends.count(); ++i) {
0366                 m_chartWidget->legend()->setText(i - 1, legends[i]);
0367             }
0368 
0369             m_chartWidget->legend()->setShowLines(true);
0370         } else {
0371             if (m_chartWidget->legend()) {
0372                 m_chartWidget->takeLegend(m_chartWidget->legend());
0373             }
0374         }
0375     }
0376 }
0377 
0378 // RTTI
0379 QString KReportItemChart::typeName() const
0380 {
0381     return "chart";
0382 }
0383 
0384 int KReportItemChart::renderReportData(OROPage *page, OROSection *section, const QPointF &offset,
0385                                         KReportData *data, KReportScriptHandler *script)
0386 {
0387     Q_UNUSED(script);
0388 
0389     setConnection(data);
0390 
0391     QStringList masters = masterFields();
0392     for (int i = 0; i < masters.size(); ++i) {
0393         if (!masters[i].simplified().isEmpty()) {
0394             setLinkData(masters[i], data->value(masters[i]));
0395         }
0396     }
0397     populateData();
0398     if (widget()) {
0399         OROPicture * pic = new OROPicture();
0400         widget()->setFixedSize(m_size.toScene().toSize());
0401 
0402         QPainter p(pic->picture());
0403 
0404         widget()->diagram()->coordinatePlane()->parent()->paint(&p, QRect(QPoint(0, 0), m_size.toScene().toSize()));
0405 
0406         QPointF pos = m_pos.toScene();
0407         QSizeF size = m_size.toScene();
0408 
0409         pos += offset;
0410 
0411         pic->setPosition(pos);
0412         pic->setSize(size);
0413         if (page) page->addPrimitive(pic);
0414 
0415         OROPicture *p2 = static_cast<OROPicture*>(pic->clone());
0416         if (p2) {
0417             p2->setPosition(m_pos.toPoint());
0418             if (section) {
0419                 section->addPrimitive(p2);
0420             }
0421         }
0422     }
0423 
0424     return 0;
0425 }