diff --git a/charts.pro b/charts.pro index a597146..0d86d66 100644 --- a/charts.pro +++ b/charts.pro @@ -13,8 +13,8 @@ integrated_build:{ CONFIG += ordered QMAKE_CXXFLAGS += -g -Wall -unix:QMAKE_DISTCLEAN += -r build bin doc/html -win32:QMAKE_DISTCLEAN += /Q /s build bin doc\\html +unix:QMAKE_DISTCLEAN += -r build bin include lib doc/html +win32:QMAKE_DISTCLEAN += /Q /s build bin include lib doc\\html # install feature file feature.path = $$[QT_INSTALL_DATA]/mkspecs/features diff --git a/doc/images/chartview_example.jpg b/doc/images/chartview_example.jpg index 7b0456c6802ae9d2825ee02946969ec98087e363..5e9f6ab353ec2333fb9db6fbb744767ab1b91c34 100644 GIT binary patch literal 11337 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 w1RsUBy(!Thhw)jt3T6Nw!u4h0DeAcK%lKuA|@ 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 Zrg=LR=8>@32pLPyosX_zu;#0&{{fc{Fwp=2 literal 13349 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 J_oCiR{~z*&iQNDI diff --git a/doc/images/chartview_example_pie.jpg b/doc/images/chartview_example_pie.jpg index 4d7497084c87cdebef2026d824cc09827f78199a..51a1c46b1d3abfe741e7b7881a0451e99830e356 100644 GIT binary patch literal 12750 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 L;QtrE=o9}7JMMNZ literal 8453 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 literal 25195 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 E7lHEFQUCw| diff --git a/doc/images/chartview_example_theme.jpg b/doc/images/chartview_example_theme.jpg index caa0ca09a420c891ad56b3e09dd9035951a04412..01c4c95af8397c920c80e2f632f771a33005bc92 100644 GIT binary patch literal 10287 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 F_h07VPpbd` diff --git a/doc/src/classes.qdoc b/doc/src/classes.qdoc index ada5dfe..48bf3e4 100644 --- a/doc/src/classes.qdoc +++ b/doc/src/classes.qdoc @@ -13,19 +13,18 @@ diff --git a/doc/src/example-linechart.qdoc b/doc/src/example-linechart.qdoc index 3ff0e49..3fac9dc 100644 --- a/doc/src/example-linechart.qdoc +++ b/doc/src/example-linechart.qdoc @@ -5,5 +5,22 @@ The example shows how to create simple line chart. - ... + \image linechart.png + + To create line charts, QLineSeries instance is needed. Here we create two line series and we set the color and width of line. + + \snippet ../example/linechart/main.cpp 1 + + We add data to be shown to both series. We can use add() member function or use stream operator. + + \snippet ../example/linechart/main.cpp 2 + + In the end we create QChartView instance, set title, set anti-aliasing and add both series. + + \snippet ../example/linechart/main.cpp 3 + + Chart is ready to be shown. + + \snippet ../example/linechart/main.cpp 4 + */ \ No newline at end of file diff --git a/doc/src/index.qdoc b/doc/src/index.qdoc index efe0e0a..cef910e 100644 --- a/doc/src/index.qdoc +++ b/doc/src/index.qdoc @@ -7,17 +7,21 @@ qtcommercial

- QCharts is a part of Qt Commercial addons package. It provides a set of simple chart components which are available for Qt Commercial customers. - It uses Qt Graphics View Framework, therefore charts can be easily integrated 2D modern user interfaces. QCharts can be used as QWidgets, QGraphicsWidget or QML elements. - Users can easily create impressive graphs by selecting one of the charts themes. + QCharts is a part of Qt Commercial addons package. It provides a set of easy to use chart + components which are available for Qt Commercial customers. It uses Qt Graphics View + Framework, therefore charts can be easily integrated to modern 2D user interfaces. QCharts can + be used as QWidgets, QGraphicsWidget or QML elements. Users can easily create impressive + graphs by selecting one of the charts themes.

+ - + - + + diff --git a/doc/style/offline.css b/doc/style/offline.css index 56ff06b..484fe88 100644 --- a/doc/style/offline.css +++ b/doc/style/offline.css @@ -3,10 +3,12 @@ .qchart { - width: 80%; + width:1000px; margin-left: auto; margin-right: auto; margin-top: 50px; + max-width:100%; + overflow-x: auto; } .qchart img @@ -16,13 +18,16 @@ .qchart table { - margin-top: 50px; + width:1000px; + margin-top: 50px; + max-width:100%; } /* basic elements */ html { color: #000000; + min-width: 1000px; background: #FFFFFF; } table diff --git a/example/axischart/main.cpp b/example/axischart/main.cpp index 602161e..26b4b65 100644 --- a/example/axischart/main.cpp +++ b/example/axischart/main.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include @@ -16,11 +16,11 @@ int main(int argc, char *argv[]) QMainWindow window; - QLineChartSeries* series0 = new QLineChartSeries(); + QLineSeries* series0 = new QLineSeries(); QPen blue(Qt::blue); blue.setWidth(3); series0->setPen(blue); - QLineChartSeries* series1 = new QLineChartSeries(); + QLineSeries* series1 = new QLineSeries(); QPen red(Qt::red); red.setWidth(3); series1->setPen(red); diff --git a/example/barchart/main.cpp b/example/barchart/main.cpp index ed8b3c6..b97060f 100644 --- a/example/barchart/main.cpp +++ b/example/barchart/main.cpp @@ -1,9 +1,9 @@ #include #include #include -#include +#include #include -#include +#include QTCOMMERCIALCHART_USE_NAMESPACE @@ -13,9 +13,9 @@ int main(int argc, char *argv[]) QMainWindow window; //! [1] - // Create category - QBarCategory *category = new QBarCategory; - *category << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "June" << "Jul" << "Aug" << "Sep" << "Oct" << "Nov" << "Dec"; + // Define categories + QStringList catecories; + catecories << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "June" << "Jul" << "Aug" << "Sep" << "Oct" << "Nov" << "Dec"; //! [1] //! [2] @@ -36,7 +36,7 @@ int main(int argc, char *argv[]) //! [3] // Create series and add sets to it - QBarChartSeries* series= new QBarChartSeries(category); + QBarSeries* series= new QBarSeries(catecories); series->addBarSet(set0); series->addBarSet(set1); @@ -47,8 +47,8 @@ int main(int argc, char *argv[]) //! [4] // Enable some features - series->enableToolTip(); - series->enableFloatingValues(); + series->setToolTipEnabled(); + series->setFloatingValuesEnabled(); //! [4] //! [5] diff --git a/example/chartview/main.cpp b/example/chartview/main.cpp index 1f7af3e..68abd23 100644 --- a/example/chartview/main.cpp +++ b/example/chartview/main.cpp @@ -2,12 +2,12 @@ #include #include #include -#include +#include #include -#include +#include #include -#include #include +#include QTCOMMERCIALCHART_USE_NAMESPACE @@ -19,19 +19,22 @@ int main(int argc, char *argv[]) // Create chart view QChartView *chartView = new QChartView(); chartView->setRenderHint(QPainter::Antialiasing); + chartView->setChartTitle("Simple Line Chart"); // Add series to the chart - QLineChartSeries *line = new QLineChartSeries(); + QLineSeries *line = new QLineSeries(); line->add(0.0, 0.8); line->add(1.1, 1.1); line->add(2.0, 2.5); chartView->addSeries(line); //! [1] + chartView->setChartTitle("\'Scietific\' theme"); //! [2] // Change theme chartView->setChartTheme(QChart::ChartThemeScientific); //! [2] + chartView->setChartTitle("Simple Pie Chart"); //! [3] // Add pie series // ... @@ -41,6 +44,7 @@ int main(int argc, char *argv[]) chartView->addSeries(pie); //! [3] + chartView->setChartTitle("Simple Scatter Chart"); //! [4] // Add scatter series // ... @@ -52,14 +56,15 @@ int main(int argc, char *argv[]) chartView->addSeries(scatter); //! [4] + chartView->setChartTitle("Simple Bar Chart"); //! [5] // ... // Add bar series - QBarCategory *barCategory = new QBarCategory(); - *barCategory << "Jan" + QStringList barCategory; + barCategory << "Jan" << "Feb" << "Mar"; - QBarChartSeries *bar = new QBarChartSeries(barCategory); + QBarSeries *bar = new QBarSeries(barCategory); QBarSet *barSet = new QBarSet("Sales"); *barSet << 123.2 << 301.3 @@ -69,8 +74,9 @@ int main(int argc, char *argv[]) //! [5] QMainWindow w; - w.resize(380, 250); + w.resize(400, 300); w.setCentralWidget(chartView); + w.setWindowFlags(Qt::FramelessWindowHint); w.show(); return a.exec(); diff --git a/example/colorlinechart/main.cpp b/example/colorlinechart/main.cpp index f26b674..ae123b6 100644 --- a/example/colorlinechart/main.cpp +++ b/example/colorlinechart/main.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include @@ -15,11 +15,11 @@ int main(int argc, char *argv[]) QMainWindow window; - QLineChartSeries* series0 = new QLineChartSeries(); + QLineSeries* series0 = new QLineSeries(); QPen blue(Qt::blue); blue.setWidth(3); series0->setPen(blue); - QLineChartSeries* series1 = new QLineChartSeries(); + QLineSeries* series1 = new QLineSeries(); QPen red(Qt::red); red.setWidth(3); series1->setPen(red); diff --git a/example/dynamiclinechart/main.cpp b/example/dynamiclinechart/main.cpp index a968731..33c2dd7 100644 --- a/example/dynamiclinechart/main.cpp +++ b/example/dynamiclinechart/main.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include "wavegenerator.h" @@ -13,11 +13,11 @@ int main(int argc, char *argv[]) QMainWindow window; - QLineChartSeries* series0 = new QLineChartSeries(); + QLineSeries* series0 = new QLineSeries(); QPen blue(Qt::blue); blue.setWidth(3); series0->setPen(blue); - QLineChartSeries* series1 = new QLineChartSeries(); + QLineSeries* series1 = new QLineSeries(); QPen red(Qt::red); red.setWidth(3); series1->setPen(red); diff --git a/example/dynamiclinechart/wavegenerator.h b/example/dynamiclinechart/wavegenerator.h index eca8dc9..1bfcdb5 100644 --- a/example/dynamiclinechart/wavegenerator.h +++ b/example/dynamiclinechart/wavegenerator.h @@ -2,7 +2,7 @@ #include #include #include -#include +#include QTCOMMERCIALCHART_USE_NAMESPACE @@ -14,7 +14,7 @@ class WaveGenerator: public QObject Q_OBJECT public: - WaveGenerator(QLineChartSeries* series1, QLineChartSeries* series2) : + WaveGenerator(QLineSeries* series1, QLineSeries* series2) : m_series1(series1), m_series2(series2), m_wave(0), @@ -44,16 +44,16 @@ public slots: for (qreal i = 0, x = 0; x <= 2*PI; x+=m_step, i++) { fluctuate = qrand() % 100; - m_series1->set(i, x, fabs(sin(x)*fluctuate)); + m_series1->replace(x, fabs(sin(x)*fluctuate)); fluctuate = qrand() % 100; - m_series2->set(i, x, fabs(cos(x)*fluctuate)); + m_series2->replace(x, fabs(cos(x)*fluctuate)); } } private: - QLineChartSeries* m_series1; - QLineChartSeries* m_series2; + QLineSeries* m_series1; + QLineSeries* m_series2; int m_wave; qreal m_step; QTimer m_timer; diff --git a/example/gdpbarchart/widget.cpp b/example/gdpbarchart/widget.cpp index 97afda2..1fbcc64 100644 --- a/example/gdpbarchart/widget.cpp +++ b/example/gdpbarchart/widget.cpp @@ -13,12 +13,12 @@ #include #include #include -#include #include #include #include #include #include +#include QTCOMMERCIALCHART_USE_NAMESPACE @@ -86,7 +86,7 @@ Widget::Widget(QWidget *parent) // hide axis X labels QChartAxis* axis = chartArea->axisX(); -// axis->setLabelsVisible(false); + // axis->setLabelsVisible(false); // newAxis.setLabelsOrientation(QChartAxis::LabelsOrientationSlide); } @@ -102,7 +102,7 @@ Widget::~Widget() */ void Widget::refreshChart() { - chartArea->removeAllSeries(); + chartArea->removeAllSeries(); // selected countries items list is not sorted. copy the values to QStringlist and sort them. QStringList selectedCountriesStrings; @@ -120,12 +120,13 @@ void Widget::refreshChart() qSort(selectedYearsInts.begin(), selectedYearsInts.end(), qGreater()); if (barChartRadioButton->isChecked()) - { + { // use the sorted selected coutries list to initialize BarCategory - QBarCategory* category = new QBarCategory; + QStringList category; for (int i = 0; i < selectedCountriesStrings.size(); i++) - *category << selectedCountriesStrings[i]; + category << selectedCountriesStrings[i]; QBarChartSeries* series0 = new QBarChartSeries(category); + series0 = new QBarSeries(category); // prepare the selected counries SQL query QString countriesQuery = "country IN ("; @@ -206,7 +207,7 @@ void Widget::refreshChart() qDebug() << "Putting 0 for the missing data" << " : " << QString("%1").arg(selectedYearsInts[i]) << " " << query.value(0).toInt(); } } -// chartArea->axisX()->setRange(selectedYearsInts[selectedYearsInts.size() - 1] + 1, selectedYearsInts[0] - 1); + // chartArea->axisX()->setRange(selectedYearsInts[selectedYearsInts.size() - 1] + 1, selectedYearsInts[0] - 1); chartArea->addSeries(series); } chartArea->axisX()->setRange(selectedYearsInts[selectedYearsInts.size() - 1] + 1, selectedYearsInts[0] - 1); diff --git a/example/gdpbarchart/widget.h b/example/gdpbarchart/widget.h index 6bb1f76..186a9b8 100644 --- a/example/gdpbarchart/widget.h +++ b/example/gdpbarchart/widget.h @@ -3,7 +3,6 @@ #include #include -#include #include QTCOMMERCIALCHART_USE_NAMESPACE @@ -28,7 +27,6 @@ private: QListWidget* countrieslist; QListWidget* yearslist; QSqlDatabase db; -// QBarChartSeries* series0; QRadioButton* barChartRadioButton; QRadioButton* scatterChartRadioButton; }; diff --git a/example/linechart/main.cpp b/example/linechart/main.cpp index 30e52c4..9485d9e 100644 --- a/example/linechart/main.cpp +++ b/example/linechart/main.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include @@ -11,16 +11,14 @@ int main(int argc, char *argv[]) { QApplication a(argc, argv); - QMainWindow window; - //![1] - QLineChartSeries* series0 = new QLineChartSeries(); + QLineSeries* series0 = new QLineSeries(); QPen blue(Qt::blue); blue.setWidth(3); series0->setPen(blue); - QLineChartSeries* series1 = new QLineChartSeries(); + QLineSeries* series1 = new QLineSeries(); QPen red(Qt::red); red.setWidth(3); series1->setPen(red); @@ -33,24 +31,23 @@ int main(int argc, char *argv[]) series0->add(7, 4); series0->add(10,5); - series1->add(1, 1); - series1->add(3, 3); - series1->add(7, 6); - series1->add(8, 3); - series1->add(10,2); + *series1 << QPointF(1, 1) << QPointF(3, 3) << QPointF(7, 6) << QPointF(8, 3) << QPointF(10,2); //![2] //![3] + QMainWindow window; QChartView* chartView = new QChartView(&window); - chartView->setRenderHint(QPainter::Antialiasing); chartView->setChartTitle("Basic line chart example"); + chartView->setRenderHint(QPainter::Antialiasing); + chartView->addSeries(series0); chartView->addSeries(series1); //![3] - +//![4] window.setCentralWidget(chartView); window.resize(400, 300); window.show(); +//![4] return a.exec(); } diff --git a/example/percentbarchart/main.cpp b/example/percentbarchart/main.cpp index 48a7069..e19e1a9 100644 --- a/example/percentbarchart/main.cpp +++ b/example/percentbarchart/main.cpp @@ -1,10 +1,10 @@ #include #include #include -#include -#include +#include #include #include +#include QTCOMMERCIALCHART_USE_NAMESPACE @@ -14,9 +14,9 @@ int main(int argc, char *argv[]) QMainWindow window; //! [1] - // Create category - QBarCategory *category = new QBarCategory; - *category << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "June" << "Jul" << "Aug" << "Sep" << "Oct" << "Nov" << "Dec"; + // Define categories + QStringList categories; + categories << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "June" << "Jul" << "Aug" << "Sep" << "Oct" << "Nov" << "Dec"; //! [1] //! [2] @@ -36,7 +36,7 @@ int main(int argc, char *argv[]) //! [3] // Create series and add sets to it - QPercentBarChartSeries* series = new QPercentBarChartSeries(category); + QPercentBarSeries* series = new QPercentBarSeries(categories); series->addBarSet(set0); series->addBarSet(set1); @@ -47,8 +47,8 @@ int main(int argc, char *argv[]) //! [4] // Enable features - series->enableToolTip(); - series->enableFloatingValues(); + series->setToolTipEnabled(); + series->setFloatingValuesEnabled(); //! [4] //! [5] diff --git a/example/piechart/customslice.cpp b/example/piechart/customslice.cpp deleted file mode 100644 index 4132a55..0000000 --- a/example/piechart/customslice.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "customslice.h" - -CustomSlice::CustomSlice(qreal value, QObject* parent) - :QPieSlice(parent) -{ - setValue(value); - setLabelVisible(true); - setExploded(true); - connect(this, SIGNAL(changed()), this, SLOT(updateLabel())); - connect(this, SIGNAL(hoverEnter()), this, SLOT(toggleExploded())); - connect(this, SIGNAL(hoverLeave()), this, SLOT(toggleExploded())); -} - -void CustomSlice::updateLabel() -{ - setLabel(QString::number(this->percentage()*100) + "%"); -} - -void CustomSlice::toggleExploded() -{ - setExploded(!isExploded()); -} diff --git a/example/piechart/customslice.h b/example/piechart/customslice.h deleted file mode 100644 index 3c6ccf4..0000000 --- a/example/piechart/customslice.h +++ /dev/null @@ -1,15 +0,0 @@ -#include - -QTCOMMERCIALCHART_USE_NAMESPACE - -class CustomSlice : public QPieSlice -{ - Q_OBJECT - -public: - CustomSlice(qreal value, QObject* parent = 0); - -public Q_SLOTS: - void updateLabel(); - void toggleExploded(); -}; diff --git a/example/piechart/main.cpp b/example/piechart/main.cpp index ebb9058..5a73bfc 100644 --- a/example/piechart/main.cpp +++ b/example/piechart/main.cpp @@ -4,7 +4,6 @@ #include #include #include -#include "customslice.h" QTCOMMERCIALCHART_USE_NAMESPACE @@ -14,23 +13,22 @@ int main(int argc, char *argv[]) QMainWindow window; + QChartView* chartView = new QChartView(&window); + + //! [1] QPieSeries *series = new QPieSeries(); - series->add(5, "Slice 1"); + series->add(1, "Slice 1"); series->add(2, "Slice 2"); series->add(3, "Slice 3"); series->add(4, "Slice 4"); series->add(5, "Slice 5"); - series->add(6, "Slice 6"); - series->add(7, "Slice 7"); - series->add(new CustomSlice(8)); - series->enableClickExplodes(true); - series->enableHoverHighlight(true); - - QChartView* chartView = new QChartView(&window); - chartView->setRenderHint(QPainter::Antialiasing); - chartView->setChartTheme(QChart::ChartThemeIcy); - chartView->setChartTitle("Simple piechart"); chartView->addSeries(series); + //! [1] + + //! [2] + series->enableHoverHighlight(true); + series->enableClickExplodes(true); + //! [2] window.setCentralWidget(chartView); window.resize(600, 600); diff --git a/example/piechart/piechart.pro b/example/piechart/piechart.pro index 85c2b35..a8bed67 100644 --- a/example/piechart/piechart.pro +++ b/example/piechart/piechart.pro @@ -2,7 +2,7 @@ error( "Couldn't find the example.pri file!" ) } TARGET = piechart -SOURCES += main.cpp customslice.cpp -HEADERS += customslice.h +SOURCES += main.cpp +HEADERS += diff --git a/example/presenterchart/chartview.cpp b/example/presenterchart/chartview.cpp index 877ea3f..1953a92 100644 --- a/example/presenterchart/chartview.cpp +++ b/example/presenterchart/chartview.cpp @@ -1,5 +1,5 @@ #include "chartview.h" -#include +#include #include ChartView::ChartView(QWidget* parent):QChartView(parent), @@ -11,15 +11,15 @@ m_index(0) QTime now = QTime::currentTime(); qsrand((uint)now.msec()); - QLineChartSeries* series0 = new QLineChartSeries(); + QLineSeries* series0 = new QLineSeries(); QPen blue(Qt::blue); blue.setWidth(3); series0->setPen(blue); - QLineChartSeries* series1 = new QLineChartSeries(); + QLineSeries* series1 = new QLineSeries(); QPen red(Qt::red); red.setWidth(3); series1->setPen(red); - QLineChartSeries* series2 = new QLineChartSeries(); + QLineSeries* series2 = new QLineSeries(); QPen green(Qt::green); green.setWidth(3); series2->setPen(green); diff --git a/example/presenterchart/chartview.h b/example/presenterchart/chartview.h index 0264fee..050b98b 100644 --- a/example/presenterchart/chartview.h +++ b/example/presenterchart/chartview.h @@ -18,7 +18,7 @@ public slots: private: QTimer m_timer; - QList m_series; + QList m_series; int m_index; }; diff --git a/example/scatter/main.cpp b/example/scatter/main.cpp index 59c0446..bd612f4 100644 --- a/example/scatter/main.cpp +++ b/example/scatter/main.cpp @@ -27,14 +27,9 @@ int main(int argc, char *argv[]) chartView->addSeries(scatter); //! [1] - // Add some more data - //! [2] - scatter->addData(QPointF(2.0, 5.5)); - //! [2] - // And more //! [3] - *scatter << QPointF(2.0, 5.5); + *scatter << QPointF(2.0, 5.5) << QPointF(2.2, 5.4); //! [3] // Add another scatter series (re-use the previous pointer) @@ -46,14 +41,14 @@ int main(int argc, char *argv[]) } //! [4] QBrush brush(QColor(255, 0, 0, 100), Qt::SolidPattern); - scatter->setMarkerBrush(brush); + scatter->setBrush(brush); //! [4] //! [5] QPen pen(QColor(0, 255, 0, 80), 3); - scatter->setMarkerPen(pen); + scatter->setPen(pen); //! [5] //! [6] - scatter->setMarkerShape(QScatterSeries::MarkerShapeRectangle); + scatter->setShape(QScatterSeries::MarkerShapeRectangle); //! [6] chartView->addSeries(scatter); diff --git a/example/stackedbarchart/main.cpp b/example/stackedbarchart/main.cpp index 3dc8d00..32b189c 100644 --- a/example/stackedbarchart/main.cpp +++ b/example/stackedbarchart/main.cpp @@ -1,9 +1,9 @@ #include #include #include -#include +#include #include -#include +#include QTCOMMERCIALCHART_USE_NAMESPACE @@ -13,9 +13,9 @@ int main(int argc, char *argv[]) QMainWindow window; //! [1] - // Create category - QBarCategory *category = new QBarCategory; - *category << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "June" << "Jul" << "Aug" << "Sep" << "Oct" << "Nov" << "Dec"; + // Define categories + QStringList catecories; + catecories << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "June" << "Jul" << "Aug" << "Sep" << "Oct" << "Nov" << "Dec"; //! [1] //! [2] @@ -35,7 +35,7 @@ int main(int argc, char *argv[]) //! [3] // Create series and add sets to it - QStackedBarChartSeries* series = new QStackedBarChartSeries(category); + QStackedBarSeries* series = new QStackedBarSeries(catecories); series->addBarSet(set0); series->addBarSet(set1); @@ -46,8 +46,8 @@ int main(int argc, char *argv[]) //! [4] // Enable features - series->enableToolTip(); - series->enableFloatingValues(); + series->setToolTipEnabled(); + series->setFloatingValuesEnabled(); //! [4] //! [5] diff --git a/example/zoomlinechart/main.cpp b/example/zoomlinechart/main.cpp index a34cb6c..0e307f8 100644 --- a/example/zoomlinechart/main.cpp +++ b/example/zoomlinechart/main.cpp @@ -1,7 +1,7 @@ #include "chartwidget.h" #include #include -#include +#include #include QTCOMMERCIALCHART_USE_NAMESPACE @@ -14,11 +14,11 @@ int main(int argc, char *argv[]) QMainWindow window; - QLineChartSeries* series0 = new QLineChartSeries(); + QLineSeries* series0 = new QLineSeries(); QPen blue(Qt::blue); blue.setWidth(3); series0->setPen(blue); - QLineChartSeries* series1 = new QLineChartSeries(); + QLineSeries* series1 = new QLineSeries(); QPen red(Qt::red); red.setWidth(3); series1->setPen(red); diff --git a/qmlplugin/declarativelineseries.cpp b/qmlplugin/declarativelineseries.cpp index 627c3c4..558aa23 100644 --- a/qmlplugin/declarativelineseries.cpp +++ b/qmlplugin/declarativelineseries.cpp @@ -1,7 +1,7 @@ #include "declarativelineseries.h" #include "declarativechart.h" #include "qchart.h" -#include "qlinechartseries.h" +#include "qlineseries.h" QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -23,7 +23,7 @@ void DeclarativeLineSeries::setParentForSeries() qDebug() << "creating line series for chart: " << chart; Q_ASSERT(chart); - m_series = new QLineChartSeries(); + m_series = new QLineSeries(); Q_ASSERT(m_series); for (int i(0); i < m_data.count(); i++) { ScatterElement *element = m_data.at(i); diff --git a/qmlplugin/declarativelineseries.h b/qmlplugin/declarativelineseries.h index 9819453..92bb1b1 100644 --- a/qmlplugin/declarativelineseries.h +++ b/qmlplugin/declarativelineseries.h @@ -8,7 +8,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE class QChart; -class QLineChartSeries; +class QLineSeries; class DeclarativeLineSeries : public QDeclarativeItem { @@ -30,7 +30,7 @@ private slots: private: QChart *m_chart; - QLineChartSeries *m_series; + QLineSeries *m_series; QList m_data; }; diff --git a/qmlplugin/declarativescatterseries.cpp b/qmlplugin/declarativescatterseries.cpp index 6100df3..5780cca 100644 --- a/qmlplugin/declarativescatterseries.cpp +++ b/qmlplugin/declarativescatterseries.cpp @@ -59,7 +59,7 @@ void DeclarativeScatterSeries::appendData(QDeclarativeListPropertym_data.append(element); if (series->m_series) - series->m_series->addData(QPointF(element->x(), element->y())); + series->m_series->add(element->x(), element->y()); } } diff --git a/src/axisitem.cpp b/src/axisitem.cpp index a3d4b79..cea51b9 100644 --- a/src/axisitem.cpp +++ b/src/axisitem.cpp @@ -95,7 +95,7 @@ void AxisItem::handleAxisUpdate(QChartAxis* axis) setGridOpacity(0); } - if(axis->isLabelsVisible()) + if(axis->labelsVisible()) { setLabelsOpacity(100); } @@ -103,7 +103,7 @@ void AxisItem::handleAxisUpdate(QChartAxis* axis) setLabelsOpacity(0); } - if(axis->isShadesVisible()) { + if(axis->shadesVisible()) { setShadesOpacity(axis->shadesOpacity()); } else { diff --git a/src/barchart/barchart.pri b/src/barchart/barchart.pri index 35668e6..3ae84f5 100644 --- a/src/barchart/barchart.pri +++ b/src/barchart/barchart.pri @@ -8,11 +8,10 @@ SOURCES += \ $$PWD/barpresenter.cpp \ $$PWD/barpresenterbase.cpp \ $$PWD/percentbarpresenter.cpp \ - $$PWD/qbarcategory.cpp \ - $$PWD/qbarchartseries.cpp \ + $$PWD/qbarseries.cpp \ $$PWD/qbarset.cpp \ - $$PWD/qpercentbarchartseries.cpp \ - $$PWD/qstackedbarchartseries.cpp \ + $$PWD/qpercentbarseries.cpp \ + $$PWD/qstackedbarseries.cpp \ $$PWD/separator.cpp \ $$PWD/stackedbarpresenter.cpp \ $$PWD/barvalue.cpp @@ -21,18 +20,17 @@ PRIVATE_HEADERS += \ $$PWD/bar_p.h \ $$PWD/barchartmodel_p.h \ $$PWD/barlabel_p.h \ - $$PWD/barpresenter.h \ - $$PWD/barpresenterbase.h \ - $$PWD/percentbarpresenter.h \ + $$PWD/barpresenter_p.h \ + $$PWD/barpresenterbase_p.h \ + $$PWD/percentbarpresenter_p.h \ $$PWD/separator_p.h \ - $$PWD/stackedbarpresenter.h \ + $$PWD/stackedbarpresenter_p.h \ $$PWD/barvalue_p.h PUBLIC_HEADERS += \ - $$PWD/qbarcategory.h \ - $$PWD/qbarchartseries.h \ + $$PWD/qbarseries.h \ $$PWD/qbarset.h \ - $$PWD/qpercentbarchartseries.h \ - $$PWD/qstackedbarchartseries.h + $$PWD/qpercentbarseries.h \ + $$PWD/qstackedbarseries.h diff --git a/src/barchart/barchartmodel.cpp b/src/barchart/barchartmodel.cpp index eea1e47..2807cdc 100644 --- a/src/barchart/barchartmodel.cpp +++ b/src/barchart/barchartmodel.cpp @@ -2,26 +2,19 @@ #include #include #include "barchartmodel_p.h" -#include "qbarcategory.h" #include "qbarset.h" QTCOMMERCIALCHART_BEGIN_NAMESPACE -BarChartModel::BarChartModel(QBarCategory *category, QObject *parent) : +BarChartModel::BarChartModel(QStringList categories, QObject *parent) : QObject(parent) - ,mCategory(category) + ,mCategory(categories) { } -BarChartModel::~BarChartModel() +QStringList BarChartModel::category() { - delete mCategory; -} - - -QBarCategory& BarChartModel::category() -{ - return *mCategory; + return mCategory; } void BarChartModel::addBarSet(QBarSet *set) @@ -36,32 +29,25 @@ void BarChartModel::removeBarSet(QBarSet *set) } } -QBarSet* BarChartModel::nextSet(bool getFirst) +QBarSet* BarChartModel::setAt(int index) { - if (getFirst) { - mCurrentSet = 0; - } - - if ((mDataModel.count() <= 0) || (mDataModel.count() <= mCurrentSet)) { - return 0; - } - - QBarSet* set = mDataModel.at(mCurrentSet); - mCurrentSet++; - return set; + return mDataModel.at(index); } -QBarSet* BarChartModel::setAt(int index) +QList BarChartModel::barSets() { - return mDataModel.at(index); + return mDataModel; } -QList BarChartModel::legend() +QList BarChartModel::legend() { - QList legend; + QList legend; for (int i=0; iname()); + QSeries::Legend l; + l.mName = mDataModel.at(i)->name(); + l.mPen = mDataModel.at(i)->pen(); + legend.append(l); } return legend; } @@ -192,7 +178,7 @@ qreal BarChartModel::maxCategorySum() QString BarChartModel::label(int category) { - return mCategory->label(category); + return mCategory.at(category); } #include "moc_barchartmodel_p.cpp" diff --git a/src/barchart/barchartmodel_p.h b/src/barchart/barchartmodel_p.h index 4c33392..cbe71da 100644 --- a/src/barchart/barchartmodel_p.h +++ b/src/barchart/barchartmodel_p.h @@ -2,7 +2,9 @@ #define BARCHARTMODEL_H #include +#include #include "qchartglobal.h" +#include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -10,21 +12,20 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE // TODO: Implement as QAbstractItemModel? class QBarSet; -class QBarCategory; class BarChartModel : public QObject //, public QAbstractItemModel { Q_OBJECT public: - explicit BarChartModel(QBarCategory *category, QObject *parent = 0); - ~BarChartModel(); + explicit BarChartModel(QStringList categories, QObject *parent = 0); - QBarCategory& category(); + QStringList category(); void addBarSet(QBarSet *set); void removeBarSet(QBarSet *set); - QBarSet* nextSet(bool getFirst); QBarSet *setAt(int index); - QList legend(); + QList barSets(); + + QList legend(); int countSets(); // Number of sets in model int countCategories(); // Number of categories @@ -48,7 +49,7 @@ public slots: private: QList mDataModel; - QBarCategory* mCategory; // Owned + QStringList mCategory; int mCurrentSet; diff --git a/src/barchart/barpresenter.cpp b/src/barchart/barpresenter.cpp index 9e06f12..2bbcf4e 100644 --- a/src/barchart/barpresenter.cpp +++ b/src/barchart/barpresenter.cpp @@ -1,4 +1,4 @@ -#include "barpresenter.h" +#include "barpresenter_p.h" #include "bar_p.h" #include "barlabel_p.h" #include "barvalue_p.h" @@ -7,7 +7,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE -BarPresenter::BarPresenter(QBarChartSeries *series, QGraphicsItem *parent) : +BarPresenter::BarPresenter(QBarSeries *series, QGraphicsItem *parent) : BarPresenterBase(series, parent) { mBarDefaultWidth = 15; @@ -17,7 +17,7 @@ void BarPresenter::layoutChanged() { // Scale bars to new layout // Layout for bars: - if (mSeries->countSets() <= 0) { + if (mSeries->barsetCount() <= 0) { qDebug() << "No sets in model!"; return; } @@ -29,8 +29,8 @@ void BarPresenter::layoutChanged() // TODO: better way to auto-layout? // Use reals for accurancy (we might get some compiler warnings... :) - int categoryCount = mSeries->countCategories(); - int setCount = mSeries->countSets(); + int categoryCount = mSeries->categoryCount(); + int setCount = mSeries->barsetCount(); qreal tW = mWidth; qreal tH = mHeight; @@ -52,7 +52,7 @@ void BarPresenter::layoutChanged() // TODO: width settable per bar? bar->resize(mBarDefaultWidth, barHeight); - bar->setBrush(mSeries->setAt(set)->brush()); + bar->setBrush(mSeries->barsetAt(set)->brush()); bar->setPos(xPos, yPos-barHeight); itemIndex++; xPos += mBarDefaultWidth; @@ -67,10 +67,10 @@ void BarPresenter::layoutChanged() // Position floating values itemIndex = 0; - for (int category=0; category < mSeries->countCategories(); category++) { + for (int category=0; category < mSeries->categoryCount(); category++) { qreal xPos = xStepPerSet * category + ((tW + mBarDefaultWidth*setCount)/(categoryCount*2)); qreal yPos = mHeight; - for (int set=0; set < mSeries->countSets(); set++) { + for (int set=0; set < mSeries->barsetCount(); set++) { qreal barHeight = mSeries->valueAt(set,category) * scale; BarValue* value = mFloatingValues.at(itemIndex); @@ -92,6 +92,6 @@ void BarPresenter::layoutChanged() mLayoutDirty = true; } -#include "moc_barpresenter.cpp" +#include "moc_barpresenter_p.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/barchart/barpresenter.h b/src/barchart/barpresenter_p.h similarity index 85% rename from src/barchart/barpresenter.h rename to src/barchart/barpresenter_p.h index 623ea6b..383ecbd 100644 --- a/src/barchart/barpresenter.h +++ b/src/barchart/barpresenter_p.h @@ -2,19 +2,19 @@ #define BARPRESENTER_H #include "qchartglobal.h" -#include "barpresenterbase.h" +#include "barpresenterbase_p.h" #include QTCOMMERCIALCHART_BEGIN_NAMESPACE -class QBarChartSeries; +class QBarSeries; // Presenter for parallel bars. Grouping of bars is done on category basis. class BarPresenter : public BarPresenterBase { Q_OBJECT public: - explicit BarPresenter(QBarChartSeries *series, QGraphicsItem *parent = 0); + explicit BarPresenter(QBarSeries *series, QGraphicsItem *parent = 0); private: diff --git a/src/barchart/barpresenterbase.cpp b/src/barchart/barpresenterbase.cpp index dd21a43..48247f9 100644 --- a/src/barchart/barpresenterbase.cpp +++ b/src/barchart/barpresenterbase.cpp @@ -1,16 +1,16 @@ -#include "barpresenterbase.h" +#include "barpresenterbase_p.h" #include "bar_p.h" #include "barvalue_p.h" #include "barlabel_p.h" #include "separator_p.h" #include "qbarset.h" -#include "qbarchartseries.h" +#include "qbarseries.h" #include #include QTCOMMERCIALCHART_BEGIN_NAMESPACE -BarPresenterBase::BarPresenterBase(QBarChartSeries *series, QGraphicsItem *parent) +BarPresenterBase::BarPresenterBase(QBarSeries *series, QGraphicsItem *parent) : ChartItem(parent) ,mBarDefaultWidth(20) // TODO: remove hard coding, when we have layout code ready ,mLayoutSet(false) @@ -68,9 +68,9 @@ void BarPresenterBase::dataChanged() mFloatingValues.clear(); // Create new graphic items for bars - for (int c=0; ccountCategories(); c++) { - for (int s=0; scountSets(); s++) { - QBarSet *set = mSeries->setAt(s); + for (int c=0; ccategoryCount(); c++) { + for (int s=0; sbarsetCount(); s++) { + QBarSet *set = mSeries->barsetAt(s); Bar *bar = new Bar(this); childItems().append(bar); mBars.append(bar); @@ -81,7 +81,7 @@ void BarPresenterBase::dataChanged() } // Create labels - int count = mSeries->countCategories(); + int count = mSeries->categoryCount(); for (int i=0; iset(mSeries->label(i)); @@ -90,7 +90,7 @@ void BarPresenterBase::dataChanged() } // Create separators - count = mSeries->countCategories() - 1; // There is one less separator than columns + count = mSeries->categoryCount() - 1; // There is one less separator than columns for (int i=0; isetColor(QColor(255,0,0,255)); // TODO: color for separations from theme @@ -100,9 +100,9 @@ void BarPresenterBase::dataChanged() } // Create floating values - for (int category=0; categorycountCategories(); category++) { - for (int s=0; scountSets(); s++) { - QBarSet *set = mSeries->setAt(s); + for (int category=0; categorycategoryCount(); category++) { + for (int s=0; sbarsetCount(); s++) { + QBarSet *set = mSeries->barsetAt(s); BarValue *value = new BarValue(*set, this); childItems().append(value); mFloatingValues.append(value); @@ -153,6 +153,6 @@ void BarPresenterBase::enableSeparators(bool enabled) mSeparatorsEnabled = enabled; } -#include "moc_barpresenterbase.cpp" +#include "moc_barpresenterbase_p.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/barchart/barpresenterbase.h b/src/barchart/barpresenterbase_p.h similarity index 94% rename from src/barchart/barpresenterbase.h rename to src/barchart/barpresenterbase_p.h index 720ab44..c342ba1 100644 --- a/src/barchart/barpresenterbase.h +++ b/src/barchart/barpresenterbase_p.h @@ -2,7 +2,7 @@ #define BARPRESENTERBASE_H #include "chartitem_p.h" -#include "qbarchartseries.h" +#include "qbarseries.h" #include #include #include @@ -20,7 +20,7 @@ class BarPresenterBase : public QObject, public ChartItem { Q_OBJECT public: - BarPresenterBase(QBarChartSeries *series, QGraphicsItem *parent = 0); + BarPresenterBase(QBarSeries *series, QGraphicsItem *parent = 0); ~BarPresenterBase(); public: @@ -57,7 +57,7 @@ protected: bool mSeparatorsEnabled; // Owned - QBarChartSeries* mSeries; + QBarSeries* mSeries; // Not owned. QList mBars; diff --git a/src/barchart/percentbarpresenter.cpp b/src/barchart/percentbarpresenter.cpp index f620f80..6fb873b 100644 --- a/src/barchart/percentbarpresenter.cpp +++ b/src/barchart/percentbarpresenter.cpp @@ -1,4 +1,4 @@ -#include "percentbarpresenter.h" +#include "percentbarpresenter_p.h" #include "bar_p.h" #include "barlabel_p.h" #include "barvalue_p.h" @@ -9,7 +9,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE -PercentBarPresenter::PercentBarPresenter(QBarChartSeries *series, QGraphicsItem *parent) : +PercentBarPresenter::PercentBarPresenter(QBarSeries *series, QGraphicsItem *parent) : BarPresenterBase(series, parent) { } @@ -18,7 +18,7 @@ void PercentBarPresenter::layoutChanged() { // Scale bars to new layout // Layout for bars: - if (mSeries->countSets() <= 0) { + if (mSeries->barsetCount() <= 0) { qDebug() << "No sets in model!"; // Nothing to do. return; @@ -31,7 +31,7 @@ void PercentBarPresenter::layoutChanged() // TODO: better way to auto-layout // Use reals for accurancy (we might get some compiler warnings... :) - int count = mSeries->countCategories(); + int count = mSeries->categoryCount(); int itemIndex(0); int labelIndex(0); qreal tW = mWidth; @@ -40,17 +40,17 @@ void PercentBarPresenter::layoutChanged() qreal xPos = ((tW/tC) - mBarDefaultWidth / 2); qreal h = mHeight; - for (int category = 0; category < mSeries->countCategories(); category++) { + for (int category = 0; category < mSeries->categoryCount(); category++) { qreal colSum = mSeries->categorySum(category); qreal scale = (h / colSum); qreal yPos = h; - for (int set=0; set < mSeries->countSets(); set++) { + for (int set=0; set < mSeries->barsetCount(); set++) { qreal barHeight = mSeries->valueAt(set, category) * scale; Bar* bar = mBars.at(itemIndex); // TODO: width settable per bar? bar->resize(mBarDefaultWidth, barHeight); - bar->setBrush(mSeries->setAt(set)->brush()); + bar->setBrush(mSeries->barsetAt(set)->brush()); bar->setPos(xPos, yPos-barHeight); itemIndex++; yPos -= barHeight; @@ -65,7 +65,7 @@ void PercentBarPresenter::layoutChanged() // Position separators xPos = xStep + xStep/2; - for (int s=0; s < mSeries->countCategories() - 1; s++) { + for (int s=0; s < mSeries->categoryCount() - 1; s++) { Separator* sep = mSeparators.at(s); sep->setPos(xPos,0); sep->setSize(QSizeF(1,mHeight)); @@ -75,11 +75,11 @@ void PercentBarPresenter::layoutChanged() // Position floating values itemIndex = 0; xPos = ((tW/tC) - mBarDefaultWidth / 2); - for (int category=0; category < mSeries->countCategories(); category++) { + for (int category=0; category < mSeries->categoryCount(); category++) { qreal yPos = h; qreal colSum = mSeries->categorySum(category); qreal scale = (h / colSum); - for (int set=0; set < mSeries->countSets(); set++) { + for (int set=0; set < mSeries->barsetCount(); set++) { qreal barHeight = mSeries->valueAt(set,category) * scale; BarValue* value = mFloatingValues.at(itemIndex); @@ -107,6 +107,6 @@ void PercentBarPresenter::layoutChanged() mLayoutDirty = true; } -#include "moc_percentbarpresenter.cpp" +#include "moc_percentbarpresenter_p.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/barchart/percentbarpresenter.h b/src/barchart/percentbarpresenter_p.h similarity index 85% rename from src/barchart/percentbarpresenter.h rename to src/barchart/percentbarpresenter_p.h index fa16399..3002365 100644 --- a/src/barchart/percentbarpresenter.h +++ b/src/barchart/percentbarpresenter_p.h @@ -3,8 +3,8 @@ #include "chartitem_p.h" #include "bar_p.h" -#include "qpercentbarchartseries.h" -#include "barpresenterbase.h" +#include "qpercentbarseries.h" +#include "barpresenterbase_p.h" #include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -13,7 +13,7 @@ class PercentBarPresenter : public BarPresenterBase { Q_OBJECT public: - PercentBarPresenter(QBarChartSeries *series, QGraphicsItem *parent = 0); + PercentBarPresenter(QBarSeries *series, QGraphicsItem *parent = 0); private: diff --git a/src/barchart/qbarcategory.cpp b/src/barchart/qbarcategory.cpp deleted file mode 100644 index d2195fa..0000000 --- a/src/barchart/qbarcategory.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "qbarcategory.h" - -QTCOMMERCIALCHART_BEGIN_NAMESPACE - -/*! - \class QBarCategory - \brief part of QtCommercial chart API. - - QBarCategory is a container for labels of various bar charts. Before the - bar chart can be constructed, the categories must be defined. This is done by - creating a QBarCategory class and appending the labels of categories to it. - The QBarCategory is then given to bar chart series class. - - \mainclass - - Example on how to create a category: - \snippet ../example/barchart/main.cpp 1 - - \sa QBarChartSeries, QStackedBarChartSeries, QPercentBarChartSeries -*/ - -/*! - Constructs the category container -*/ -QBarCategory::QBarCategory() -{ -} - -/*! - Appends the \a label in the category. -*/ -QBarCategory& QBarCategory::operator << (const QString &label) -{ - mList.append(label); - return *this; -} - -/*! - Retrurns number of labels in category -*/ -int QBarCategory::count() -{ - return mList.count(); -} - -/*! - Retruns the label of category defined by index \a category -*/ -QString QBarCategory::label(int category) -{ - return mList.at(category); -} - -// TODO?: -//#include "moc_qbarcategory.cpp" -QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/barchart/qbarcategory.h b/src/barchart/qbarcategory.h deleted file mode 100644 index f534265..0000000 --- a/src/barchart/qbarcategory.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef QBARCATEGORY_H -#define QBARCATEGORY_H - -#include "qchartglobal.h" - -QTCOMMERCIALCHART_BEGIN_NAMESPACE - -class QTCOMMERCIALCHART_EXPORT QBarCategory // TODO?: : public QObject -{ -// Q_OBJECT; -public: - QBarCategory(); - - QBarCategory& operator << (const QString &label); - - // Number of items in category - int count(); - QString label(int category); - -public: - - QList mList; - -}; - -QTCOMMERCIALCHART_END_NAMESPACE - -#endif // QBARCATEGORY_H diff --git a/src/barchart/qbarchartseries.cpp b/src/barchart/qbarseries.cpp similarity index 63% rename from src/barchart/qbarchartseries.cpp rename to src/barchart/qbarseries.cpp index 9b4d9aa..cebdffc 100644 --- a/src/barchart/qbarchartseries.cpp +++ b/src/barchart/qbarseries.cpp @@ -1,6 +1,5 @@ #include -#include "qbarchartseries.h" -#include "qbarcategory.h" +#include "qbarseries.h" #include "qbarset.h" #include "barchartmodel_p.h" @@ -8,74 +7,58 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE /*! - \class QBarChartSeries + \class QBarSeries \brief part of QtCommercial chart API. - QBarChartSeries represents a series of data shown as bars. One QBarChartSeries can contain multible - QBarSet data sets. QBarChartSeries groups the data from sets to categories, which are defined - by QBarCategory class. + QBarSeries represents a series of data shown as bars. One QBarSeries can contain multible + QBarSet data sets. QBarSeries groups the data from sets to categories, which are defined + by QStringList. \mainclass - Example on how to create category: - \snippet ../example/barchart/main.cpp 1 - - Example on how to create sets of data: - \snippet ../example/barchart/main.cpp 2 - - Example on how to add sets to bar chart: - \snippet ../example/barchart/main.cpp 3 - - Example on how to enable tooltip and floating values: - \snippet ../example/barchart/main.cpp 4 - - Example on how to create view and apply theme: - \snippet ../example/barchart/main.cpp 5 - - \sa QBarCategory, QBarSet, QStackedBarChartSeries, QPercentBarChartSeries + \sa QBarSet, QStackedBarSeries, QPercentBarSeries */ /*! - \fn virtual QChartSeriesType QBarChartSeries::type() const + \fn virtual QSeriesType QBarSeries::type() const \brief Returns type of series. - \sa QChartSeries, QChartSeriesType + \sa QSeries, QSeriesType */ /*! - \fn void QBarChartSeries::changed(int index) + \fn void QBarSeries::changed(int index) \brief \internal \a index */ /*! - \fn void QBarChartSeries::floatingValuesEnabled(bool enabled) + \fn void QBarSeries::floatingValuesEnabled(bool enabled) \brief \internal \a enabled */ /*! - \fn void QBarChartSeries::toolTipEnabled(bool enabled) + \fn void QBarSeries::toolTipEnabled(bool enabled) \brief \internal \a enabled */ /*! - \fn void QBarChartSeries::separatorsEnabled(bool enabled) + \fn void QBarSeries::separatorsEnabled(bool enabled) \brief \internal \a enabled */ /*! - \fn void QBarChartSeries::showToolTip(QPoint pos, QString tip) + \fn void QBarSeries::showToolTip(QPoint pos, QString tip) \brief \internal \a pos \a tip */ /*! - Constructs empty QBarChartSeries. Parameter \a category defines the categories for chart. - Takes ownership of \a category. - QBarChartSeries is QObject which is a child of a \a parent. + Constructs empty QBarSeries. Parameter \a category defines the categories for chart. + QBarSeries is QObject which is a child of a \a parent. */ -QBarChartSeries::QBarChartSeries(QBarCategory *category, QObject *parent) - : QChartSeries(parent) - ,mModel(new BarChartModel(category, this)) +QBarSeries::QBarSeries(QStringList categories, QObject *parent) + : QSeries(parent) + ,mModel(new BarChartModel(categories, this)) { } /*! Adds a set of bars to series. Takes ownership of \a set */ -void QBarChartSeries::addBarSet(QBarSet *set) +void QBarSeries::addBarSet(QBarSet *set) { mModel->addBarSet(set); } @@ -83,7 +66,7 @@ void QBarChartSeries::addBarSet(QBarSet *set) /*! Removes a set of bars from series. Releases ownership of \a set. Doesnt delete \a set. */ -void QBarChartSeries::removeBarSet(QBarSet *set) +void QBarSeries::removeBarSet(QBarSet *set) { mModel->removeBarSet(set); } @@ -91,7 +74,7 @@ void QBarChartSeries::removeBarSet(QBarSet *set) /*! Returns number of sets in series. */ -int QBarChartSeries::countSets() +int QBarSeries::barsetCount() { return mModel->countSets(); } @@ -99,36 +82,31 @@ int QBarChartSeries::countSets() /*! Returns number of categories in series */ -int QBarChartSeries::countCategories() +int QBarSeries::categoryCount() { return mModel->countCategories(); } /*! - Simple iterator for set. Returns pointer to next set in series. - Returns first set, if parameter \a getFirst is true. - If series is empty, returns 0. - Returns 0 after last set. -*/ -QBarSet* QBarChartSeries::nextSet(bool getFirst) + Returns a list of sets in series. Keeps ownership of sets. + */ +QList QBarSeries::barSets() { - return mModel->nextSet(getFirst); + return mModel->barSets(); } /*! - Returns set indexed by \a index. Doesn't check for index bounds. - Assumes that \a index is between 0 and number of sets. Use countSets() to get valid index bound. - \sa countSets() + \internal \a index */ -QBarSet* QBarChartSeries::setAt(int index) +QBarSet* QBarSeries::barsetAt(int index) { return mModel->setAt(index); } /*! - Returns legend of series. Legend is a list of set names in series. + Returns legend of series. */ -QList QBarChartSeries::legend() +QList QBarSeries::legend() { return mModel->legend(); } @@ -136,7 +114,7 @@ QList QBarChartSeries::legend() /*! \internal \a category */ -QString QBarChartSeries::label(int category) +QString QBarSeries::label(int category) { return mModel->label(category); } @@ -146,7 +124,7 @@ QString QBarChartSeries::label(int category) Floating values are bar values, that are displayed on top of each bar. Calling without parameter \a enabled, enables the floating values */ -void QBarChartSeries::enableFloatingValues(bool enabled) +void QBarSeries::setFloatingValuesEnabled(bool enabled) { if (enabled) { for (int i=0; icountSets(); i++) { @@ -166,7 +144,7 @@ void QBarChartSeries::enableFloatingValues(bool enabled) Tooltip shows the name of set, when mouse is hovering on top of bar. Calling without parameter \a enabled, enables the tooltip */ -void QBarChartSeries::enableToolTip(bool enabled) +void QBarSeries::setToolTipEnabled(bool enabled) { if (enabled) { for (int i=0; icountSets(); i++) { @@ -186,7 +164,7 @@ void QBarChartSeries::enableToolTip(bool enabled) Separators are visual elements that are drawn between categories. Calling without parameter \a enabled, enables the separators */ -void QBarChartSeries::enableSeparators(bool enabled) +void QBarSeries::setSeparatorsEnabled(bool enabled) { emit separatorsEnabled(enabled); } @@ -194,7 +172,7 @@ void QBarChartSeries::enableSeparators(bool enabled) /*! \internal */ -qreal QBarChartSeries::min() +qreal QBarSeries::min() { return mModel->min(); } @@ -202,7 +180,7 @@ qreal QBarChartSeries::min() /*! \internal */ -qreal QBarChartSeries::max() +qreal QBarSeries::max() { return mModel->max(); } @@ -210,7 +188,7 @@ qreal QBarChartSeries::max() /*! \internal \a set \a category */ -qreal QBarChartSeries::valueAt(int set, int category) +qreal QBarSeries::valueAt(int set, int category) { return mModel->valueAt(set,category); } @@ -218,7 +196,7 @@ qreal QBarChartSeries::valueAt(int set, int category) /*! \internal \a set \a category */ -qreal QBarChartSeries::percentageAt(int set, int category) +qreal QBarSeries::percentageAt(int set, int category) { return mModel->percentageAt(set,category); } @@ -226,7 +204,7 @@ qreal QBarChartSeries::percentageAt(int set, int category) /*! \internal \a category */ -qreal QBarChartSeries::categorySum(int category) +qreal QBarSeries::categorySum(int category) { return mModel->categorySum(category); } @@ -234,7 +212,7 @@ qreal QBarChartSeries::categorySum(int category) /*! \internal */ -qreal QBarChartSeries::maxCategorySum() +qreal QBarSeries::maxCategorySum() { return mModel->maxCategorySum(); } @@ -242,11 +220,11 @@ qreal QBarChartSeries::maxCategorySum() /*! \internal */ -BarChartModel& QBarChartSeries::model() +BarChartModel& QBarSeries::model() { return *mModel; } -#include "moc_qbarchartseries.cpp" +#include "moc_qbarseries.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/barchart/qbarchartseries.h b/src/barchart/qbarseries.h similarity index 66% rename from src/barchart/qbarchartseries.h rename to src/barchart/qbarseries.h index e3db2be..b303b85 100644 --- a/src/barchart/qbarchartseries.h +++ b/src/barchart/qbarseries.h @@ -1,36 +1,35 @@ -#ifndef BARCHARTSERIES_H -#define BARCHARTSERIES_H +#ifndef BARSERIES_H +#define BARSERIES_H -#include "qchartseries.h" +#include "qseries.h" +#include QTCOMMERCIALCHART_BEGIN_NAMESPACE -class QBarCategory; class QBarSet; class BarChartModel; // Container for series -class QTCOMMERCIALCHART_EXPORT QBarChartSeries : public QChartSeries +class QTCOMMERCIALCHART_EXPORT QBarSeries : public QSeries { Q_OBJECT public: - QBarChartSeries(QBarCategory *category, QObject* parent=0); + QBarSeries(QStringList categories, QObject* parent=0); - virtual QChartSeriesType type() const { return QChartSeries::SeriesTypeBar; } + virtual QSeriesType type() const { return QSeries::SeriesTypeBar; } void addBarSet(QBarSet *set); // Takes ownership of set void removeBarSet(QBarSet *set); // Releases ownership, doesn't delete set - int countSets(); - int countCategories(); - QBarSet* nextSet(bool getFirst=false); // Returns first set, if called with true - QBarSet *setAt(int index); - - QList legend(); // Returns legend of series (ie. names of all sets in series) + int barsetCount(); + int categoryCount(); + QList barSets(); + QList legend(); public: // TODO: Functions below this are not part of api and will be moved // to private implementation, when we start using it // TODO: TO PIMPL ---> + QBarSet *barsetAt(int index); QString label(int category); qreal min(); qreal max(); @@ -53,9 +52,9 @@ signals: // <--- TO PIMPL public Q_SLOTS: - void enableFloatingValues(bool enabled=true); // enables floating values on top of bars - void enableToolTip(bool enabled=true); // enables tooltips - void enableSeparators(bool enabled=true); // enables separators between categories + void setFloatingValuesEnabled(bool enabled=true); // enables floating values on top of bars + void setToolTipEnabled(bool enabled=true); // enables tooltips + void setSeparatorsEnabled(bool enabled=true); // enables separators between categories protected: BarChartModel* mModel; @@ -63,4 +62,4 @@ protected: QTCOMMERCIALCHART_END_NAMESPACE -#endif // BARCHARTSERIES_H +#endif // BARSERIES_H diff --git a/src/barchart/qbarset.cpp b/src/barchart/qbarset.cpp index 962ea5f..caa04bf 100644 --- a/src/barchart/qbarset.cpp +++ b/src/barchart/qbarset.cpp @@ -15,10 +15,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE \mainclass - Example on how to create sets of data: - \snippet ../example/barchart/main.cpp 2 - - \sa QBarCategory, QBarChartSeries, QStackedBarChartSeries, QPercentBarChartSeries + \sa QBarSeries, QStackedBarSeries, QPercentBarSeries */ /*! @@ -104,7 +101,7 @@ void QBarSet::setValue(int index, qreal value) /*! Sets pen for set. Bars of this set are drawn using \a pen */ -void QBarSet::setPen(const QPen& pen) +void QBarSet::setPen(QPen pen) { mPen = pen; } @@ -112,7 +109,7 @@ void QBarSet::setPen(const QPen& pen) /*! Returns pen of the set. */ -const QPen& QBarSet::pen() const +QPen QBarSet::pen() { return mPen; } @@ -120,7 +117,7 @@ const QPen& QBarSet::pen() const /*! Sets brush for the set. Bars of this set are drawn using \a brush */ -void QBarSet::setBrush(const QBrush& brush) +void QBarSet::setBrush(QBrush brush) { mBrush = brush; } @@ -128,7 +125,7 @@ void QBarSet::setBrush(const QBrush& brush) /*! Returns brush of the set. */ -const QBrush& QBarSet::brush() const +QBrush QBarSet::brush() { return mBrush; } diff --git a/src/barchart/qbarset.h b/src/barchart/qbarset.h index 3c35e5c..6d89792 100644 --- a/src/barchart/qbarset.h +++ b/src/barchart/qbarset.h @@ -21,11 +21,11 @@ public: qreal valueAt(int index); // for modifying individual values void setValue(int index, qreal value); // setter for individual value - void setPen(const QPen& pen); - const QPen& pen() const; + void setPen(QPen pen); + QPen pen(); - void setBrush(const QBrush& brush); - const QBrush& brush() const; + void setBrush(QBrush brush); + QBrush brush(); Q_SIGNALS: void clicked(); // Clicked and hover signals exposed to user diff --git a/src/barchart/qpercentbarchartseries.cpp b/src/barchart/qpercentbarchartseries.cpp deleted file mode 100644 index 76c320e..0000000 --- a/src/barchart/qpercentbarchartseries.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "qpercentbarchartseries.h" - -QTCOMMERCIALCHART_BEGIN_NAMESPACE - -/*! - \class QPercentBarChartSeries - \brief part of QtCommercial chart API. - - QPercentBarChartSeries represents a series of data shown as bars. Each bar of QBarSet is shown as percentage - of all bars in category. One QPercentBarChartSeries can contain multible QBarSet data sets. - QBarChartSeries groups the data from sets to categories, which are defined by QBarCategory class. - - \mainclass - - Example on how to create category: - \snippet ../example/barchart/main.cpp 1 - - Example on how to create sets of data: - \snippet ../example/barchart/main.cpp 2 - - Example on how to add sets to bar chart: - \snippet ../example/barchart/main.cpp 3 - - Example on how to enable tooltip and floating values: - \snippet ../example/barchart/main.cpp 4 - - Example on how to create view and apply theme: - \snippet ../example/barchart/main.cpp 5 - - \sa QBarCategory, QBarSet, QStackedBarChartSeries, QBarChartSeries -*/ - -/*! - \fn virtual QChartSeriesType QPercentBarChartSeries::type() const - \brief Returns type of series. - \sa QChartSeries, QChartSeriesType -*/ - -/*! - Constructs empty QPercentBarChartSeries. Parameter \a category defines the categories for chart. - QPercentBarChartSeries is QObject which is a child of a \a parent. -*/ -QPercentBarChartSeries::QPercentBarChartSeries(QBarCategory *category, QObject *parent) - : QBarChartSeries(category, parent) -{ -} - -#include "moc_qpercentbarchartseries.cpp" - -QTCOMMERCIALCHART_END_NAMESPACE - diff --git a/src/barchart/qpercentbarchartseries.h b/src/barchart/qpercentbarchartseries.h deleted file mode 100644 index 44f3cf1..0000000 --- a/src/barchart/qpercentbarchartseries.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef PERCENTBARCHARTSERIES_H -#define PERCENTBARCHARTSERIES_H - -#include "qbarchartseries.h" - -QTCOMMERCIALCHART_BEGIN_NAMESPACE - -class QTCOMMERCIALCHART_EXPORT QPercentBarChartSeries : public QBarChartSeries -{ - Q_OBJECT -public: - QPercentBarChartSeries(QBarCategory *category, QObject* parent=0); - - virtual QChartSeriesType type() const { return QChartSeries::SeriesTypePercentBar; } -}; - -QTCOMMERCIALCHART_END_NAMESPACE - - -#endif // PERCENTBARCHARTSERIES_H diff --git a/src/barchart/qpercentbarseries.cpp b/src/barchart/qpercentbarseries.cpp new file mode 100644 index 0000000..d9bb00d --- /dev/null +++ b/src/barchart/qpercentbarseries.cpp @@ -0,0 +1,36 @@ +#include "qpercentbarseries.h" + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +/*! + \class QPercentBarSeries + \brief part of QtCommercial chart API. + + QPercentBarSeries represents a series of data shown as bars. Each bar of QBarSet is shown as percentage + of all bars in category. One QPercentBarSeries can contain multible QBarSet data sets. + QBarSeries groups the data from sets to categories, which are defined by QStringList. + + \mainclass + + \sa QBarSet, QStackedBarSeries, QBarSeries +*/ + +/*! + \fn virtual QSeriesType QPercentBarSeries::type() const + \brief Returns type of series. + \sa QSeries, QSeriesType +*/ + +/*! + Constructs empty QPercentBarSeries. Parameter \a category defines the categories for chart. + QPercentBarSeries is QObject which is a child of a \a parent. +*/ +QPercentBarSeries::QPercentBarSeries(QStringList categories, QObject *parent) + : QBarSeries(categories, parent) +{ +} + +#include "moc_qpercentbarseries.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE + diff --git a/src/barchart/qpercentbarseries.h b/src/barchart/qpercentbarseries.h new file mode 100644 index 0000000..cbcafe1 --- /dev/null +++ b/src/barchart/qpercentbarseries.h @@ -0,0 +1,21 @@ +#ifndef PERCENTBARSERIES_H +#define PERCENTBARSERIES_H + +#include +#include "qbarseries.h" + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class QTCOMMERCIALCHART_EXPORT QPercentBarSeries : public QBarSeries +{ + Q_OBJECT +public: + QPercentBarSeries(QStringList categories, QObject* parent=0); + + virtual QSeriesType type() const { return QSeries::SeriesTypePercentBar; } +}; + +QTCOMMERCIALCHART_END_NAMESPACE + + +#endif // PERCENTBARSERIES_H diff --git a/src/barchart/qstackedbarchartseries.cpp b/src/barchart/qstackedbarchartseries.cpp deleted file mode 100644 index 280ee97..0000000 --- a/src/barchart/qstackedbarchartseries.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "qstackedbarchartseries.h" - -QTCOMMERCIALCHART_BEGIN_NAMESPACE - -/*! - \class QStackedBarChartSeries - \brief part of QtCommercial chart API. - - QStackedBarChartSeries represents a series of data shown as bars. All bars in same category are - stacked on top of each other. One QStackedBarChartSeries can contain multible QBarSet data sets. - QStackedBarChartSeries groups the data from sets to categories, which are defined by QBarCategory class. - - \mainclass - - Example on how to create category: - \snippet ../example/barchart/main.cpp 1 - - Example on how to create sets of data: - \snippet ../example/barchart/main.cpp 2 - - Example on how to add sets to bar chart: - \snippet ../example/barchart/main.cpp 3 - - Example on how to enable tooltip and floating values: - \snippet ../example/barchart/main.cpp 4 - - Example on how to create view and apply theme: - \snippet ../example/barchart/main.cpp 5 - - \sa QBarCategory, QBarSet, QPercentBarChartSeries, QBarChartSeries -*/ - -/*! - \fn virtual QChartSeriesType QStackedBarChartSeries::type() const - \brief Returns type of series. - \sa QChartSeries, QChartSeriesType -*/ - -/*! - Constructs empty QStackedBarChartSeries. Parameter \a category defines the categories for chart. - QStackedBarChartSeries is QObject which is a child of a \a parent. -*/ -QStackedBarChartSeries::QStackedBarChartSeries(QBarCategory *category, QObject *parent) - : QBarChartSeries(category, parent) -{ -} - -#include "moc_qstackedbarchartseries.cpp" - -QTCOMMERCIALCHART_END_NAMESPACE - diff --git a/src/barchart/qstackedbarchartseries.h b/src/barchart/qstackedbarchartseries.h deleted file mode 100644 index d2f3726..0000000 --- a/src/barchart/qstackedbarchartseries.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef STACKEDBARCHARTSERIES_H -#define STACKEDBARCHARTSERIES_H - -#include "qbarchartseries.h" - -QTCOMMERCIALCHART_BEGIN_NAMESPACE - -class QBarCategory; - -class QTCOMMERCIALCHART_EXPORT QStackedBarChartSeries : public QBarChartSeries -{ - Q_OBJECT -public: - QStackedBarChartSeries(QBarCategory *category, QObject* parent=0); - - virtual QChartSeriesType type() const { return QChartSeries::SeriesTypeStackedBar; } -}; - -QTCOMMERCIALCHART_END_NAMESPACE - -#endif // STACKEDBARCHARTSERIES_H diff --git a/src/barchart/qstackedbarseries.cpp b/src/barchart/qstackedbarseries.cpp new file mode 100644 index 0000000..7fda0de --- /dev/null +++ b/src/barchart/qstackedbarseries.cpp @@ -0,0 +1,36 @@ +#include "qstackedbarseries.h" + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +/*! + \class QStackedBarSeries + \brief part of QtCommercial chart API. + + QStackedBarSeries represents a series of data shown as bars. All bars in same category are + stacked on top of each other. One QStackedBarSeries can contain multible QBarSet data sets. + QStackedBarSeries groups the data from sets to categories, which are defined by QStringList. + + \mainclass + + \sa QBarSet, QPercentBarSeries, QBarSeries +*/ + +/*! + \fn virtual QSeriesType QStackedBarSeries::type() const + \brief Returns type of series. + \sa QSeries, QSeriesType +*/ + +/*! + Constructs empty QStackedBarSeries. Parameter \a category defines the categories for chart. + QStackedBarSeries is QObject which is a child of a \a parent. +*/ +QStackedBarSeries::QStackedBarSeries(QStringList categories, QObject *parent) + : QBarSeries(categories, parent) +{ +} + +#include "moc_qstackedbarseries.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE + diff --git a/src/barchart/qstackedbarseries.h b/src/barchart/qstackedbarseries.h new file mode 100644 index 0000000..e1b796e --- /dev/null +++ b/src/barchart/qstackedbarseries.h @@ -0,0 +1,20 @@ +#ifndef STACKEDBARSERIES_H +#define STACKEDBARSERIES_H + +#include +#include "qbarseries.h" + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class QTCOMMERCIALCHART_EXPORT QStackedBarSeries : public QBarSeries +{ + Q_OBJECT +public: + QStackedBarSeries(QStringList categories, QObject* parent=0); + + virtual QSeriesType type() const { return QSeries::SeriesTypeStackedBar; } +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // STACKEDBARSERIES_H diff --git a/src/barchart/stackedbarpresenter.cpp b/src/barchart/stackedbarpresenter.cpp index 644548c..deefd21 100644 --- a/src/barchart/stackedbarpresenter.cpp +++ b/src/barchart/stackedbarpresenter.cpp @@ -1,4 +1,4 @@ -#include "stackedbarpresenter.h" +#include "stackedbarpresenter_p.h" #include "bar_p.h" #include "barlabel_p.h" #include "barvalue_p.h" @@ -8,7 +8,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE -StackedBarPresenter::StackedBarPresenter(QBarChartSeries *series, QGraphicsItem *parent) : +StackedBarPresenter::StackedBarPresenter(QBarSeries *series, QGraphicsItem *parent) : BarPresenterBase(series,parent) { } @@ -17,13 +17,13 @@ void StackedBarPresenter::layoutChanged() { // Scale bars to new layout // Layout for bars: - if (mSeries->countSets() <= 0) { + if (mSeries->barsetCount() <= 0) { qDebug() << "No sets in model!"; // Nothing to do. return; } - if (mSeries->countCategories() == 0) { + if (mSeries->categoryCount() == 0) { qDebug() << "No categories in model!"; // Nothing to do return; @@ -44,18 +44,18 @@ void StackedBarPresenter::layoutChanged() int itemIndex(0); int labelIndex(0); qreal tW = mWidth; - qreal tC = mSeries->countCategories() + 1; + qreal tC = mSeries->categoryCount() + 1; qreal xStep = (tW/tC); qreal xPos = ((tW/tC) - mBarDefaultWidth / 2); - for (int category = 0; category < mSeries->countCategories(); category++) { + for (int category = 0; category < mSeries->categoryCount(); category++) { qreal yPos = h; - for (int set=0; set < mSeries->countSets(); set++) { + for (int set=0; set < mSeries->barsetCount(); set++) { qreal barHeight = mSeries->valueAt(set, category) * scale; Bar* bar = mBars.at(itemIndex); bar->resize(mBarDefaultWidth, barHeight); - bar->setBrush(mSeries->setAt(set)->brush()); + bar->setBrush(mSeries->barsetAt(set)->brush()); bar->setPos(xPos, yPos-barHeight); itemIndex++; yPos -= barHeight; @@ -70,7 +70,7 @@ void StackedBarPresenter::layoutChanged() // Position separators xPos = xStep + xStep/2; - for (int s=0; s < mSeries->countCategories() - 1; s++) { + for (int s=0; s < mSeries->categoryCount() - 1; s++) { Separator* sep = mSeparators.at(s); sep->setPos(xPos,0); sep->setSize(QSizeF(1,mHeight)); @@ -80,9 +80,9 @@ void StackedBarPresenter::layoutChanged() // Position floating values itemIndex = 0; xPos = ((tW/tC) - mBarDefaultWidth / 2); - for (int category=0; category < mSeries->countCategories(); category++) { + for (int category=0; category < mSeries->categoryCount(); category++) { qreal yPos = h; - for (int set=0; set < mSeries->countSets(); set++) { + for (int set=0; set < mSeries->barsetCount(); set++) { qreal barHeight = mSeries->valueAt(set,category) * scale; BarValue* value = mFloatingValues.at(itemIndex); @@ -106,6 +106,6 @@ void StackedBarPresenter::layoutChanged() mLayoutDirty = true; } -#include "moc_stackedbarpresenter.cpp" +#include "moc_stackedbarpresenter_p.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/barchart/stackedbarpresenter.h b/src/barchart/stackedbarpresenter_p.h similarity index 84% rename from src/barchart/stackedbarpresenter.h rename to src/barchart/stackedbarpresenter_p.h index a3afa29..744a150 100644 --- a/src/barchart/stackedbarpresenter.h +++ b/src/barchart/stackedbarpresenter_p.h @@ -1,8 +1,8 @@ #ifndef STACKEDBARPRESENTER_H #define STACKEDBARPRESENTER_H -#include "barpresenterbase.h" -#include "qstackedbarchartseries.h" +#include "barpresenterbase_p.h" +#include "qstackedbarseries.h" #include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -11,7 +11,7 @@ class StackedBarPresenter : public BarPresenterBase { Q_OBJECT public: - StackedBarPresenter(QBarChartSeries *series, QGraphicsItem *parent = 0); + StackedBarPresenter(QBarSeries *series, QGraphicsItem *parent = 0); private: // From BarPresenterBase diff --git a/src/chartdataset.cpp b/src/chartdataset.cpp index 1fbdd18..85cab17 100644 --- a/src/chartdataset.cpp +++ b/src/chartdataset.cpp @@ -1,10 +1,10 @@ #include "chartdataset_p.h" #include "qchartaxis.h" //series -#include "qlinechartseries.h" -#include "qbarchartseries.h" -#include "qstackedbarchartseries.h" -#include "qpercentbarchartseries.h" +#include "qlineseries.h" +#include "qbarseries.h" +#include "qstackedbarseries.h" +#include "qpercentbarseries.h" #include "qpieseries.h" #include "qscatterseries.h" @@ -33,7 +33,7 @@ const Domain ChartDataSet::domain(QChartAxis *axisY) const return m_domainMap.values(axisY).at(i); } -void ChartDataSet::addSeries(QChartSeries* series, QChartAxis *axisY) +void ChartDataSet::addSeries(QSeries* series, QChartAxis *axisY) { // TODO: we should check the series not already added @@ -43,7 +43,7 @@ void ChartDataSet::addSeries(QChartSeries* series, QChartAxis *axisY) if(axisY==0) axisY = m_axisY; axisY->setParent(this); // take ownership - QList seriesList = m_seriesMap.values(axisY); + QList seriesList = m_seriesMap.values(axisY); QList domainList = m_domainMap.values(axisY); @@ -55,9 +55,9 @@ void ChartDataSet::addSeries(QChartSeries* series, QChartAxis *axisY) switch(series->type()) { - case QChartSeries::SeriesTypeLine: { + case QSeries::SeriesTypeLine: { - QLineChartSeries* xyseries = static_cast(series); + QLineSeries* xyseries = static_cast(series); for (int i = 0; i < xyseries->count(); i++) { @@ -70,10 +70,10 @@ void ChartDataSet::addSeries(QChartSeries* series, QChartAxis *axisY) } break; } - case QChartSeries::SeriesTypeBar: { + case QSeries::SeriesTypeBar: { qDebug() << "QChartSeries::SeriesTypeBar"; - QBarChartSeries* barSeries = static_cast(series); - qreal x = barSeries->countCategories(); + QBarSeries* barSeries = static_cast(series); + qreal x = barSeries->categoryCount(); qreal y = barSeries->max(); domain.m_minX = qMin(domain.m_minX,x); domain.m_minY = qMin(domain.m_minY,y); @@ -81,11 +81,11 @@ void ChartDataSet::addSeries(QChartSeries* series, QChartAxis *axisY) domain.m_maxY = qMax(domain.m_maxY,y); break; } - case QChartSeries::SeriesTypeStackedBar: { + case QSeries::SeriesTypeStackedBar: { qDebug() << "QChartSeries::SeriesTypeStackedBar"; - QStackedBarChartSeries* stackedBarSeries = static_cast(series); - qreal x = stackedBarSeries->countCategories(); + QStackedBarSeries* stackedBarSeries = static_cast(series); + qreal x = stackedBarSeries->categoryCount(); qreal y = stackedBarSeries->maxCategorySum(); domain.m_minX = qMin(domain.m_minX,x); domain.m_minY = qMin(domain.m_minY,y); @@ -93,11 +93,11 @@ void ChartDataSet::addSeries(QChartSeries* series, QChartAxis *axisY) domain.m_maxY = qMax(domain.m_maxY,y); break; } - case QChartSeries::SeriesTypePercentBar: { + case QSeries::SeriesTypePercentBar: { qDebug() << "QChartSeries::SeriesTypePercentBar"; - QPercentBarChartSeries* percentBarSeries = static_cast(series); - qreal x = percentBarSeries->countCategories(); + QPercentBarSeries* percentBarSeries = static_cast(series); + qreal x = percentBarSeries->categoryCount(); domain.m_minX = qMin(domain.m_minX,x); domain.m_minY = 0; domain.m_maxX = qMax(domain.m_maxX,x); @@ -105,13 +105,13 @@ void ChartDataSet::addSeries(QChartSeries* series, QChartAxis *axisY) break; } - case QChartSeries::SeriesTypePie: { + case QSeries::SeriesTypePie: { QPieSeries *pieSeries = static_cast(series); // TODO: domain stuff break; } - case QChartSeries::SeriesTypeScatter: { + case QSeries::SeriesTypeScatter: { QScatterSeries *scatterSeries = qobject_cast(series); Q_ASSERT(scatterSeries); foreach (QPointF point, scatterSeries->data()) { @@ -160,7 +160,7 @@ void ChartDataSet::addSeries(QChartSeries* series, QChartAxis *axisY) } -void ChartDataSet::removeSeries(QChartSeries* series) +void ChartDataSet::removeSeries(QSeries* series) { QList keys = m_seriesMap.uniqueKeys(); foreach(QChartAxis* axis , keys) { @@ -184,7 +184,7 @@ void ChartDataSet::removeAllSeries() { QList keys = m_seriesMap.uniqueKeys(); foreach(QChartAxis* axis , keys) { - QList seriesList = m_seriesMap.values(axis); + QList seriesList = m_seriesMap.values(axis); for(int i =0 ; i < seriesList.size();i++ ) { emit seriesRemoved(seriesList.at(i)); @@ -228,6 +228,8 @@ void ChartDataSet::setDomain(int index) { QList domainList = m_domainMap.uniqueKeys(); + if(domainList.count()==0) return; + Domain domain; foreach (QChartAxis* axis , domainList) { @@ -235,8 +237,8 @@ void ChartDataSet::setDomain(int index) Q_ASSERT(i>=0); domain = m_domainMap.values(axis).at(i); QStringList labels = createLabels(axis,domain.m_minY,domain.m_maxY); - QList seriesList = m_seriesMap.values(axis); - foreach(QChartSeries* series, seriesList) { + QList seriesList = m_seriesMap.values(axis); + foreach(QSeries* series, seriesList) { emit seriesDomainChanged(series,domain); } emit axisLabelsChanged(axis,labels); @@ -281,8 +283,8 @@ void ChartDataSet::addDomain(const QRectF& rect, const QRectF& viewport) foreach (QChartAxis* axis , domainList){ domain = m_domainMap.value(axis).subDomain(rect,viewport.width(),viewport.height()); QStringList labels = createLabels(axis,domain.m_minY,domain.m_maxY); - QList seriesList = m_seriesMap.values(axis); - foreach(QChartSeries* series, seriesList){ + QList seriesList = m_seriesMap.values(axis); + foreach(QSeries* series, seriesList){ emit seriesDomainChanged(series,domain); } emit axisLabelsChanged(axis,labels); @@ -295,7 +297,7 @@ void ChartDataSet::addDomain(const QRectF& rect, const QRectF& viewport) m_domainIndex++; } -QChartAxis* ChartDataSet::axisY(QChartSeries* series) const +QChartAxis* ChartDataSet::axisY(QSeries* series) const { if(series == 0) return m_axisY; diff --git a/src/chartdataset_p.h b/src/chartdataset_p.h index dced6e0..9cdd499 100644 --- a/src/chartdataset_p.h +++ b/src/chartdataset_p.h @@ -1,7 +1,7 @@ #ifndef CHARTDATASET_P_H_ #define CHARTDATASET_P_H_ -#include "qchartseries.h" +#include "qseries.h" #include "domain_p.h" #include @@ -16,8 +16,8 @@ public: ChartDataSet(QObject* parent=0); virtual ~ChartDataSet(); - void addSeries(QChartSeries* series,QChartAxis *axisY = 0); - void removeSeries(QChartSeries* series); + void addSeries(QSeries* series,QChartAxis *axisY = 0); + void removeSeries(QSeries* series); void removeAllSeries(); void addDomain(const QRectF& rect, const QRectF& viewport); bool nextDomain(); @@ -28,15 +28,15 @@ public: void setDomain(int index); QChartAxis* axisX() const { return m_axisX;}; - QChartAxis* axisY(QChartSeries* series = 0) const; + QChartAxis* axisY(QSeries* series = 0) const; signals: - void seriesAdded(QChartSeries* series); - void seriesRemoved(QChartSeries* series); + void seriesAdded(QSeries* series); + void seriesRemoved(QSeries* series); void axisAdded(QChartAxis* axis); void axisRemoved(QChartAxis* axis); void axisLabelsChanged(QChartAxis* axis, const QStringList& labels); - void seriesDomainChanged(QChartSeries* series,const Domain& domain); + void seriesDomainChanged(QSeries* series,const Domain& domain); private slots: void handleMinChanged(qreal min); @@ -48,7 +48,7 @@ private: private: QMultiMap m_domainMap; - QMultiMap m_seriesMap; + QMultiMap m_seriesMap; QChartAxis* m_axisX; QChartAxis* m_axisY; int m_domainIndex; diff --git a/src/chartpresenter.cpp b/src/chartpresenter.cpp index 8d5c60b..61c8704 100644 --- a/src/chartpresenter.cpp +++ b/src/chartpresenter.cpp @@ -4,21 +4,21 @@ #include "chartdataset_p.h" #include "charttheme_p.h" //series -#include "qbarchartseries.h" -#include "qstackedbarchartseries.h" -#include "qpercentbarchartseries.h" -#include "qlinechartseries.h" +#include "qbarseries.h" +#include "qstackedbarseries.h" +#include "qpercentbarseries.h" +#include "qlineseries.h" #include "qpieseries.h" #include "qscatterseries.h" //items #include "axisitem_p.h" #include "axisanimationitem_p.h" -#include "barpresenter.h" -#include "stackedbarpresenter.h" +#include "barpresenter_p.h" +#include "stackedbarpresenter_p.h" +#include "percentbarpresenter_p.h" #include "linechartitem_p.h" -#include "percentbarpresenter.h" #include "linechartanimationitem_p.h" -#include "piepresenter.h" +#include "piepresenter_p.h" #include "scatterpresenter_p.h" QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -43,11 +43,11 @@ ChartPresenter::~ChartPresenter() void ChartPresenter::createConnections() { QObject::connect(m_chart,SIGNAL(geometryChanged()),this,SLOT(handleGeometryChanged())); - QObject::connect(m_dataset,SIGNAL(seriesAdded(QChartSeries*)),this,SLOT(handleSeriesAdded(QChartSeries*))); - QObject::connect(m_dataset,SIGNAL(seriesRemoved(QChartSeries*)),this,SLOT(handleSeriesRemoved(QChartSeries*))); + QObject::connect(m_dataset,SIGNAL(seriesAdded(QSeries*)),this,SLOT(handleSeriesAdded(QSeries*))); + QObject::connect(m_dataset,SIGNAL(seriesRemoved(QSeries*)),this,SLOT(handleSeriesRemoved(QSeries*))); QObject::connect(m_dataset,SIGNAL(axisAdded(QChartAxis*)),this,SLOT(handleAxisAdded(QChartAxis*))); QObject::connect(m_dataset,SIGNAL(axisRemoved(QChartAxis*)),this,SLOT(handleAxisRemoved(QChartAxis*))); - QObject::connect(m_dataset,SIGNAL(seriesDomainChanged(QChartSeries*,const Domain&)),this,SLOT(handleSeriesDomainChanged(QChartSeries*,const Domain&))); + QObject::connect(m_dataset,SIGNAL(seriesDomainChanged(QSeries*,const Domain&)),this,SLOT(handleSeriesDomainChanged(QSeries*,const Domain&))); QObject::connect(m_dataset,SIGNAL(axisLabelsChanged(QChartAxis*,const QStringList&)),this,SLOT(handleAxisLabelsChanged(QChartAxis*,const QStringList&))); } @@ -104,12 +104,12 @@ void ChartPresenter::handleAxisRemoved(QChartAxis* axis) } -void ChartPresenter::handleSeriesAdded(QChartSeries* series) +void ChartPresenter::handleSeriesAdded(QSeries* series) { switch(series->type()) { - case QChartSeries::SeriesTypeLine: { - QLineChartSeries* lineSeries = static_cast(series); + case QSeries::SeriesTypeLine: { + QLineSeries* lineSeries = static_cast(series); LineChartItem* item; if(m_options.testFlag(QChart::SeriesAnimations)){ item = new LineChartAnimationItem(this,lineSeries,m_chart); @@ -118,13 +118,13 @@ void ChartPresenter::handleSeriesAdded(QChartSeries* series) } m_chartTheme->decorate(item,lineSeries,m_chartItems.count()); QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&))); - QObject::connect(lineSeries,SIGNAL(changed(int)),item,SLOT(handleModelChanged(int))); + QObject::connect(lineSeries,SIGNAL(pointChanged(int)),item,SLOT(handleModelChanged(int))); m_chartItems.insert(series,item); break; } - case QChartSeries::SeriesTypeBar: { - QBarChartSeries* barSeries = static_cast(series); + case QSeries::SeriesTypeBar: { + QBarSeries* barSeries = static_cast(series); BarPresenter* item = new BarPresenter(barSeries,m_chart); m_chartTheme->decorate(item,barSeries,m_chartItems.count()); QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&))); @@ -134,9 +134,9 @@ void ChartPresenter::handleSeriesAdded(QChartSeries* series) break; } - case QChartSeries::SeriesTypeStackedBar: { + case QSeries::SeriesTypeStackedBar: { - QStackedBarChartSeries* stackedBarSeries = static_cast(series); + QStackedBarSeries* stackedBarSeries = static_cast(series); StackedBarPresenter* item = new StackedBarPresenter(stackedBarSeries,m_chart); m_chartTheme->decorate(item,stackedBarSeries,m_chartItems.count()); QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&))); @@ -145,9 +145,9 @@ void ChartPresenter::handleSeriesAdded(QChartSeries* series) break; } - case QChartSeries::SeriesTypePercentBar: { + case QSeries::SeriesTypePercentBar: { - QPercentBarChartSeries* percentBarSeries = static_cast(series); + QPercentBarSeries* percentBarSeries = static_cast(series); PercentBarPresenter* item = new PercentBarPresenter(percentBarSeries,m_chart); m_chartTheme->decorate(item,percentBarSeries ,m_chartItems.count()); QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&))); @@ -155,7 +155,7 @@ void ChartPresenter::handleSeriesAdded(QChartSeries* series) m_chartItems.insert(series,item); break; } - case QChartSeries::SeriesTypeScatter: { + case QSeries::SeriesTypeScatter: { QScatterSeries *scatterSeries = qobject_cast(series); ScatterPresenter *scatterPresenter = new ScatterPresenter(scatterSeries, m_chart); QObject::connect(scatterPresenter, SIGNAL(clicked()), scatterSeries, SIGNAL(clicked())); @@ -165,7 +165,7 @@ void ChartPresenter::handleSeriesAdded(QChartSeries* series) m_chartItems.insert(scatterSeries, scatterPresenter); break; } - case QChartSeries::SeriesTypePie: { + case QSeries::SeriesTypePie: { QPieSeries *s = qobject_cast(series); PiePresenter* pie = new PiePresenter(m_chart, s); m_chartTheme->decorate(pie, s, m_chartItems.count()); @@ -197,18 +197,18 @@ void ChartPresenter::handleSeriesAdded(QChartSeries* series) if(m_rect.isValid()) emit geometryChanged(m_rect); } -void ChartPresenter::handleSeriesRemoved(QChartSeries* series) +void ChartPresenter::handleSeriesRemoved(QSeries* series) { ChartItem* item = m_chartItems.take(series); delete item; } -void ChartPresenter::handleSeriesChanged(QChartSeries* series) +void ChartPresenter::handleSeriesChanged(QSeries* series) { //TODO: } -void ChartPresenter::handleSeriesDomainChanged(QChartSeries* series, const Domain& domain) +void ChartPresenter::handleSeriesDomainChanged(QSeries* series, const Domain& domain) { m_chartItems.value(series)->handleDomainChanged(domain); } @@ -225,7 +225,7 @@ void ChartPresenter::setChartTheme(QChart::ChartTheme theme) m_chartTheme = ChartTheme::createTheme(theme); m_chartTheme->decorate(m_chart); - QMapIterator i(m_chartItems); + QMapIterator i(m_chartItems); int index=0; while (i.hasNext()) { @@ -255,13 +255,13 @@ void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options) //recreate elements QList axisList = m_axisItems.uniqueKeys(); - QList seriesList = m_chartItems.uniqueKeys(); + QList seriesList = m_chartItems.uniqueKeys(); foreach(QChartAxis* axis, axisList) { handleAxisRemoved(axis); handleAxisAdded(axis); } - foreach(QChartSeries* series, seriesList) { + foreach(QSeries* series, seriesList) { handleSeriesRemoved(series); handleSeriesAdded(series); } diff --git a/src/chartpresenter_p.h b/src/chartpresenter_p.h index 456284f..62d4769 100644 --- a/src/chartpresenter_p.h +++ b/src/chartpresenter_p.h @@ -9,7 +9,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE class ChartItem; -class QChartSeries; +class QSeries; class ChartDataSet; //class QChart; class Domain; @@ -20,7 +20,14 @@ class ChartPresenter: public QObject { Q_OBJECT public: - enum ZValues { BackgroundZValue = -1 , ShadesZValue, GridZValue, AxisZValue , LineChartZValue }; + enum ZValues { + BackgroundZValue = -1, + ShadesZValue, + GridZValue, + AxisZValue, + LineChartZValue, + ScatterSeriesZValue + }; ChartPresenter(QChart* chart,ChartDataSet *dataset); virtual ~ChartPresenter(); @@ -40,18 +47,18 @@ private: void createConnections(); public slots: - void handleSeriesAdded(QChartSeries* series); - void handleSeriesRemoved(QChartSeries* series); + void handleSeriesAdded(QSeries* series); + void handleSeriesRemoved(QSeries* series); void handleAxisAdded(QChartAxis* axis); void handleAxisRemoved(QChartAxis* axis); - void handleSeriesDomainChanged(QChartSeries* series, const Domain& domain); + void handleSeriesDomainChanged(QSeries* series, const Domain& domain); void handleAxisLabelsChanged(QChartAxis* axis, const QStringList& labels); - void handleSeriesChanged(QChartSeries* series); + void handleSeriesChanged(QSeries* series); void handleGeometryChanged(); signals: void geometryChanged(const QRectF& rect); private: - QMap m_chartItems; + QMap m_chartItems; QMap m_axisItems; QChart* m_chart; ChartDataSet* m_dataset; diff --git a/src/charttheme.cpp b/src/charttheme.cpp index aadee2b..ece8aba 100644 --- a/src/charttheme.cpp +++ b/src/charttheme.cpp @@ -5,22 +5,22 @@ //series #include "qbarset.h" -#include "qbarchartseries.h" -#include "qstackedbarchartseries.h" -#include "qpercentbarchartseries.h" -#include "qlinechartseries.h" +#include "qbarseries.h" +#include "qstackedbarseries.h" +#include "qpercentbarseries.h" +#include "qlineseries.h" #include "qscatterseries.h" #include "qpieseries.h" #include "qpieslice.h" //items #include "axisitem_p.h" -#include "barpresenter.h" -#include "stackedbarpresenter.h" +#include "barpresenter_p.h" +#include "stackedbarpresenter_p.h" +#include "percentbarpresenter_p.h" #include "linechartitem_p.h" -#include "percentbarpresenter.h" #include "scatterpresenter_p.h" -#include "piepresenter.h" +#include "piepresenter_p.h" //themes #include "chartthemevanilla_p.h" @@ -80,35 +80,35 @@ void ChartTheme::decorate(QChart* chart) chart->setChartBackgroundBrush(backgroundGradient); } //TODO helper to by removed later -void ChartTheme::decorate(ChartItem* item, QChartSeries* series,int count) +void ChartTheme::decorate(ChartItem* item, QSeries* series,int count) { switch(series->type()) { - case QChartSeries::SeriesTypeLine: { - QLineChartSeries* s = static_cast(series); + case QSeries::SeriesTypeLine: { + QLineSeries* s = static_cast(series); LineChartItem* i = static_cast(item); decorate(i,s,count); break; } - case QChartSeries::SeriesTypeBar: { - QBarChartSeries* b = static_cast(series); + case QSeries::SeriesTypeBar: { + QBarSeries* b = static_cast(series); BarPresenter* i = static_cast(item); decorate(i,b,count); break; } - case QChartSeries::SeriesTypeStackedBar: { - QStackedBarChartSeries* s = static_cast(series); + case QSeries::SeriesTypeStackedBar: { + QStackedBarSeries* s = static_cast(series); StackedBarPresenter* i = static_cast(item); decorate(i,s,count); break; } - case QChartSeries::SeriesTypePercentBar: { - QPercentBarChartSeries* s = static_cast(series); + case QSeries::SeriesTypePercentBar: { + QPercentBarSeries* s = static_cast(series); PercentBarPresenter* i = static_cast(item); decorate(i,s,count); break; } - case QChartSeries::SeriesTypeScatter: { + case QSeries::SeriesTypeScatter: { QScatterSeries* s = qobject_cast(series); Q_ASSERT(s); ScatterPresenter* i = static_cast(item); @@ -116,7 +116,7 @@ void ChartTheme::decorate(ChartItem* item, QChartSeries* series,int count) decorate(i, s, count); break; } - case QChartSeries::SeriesTypePie: { + case QSeries::SeriesTypePie: { QPieSeries* s = static_cast(series); PiePresenter* i = static_cast(item); decorate(i,s,count); @@ -129,7 +129,7 @@ void ChartTheme::decorate(ChartItem* item, QChartSeries* series,int count) } -void ChartTheme::decorate(LineChartItem* item, QLineChartSeries* series,int count) +void ChartTheme::decorate(LineChartItem* item, QLineSeries* series,int count) { QPen pen; if(pen != series->pen()){ @@ -141,24 +141,27 @@ void ChartTheme::decorate(LineChartItem* item, QLineChartSeries* series,int coun item->setPen(pen); } -void ChartTheme::decorate(BarPresenter* item, QBarChartSeries* series,int count) +void ChartTheme::decorate(BarPresenter* item, QBarSeries* series,int count) { - for (int i=0; icountSets(); i++) { - series->nextSet(0==i)->setBrush(QBrush(m_seriesColor.at(i%m_seriesColor.count()))); + QList sets = series->barSets(); + for (int i=0; ibarsetCount(); i++) { + sets.at(i)->setBrush(QBrush(m_seriesColor.at(i%m_seriesColor.count()))); } } -void ChartTheme::decorate(StackedBarPresenter* item, QStackedBarChartSeries* series,int count) +void ChartTheme::decorate(StackedBarPresenter* item, QStackedBarSeries* series,int count) { - for (int i=0; icountSets(); i++) { - series->nextSet(0==i)->setBrush(QBrush(m_seriesColor.at(i%m_seriesColor.count()))); + QList sets = series->barSets(); + for (int i=0; ibarsetCount(); i++) { + sets.at(i)->setBrush(QBrush(m_seriesColor.at(i%m_seriesColor.count()))); } } -void ChartTheme::decorate(PercentBarPresenter* item, QPercentBarChartSeries* series,int count) +void ChartTheme::decorate(PercentBarPresenter* item, QPercentBarSeries* series,int count) { - for (int i=0; icountSets(); i++) { - series->nextSet(0==i)->setBrush(QBrush(m_seriesColor.at(i%m_seriesColor.count()))); + QList sets = series->barSets(); + for (int i=0; ibarsetCount(); i++) { + sets.at(i)->setBrush(QBrush(m_seriesColor.at(i%m_seriesColor.count()))); } } @@ -190,6 +193,10 @@ void ChartTheme::decorate(PiePresenter* item, QPieSeries* series, int /*count*/) QColor c = m_seriesColor[i++]; i = i % m_seriesColor.count(); + // dont use black colors... looks bad + if (c == Qt::black) + continue; + // by default use the "raw" theme color if (!colors.contains(c)) { colors << c; diff --git a/src/charttheme_p.h b/src/charttheme_p.h index 86eeb20..16a031f 100644 --- a/src/charttheme_p.h +++ b/src/charttheme_p.h @@ -8,14 +8,14 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE class ChartItem; -class QChartSeries; +class QSeries; class LineChartItem; -class QLineChartSeries; +class QLineSeries; class BarPresenter; -class QBarChartSeries; +class QBarSeries; class StackedBarPresenter; -class QStackedBarChartSeries; -class QPercentBarChartSeries; +class QStackedBarSeries; +class QPercentBarSeries; class PercentBarPresenter; class QScatterSeries; class ScatterPresenter; @@ -30,11 +30,11 @@ public: static ChartTheme* createTheme(QChart::ChartTheme theme); QChart::ChartTheme id() const {return m_id;} void decorate(QChart* chart); - void decorate(ChartItem* item, QChartSeries* series,int count); - void decorate(LineChartItem* item, QLineChartSeries*, int count); - void decorate(BarPresenter* item, QBarChartSeries* series,int count); - void decorate(StackedBarPresenter* item, QStackedBarChartSeries* series,int count); - void decorate(PercentBarPresenter* item, QPercentBarChartSeries* series,int count); + void decorate(ChartItem* item, QSeries* series,int count); + void decorate(BarPresenter* item, QBarSeries* series,int count); + void decorate(StackedBarPresenter* item, QStackedBarSeries* series,int count); + void decorate(PercentBarPresenter* item, QPercentBarSeries* series,int count); + void decorate(LineChartItem* item, QLineSeries*, int count); void decorate(ScatterPresenter* presenter, QScatterSeries* series, int count); void decorate(PiePresenter* item, QPieSeries* series, int count); void decorate(QChartAxis* axis,AxisItem* item); diff --git a/src/linechart/linechart.pri b/src/linechart/linechart.pri index 865dcd1..a3332b7 100644 --- a/src/linechart/linechart.pri +++ b/src/linechart/linechart.pri @@ -4,11 +4,11 @@ DEPENDPATH += $$PWD SOURCES += \ $$PWD/linechartanimationitem.cpp \ $$PWD/linechartitem.cpp \ - $$PWD/qlinechartseries.cpp + $$PWD/qlineseries.cpp PRIVATE_HEADERS += \ $$PWD/linechartitem_p.h \ $$PWD/linechartanimationitem_p.h PUBLIC_HEADERS += \ - $$PWD/qlinechartseries.h \ No newline at end of file + $$PWD/qlineseries.h \ No newline at end of file diff --git a/src/linechart/linechartanimationitem.cpp b/src/linechart/linechartanimationitem.cpp index 75ac2b8..0a07e80 100644 --- a/src/linechart/linechartanimationitem.cpp +++ b/src/linechart/linechartanimationitem.cpp @@ -7,7 +7,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE const static int duration = 500; -LineChartAnimationItem::LineChartAnimationItem(ChartPresenter* presenter, QLineChartSeries* series,QGraphicsItem *parent): +LineChartAnimationItem::LineChartAnimationItem(ChartPresenter* presenter, QLineSeries* series,QGraphicsItem *parent): LineChartItem(presenter,series,parent) { diff --git a/src/linechart/linechartanimationitem_p.h b/src/linechart/linechartanimationitem_p.h index 2ac6851..163df48 100644 --- a/src/linechart/linechartanimationitem_p.h +++ b/src/linechart/linechartanimationitem_p.h @@ -14,7 +14,7 @@ class LineChartAnimationItem : public LineChartItem { Q_PROPERTY(int a_addPoints READ ar_addPoints WRITE aw_addPoints); // Q_PROPERTY(QPointF a_setPoint READ ar_setPoint WRITE aw_setPoint); public: - LineChartAnimationItem(ChartPresenter* presenter, QLineChartSeries *series, QGraphicsItem *parent = 0); + LineChartAnimationItem(ChartPresenter* presenter, QLineSeries *series, QGraphicsItem *parent = 0); virtual ~LineChartAnimationItem(); void addPoints(const QVector& points); diff --git a/src/linechart/linechartitem.cpp b/src/linechart/linechartitem.cpp index 25d9e2c..2212b29 100644 --- a/src/linechart/linechartitem.cpp +++ b/src/linechart/linechartitem.cpp @@ -1,5 +1,5 @@ #include "linechartitem_p.h" -#include "qlinechartseries.h" +#include "qlineseries.h" #include "chartpresenter_p.h" #include @@ -8,7 +8,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE //TODO: optimazie : remove points which are not visible -LineChartItem::LineChartItem(ChartPresenter* presenter, QLineChartSeries* series,QGraphicsItem *parent):ChartItem(parent), +LineChartItem::LineChartItem(ChartPresenter* presenter, QLineSeries* series,QGraphicsItem *parent):ChartItem(parent), m_presenter(presenter), m_series(series), m_dirtyData(false), @@ -36,7 +36,7 @@ void LineChartItem::addPoints(const QVector& points) const QPointF& point =m_data[i]; QGraphicsRectItem* item = new QGraphicsRectItem(0,0,3,3,this); item->setPos(point.x()-1,point.y()-1);; - if(!m_clipRect.contains(point) || !m_series->isPointsVisible()) item->setVisible(false); + if(!m_clipRect.contains(point) || !m_series->pointsVisible()) item->setVisible(false); m_points << item; } } @@ -47,7 +47,7 @@ void LineChartItem::addPoint(const QPointF& point) QGraphicsRectItem* item = new QGraphicsRectItem(0,0,3,3,this); m_clipRect.contains(point); item->setPos(point.x()-1,point.y()-1); - if(!m_clipRect.contains(point) || !m_series->isPointsVisible()) item->setVisible(false); + if(!m_clipRect.contains(point) || !m_series->pointsVisible()) item->setVisible(false); m_points << item; } @@ -111,7 +111,7 @@ void LineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt painter->restore(); } -void LineChartItem::calculatePoint(QPointF& point, int index, const QLineChartSeries* series,const QSizeF& size, const Domain& domain) const +void LineChartItem::calculatePoint(QPointF& point, int index, const QLineSeries* series,const QSizeF& size, const Domain& domain) const { const qreal deltaX = size.width()/domain.spanX(); const qreal deltaY = size.height()/domain.spanY(); @@ -122,7 +122,7 @@ void LineChartItem::calculatePoint(QPointF& point, int index, const QLineChartSe } -void LineChartItem::calculatePoints(QVector& points, QHash& hash,const QLineChartSeries* series,const QSizeF& size, const Domain& domain) const +void LineChartItem::calculatePoints(QVector& points, QHash& hash,const QLineSeries* series,const QSizeF& size, const Domain& domain) const { const qreal deltaX = size.width()/domain.spanX(); const qreal deltaY = size.height()/domain.spanY(); diff --git a/src/linechart/linechartitem_p.h b/src/linechart/linechartitem_p.h index fcf3eec..68ff1c9 100644 --- a/src/linechart/linechartitem_p.h +++ b/src/linechart/linechartitem_p.h @@ -8,14 +8,14 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE class ChartPresenter; -class QLineChartSeries; +class QLineSeries; class LineChartAnimationItem; class LineChartItem : public QObject , public ChartItem { Q_OBJECT public: - LineChartItem(ChartPresenter* presenter, QLineChartSeries* series,QGraphicsItem *parent = 0); + LineChartItem(ChartPresenter* presenter, QLineSeries* series,QGraphicsItem *parent = 0); ~ LineChartItem(){}; //from QGraphicsItem @@ -43,8 +43,8 @@ protected: virtual void updateData(); virtual void updateDomain(); //refactor - void calculatePoint(QPointF& point, int index, const QLineChartSeries* series,const QSizeF& size, const Domain& domain) const; - void calculatePoints(QVector& points,QHash& hash,const QLineChartSeries* series, const QSizeF& size, const Domain& domain) const; + void calculatePoint(QPointF& point, int index, const QLineSeries* series,const QSizeF& size, const Domain& domain) const; + void calculatePoints(QVector& points,QHash& hash,const QLineSeries* series, const QSizeF& size, const Domain& domain) const; protected slots: void handleModelChanged(int index); @@ -61,7 +61,7 @@ private: QList m_points; QVector m_data; QHash m_hash; - QLineChartSeries* m_series; + QLineSeries* m_series; QPen m_pen; bool m_dirtyData; bool m_dirtyGeometry; diff --git a/src/linechart/qlinechartseries.cpp b/src/linechart/qlineseries.cpp similarity index 60% rename from src/linechart/qlinechartseries.cpp rename to src/linechart/qlineseries.cpp index 189d207..fa960ef 100644 --- a/src/linechart/qlinechartseries.cpp +++ b/src/linechart/qlineseries.cpp @@ -1,10 +1,10 @@ -#include "qlinechartseries.h" +#include "qlineseries.h" QTCOMMERCIALCHART_BEGIN_NAMESPACE /*! - \class QLineChartSeries - \brief The QLineChartSeries class is used for making line charts. + \class QLineSeries + \brief The QLineSeries class is used for making line charts. \mainclass @@ -13,41 +13,47 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE \image linechart.png - To create line charts, users need to first QLineChartSeries object. - - \snippet ../example/linechart/main.cpp 1 - - Populate with the data - - \snippet ../example/linechart/main.cpp 2 - - Add created series objects to QChartView or QChart instance. - - \snippet ../example/linechart/main.cpp 3 - + Creating basic line chart is simple: + \code + QLineSeries* series = new QLineSeries(); + series->add(0, 6); + series->add(2, 4); + ... + chartView->addSeries(series); + \endcode */ /*! - \fn virtual QChartSeriesType QLineChartSeries::type() const + \fn virtual QSeriesType QLineSeries::type() const \brief Returns type of series. - \sa QChartSeries, QChartSeriesType + \sa QSeries, QSeriesType */ /*! - \fn QPen QLineChartSeries::pen() const + \fn QPen QLineSeries::pen() const \brief Returns the pen used to draw line for this series. \sa setPen() */ /*! - \fn bool QLineChartSeries::isPointsVisible() const + \fn bool QLineSeries::pointsVisible() const \brief Returns if the points are drawn for this series. \sa setPointsVisible() */ /*! - \fn void QLineChartSeries::changed(int index) + \fn void QLineSeries::pointChanged(int index) + \brief \internal \a index +*/ + +/*! + \fn void QLineSeries::pointAdded(int index) + \brief \internal \a index +*/ + +/*! + \fn void QLineSeries::pointRemoved(int index) \brief \internal \a index */ @@ -55,7 +61,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE Constructs empty series object which is a child of \a parent. When series object is added to QChartView or QChart instance ownerships is transfered. */ -QLineChartSeries::QLineChartSeries(QObject* parent):QChartSeries(parent), +QLineSeries::QLineSeries(QObject* parent):QSeries(parent), m_pointsVisible(false) { } @@ -63,59 +69,73 @@ m_pointsVisible(false) Destroys the object. Series added to QChartView or QChart instances are owned by those, and are deleted when mentioned object are destroyed. */ -QLineChartSeries::~QLineChartSeries() +QLineSeries::~QLineSeries() { } /*! Adds data point \a x \a y to the series. Points are connected with lines on the chart. - Function returns index, which can be used to modify data. */ -int QLineChartSeries::add(qreal x,qreal y) +void QLineSeries::add(qreal x,qreal y) { + Q_ASSERT(m_x.size() == m_y.size()); m_x< #include #include QTCOMMERCIALCHART_BEGIN_NAMESPACE -class QTCOMMERCIALCHART_EXPORT QLineChartSeries : public QChartSeries +class QTCOMMERCIALCHART_EXPORT QLineSeries : public QSeries { Q_OBJECT public: - QLineChartSeries(QObject* parent=0); - virtual ~QLineChartSeries(); + QLineSeries(QObject* parent=0); + virtual ~QLineSeries(); public: // from QChartSeries - virtual QChartSeriesType type() const { return QChartSeries::SeriesTypeLine;} - int add(qreal x, qreal y); - int add(const QPointF& point); - void set(int index,qreal x,qreal y); - void set(int index,const QPointF& point); + virtual QSeriesType type() const { return QSeries::SeriesTypeLine;} + void add(qreal x, qreal y); + void add(const QPointF& point); + void replace(qreal x,qreal y); + void replace(const QPointF& point); + void remove(qreal x); + void remove(const QPointF& point); void clear(); void setPen(const QPen& pen); QPen pen() const { return m_pen;} void setPointsVisible(bool visible); - bool isPointsVisible() const {return m_pointsVisible;} + bool pointsVisible() const {return m_pointsVisible;} int count() const; qreal x(int pos) const; qreal y(int pos) const; - friend QDebug operator<< (QDebug d, const QLineChartSeries series); + + QLineSeries& operator << (const QPointF &point); + friend QDebug operator<< (QDebug d, const QLineSeries series); signals: - void changed(int index); + void pointChanged(int index); + void pointRemoved(int index); + void pointAdded(int index); private: QVector m_x; diff --git a/src/piechart/piechart.pri b/src/piechart/piechart.pri index d5018df..dbed0d8 100644 --- a/src/piechart/piechart.pri +++ b/src/piechart/piechart.pri @@ -9,9 +9,9 @@ SOURCES += \ $$PWD/qpieslice.cpp PRIVATE_HEADERS += \ - $$PWD/piepresenter.h \ - $$PWD/pieslice.h \ - $$PWD/pieslicelabel.h + $$PWD/piepresenter_p.h \ + $$PWD/pieslice_p.h \ + $$PWD/pieslicelabel_p.h PUBLIC_HEADERS += \ $$PWD/qpieseries.h \ diff --git a/src/piechart/piepresenter.cpp b/src/piechart/piepresenter.cpp index 9e5f4fd..bd6cbd1 100644 --- a/src/piechart/piepresenter.cpp +++ b/src/piechart/piepresenter.cpp @@ -1,8 +1,8 @@ -#include "piepresenter.h" -#include "pieslice.h" +#include "piepresenter_p.h" +#include "pieslice_p.h" #include "qpieslice.h" -#include "pieslicelabel.h" +#include "pieslicelabel_p.h" #include "qpieseries.h" #include #include @@ -123,7 +123,7 @@ void PiePresenter::updateGeometry() foreach (QPieSlice* s, m_series->m_slices) { // calculate the farthest point in the slice from the pie center - qreal centerAngle = s->angle() + (s->angleSpan() / 2); + qreal centerAngle = s->m_startAngle + (s->m_angleSpan / 2); qreal len = pieRadius + s->labelArmLength() + s->explodeDistance(); QPointF dp(qSin(centerAngle*(PI/180)) * len, -qCos(centerAngle*(PI/180)) * len); QPointF p = pieRect.center() + dp; @@ -205,6 +205,6 @@ void PiePresenter::deleteSlice(QPieSlice* sliceData) delete m_slices.take(sliceData); } -#include "moc_piepresenter.cpp" +#include "moc_piepresenter_p.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/piechart/piepresenter.h b/src/piechart/piepresenter_p.h similarity index 100% rename from src/piechart/piepresenter.h rename to src/piechart/piepresenter_p.h diff --git a/src/piechart/pieslice.cpp b/src/piechart/pieslice.cpp index 9893cfc..cdb07d3 100644 --- a/src/piechart/pieslice.cpp +++ b/src/piechart/pieslice.cpp @@ -1,6 +1,6 @@ -#include "pieslice.h" -#include "pieslicelabel.h" -#include "piepresenter.h" +#include "pieslice_p.h" +#include "pieslicelabel_p.h" +#include "piepresenter_p.h" #include "qpieseries.h" #include "qpieslice.h" #include @@ -21,7 +21,7 @@ QPointF offset(qreal angle, qreal length) PieSlice::PieSlice(QGraphicsItem* parent) :QGraphicsObject(parent), m_slicelabel(new PieSliceLabel(this)), - m_angle(0), + m_startAngle(0), m_angleSpan(0), m_isExploded(false), m_explodeDistance(0) @@ -80,7 +80,7 @@ void PieSlice::updateGeometry() prepareGeometryChange(); // calculate center angle - qreal centerAngle = m_angle + (m_angleSpan/2); + qreal centerAngle = m_startAngle + (m_angleSpan/2); // adjust rect for exploding QRectF rect = m_pieRect; @@ -94,7 +94,7 @@ void PieSlice::updateGeometry() // TODO: draw the shape so that it might have a hole in the center QPainterPath path; path.moveTo(rect.center()); - path.arcTo(rect, -m_angle + 90, -m_angleSpan); + path.arcTo(rect, -m_startAngle + 90, -m_angleSpan); path.closeSubpath(); m_path = path; @@ -113,8 +113,8 @@ void PieSlice::updateData(const QPieSlice* sliceData) { // TODO: compare what has changes to avoid unneccesary geometry updates - m_angle = sliceData->angle(); - m_angleSpan = sliceData->angleSpan(); + m_startAngle = sliceData->startAngle(); + m_angleSpan = sliceData->m_angleSpan; m_isExploded = sliceData->isExploded(); m_explodeDistance = sliceData->explodeDistance(); // TODO: expose to public API m_pen = sliceData->pen(); @@ -130,6 +130,6 @@ void PieSlice::updateData(const QPieSlice* sliceData) update(); } -#include "moc_pieslice.cpp" +#include "moc_pieslice_p.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/piechart/pieslice.h b/src/piechart/pieslice_p.h similarity index 98% rename from src/piechart/pieslice.h rename to src/piechart/pieslice_p.h index aca1f3f..fd0660e 100644 --- a/src/piechart/pieslice.h +++ b/src/piechart/pieslice_p.h @@ -49,7 +49,7 @@ private: QRectF m_pieRect; QPainterPath m_path; - qreal m_angle; + qreal m_startAngle; qreal m_angleSpan; bool m_isExploded; diff --git a/src/piechart/pieslicelabel.cpp b/src/piechart/pieslicelabel.cpp index c6267be..697dd93 100644 --- a/src/piechart/pieslicelabel.cpp +++ b/src/piechart/pieslicelabel.cpp @@ -1,4 +1,4 @@ -#include "pieslicelabel.h" +#include "pieslicelabel_p.h" #include #include #include diff --git a/src/piechart/pieslicelabel.h b/src/piechart/pieslicelabel_p.h similarity index 100% rename from src/piechart/pieslicelabel.h rename to src/piechart/pieslicelabel_p.h diff --git a/src/piechart/qpieseries.cpp b/src/piechart/qpieseries.cpp index 3be2d29..5eb1c58 100644 --- a/src/piechart/qpieseries.cpp +++ b/src/piechart/qpieseries.cpp @@ -1,8 +1,5 @@ #include "qpieseries.h" #include "qpieslice.h" -#include "piepresenter.h" -#include "pieslice.h" -#include #include QTCOMMERCIALCHART_BEGIN_NAMESPACE @@ -113,13 +110,21 @@ bool QPieSeries::ChangeSet::isEmpty() const By default the pie is defined as full but it can be a partial pie. This can be done by setting a starting angle and angle span to the series. + + Example on how to create a chart with pie series: + \snippet ../example/piechart/main.cpp 1 + + To help with the most common user intercation scenarions there some convenience functions. Specifically + exploding and higlighting: + \snippet ../example/piechart/main.cpp 2 + */ /*! Constructs a series object which is a child of \a parent. */ QPieSeries::QPieSeries(QObject *parent) : - QChartSeries(parent), + QSeries(parent), m_sizeFactor(1.0), m_position(PiePositionMaximized), m_pieStartAngle(0), @@ -139,14 +144,13 @@ QPieSeries::~QPieSeries() /*! Returns QChartSeries::SeriesTypePie. */ -QChartSeries::QChartSeriesType QPieSeries::type() const +QSeries::QSeriesType QPieSeries::type() const { - return QChartSeries::SeriesTypePie; + return QSeries::SeriesTypePie; } /*! - Sets an array of values to the series. - TO BE REMOVED + \internal \a data */ bool QPieSeries::setData(QList data) { @@ -154,22 +158,22 @@ bool QPieSeries::setData(QList data) QList slices; foreach (qreal value, data) slices << new QPieSlice(value, QString::number(value)); - set(slices); + replace(slices); return true; } /*! - Sets an array of \a slices to the series. + Sets an array of \a slices to the series replacing the existing slices. Slice ownership is passed to the series. */ -void QPieSeries::set(QList slices) +void QPieSeries::replace(QList slices) { clear(); add(slices); } /*! - Adds an array of slices to the series. + Adds an array of \a slices to the series. Slice ownership is passed to the series. */ void QPieSeries::add(QList slices) @@ -345,9 +349,10 @@ void QPieSeries::setLabelsVisible(bool visible) } /*! - Convenience method for exploding a slice when user clicks the pie. + Convenience method for exploding a slice when user clicks the pie. Set \a enable to true to + explode slices by clicking. - \sa QPieSlice::isExploded(), QPieSlice::setExploded() + \sa QPieSlice::isExploded(), QPieSlice::setExploded(), QPieSlice::setExplodeDistance() */ void QPieSeries::enableClickExplodes(bool enable) { @@ -360,6 +365,7 @@ void QPieSeries::enableClickExplodes(bool enable) /*! Convenience method for highlighting a slice when user hovers over the slice. It changes the slice color to be lighter and shows the label of the slice. + Set \a enable to true to highlight a slice when user hovers on top of it. \sa QPieSlice::isExploded(), QPieSlice::setExploded() */ @@ -512,8 +518,8 @@ void QPieSeries::updateDerivativeData() changed = true; } - if (s->m_angle != sliceAngle) { - s->m_angle = sliceAngle; + if (s->m_startAngle != sliceAngle) { + s->m_startAngle = sliceAngle; changed = true; } sliceAngle += sliceSpan; diff --git a/src/piechart/qpieseries.h b/src/piechart/qpieseries.h index 5804be3..289900b 100644 --- a/src/piechart/qpieseries.h +++ b/src/piechart/qpieseries.h @@ -1,7 +1,7 @@ #ifndef PIESERIES_H #define PIESERIES_H -#include "qchartseries.h" +#include "qseries.h" #include #include #include @@ -15,7 +15,7 @@ class PiePresenter; class PieSlice; class QPieSlice; -class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries +class QTCOMMERCIALCHART_EXPORT QPieSeries : public QSeries { Q_OBJECT @@ -55,11 +55,11 @@ public: virtual ~QPieSeries(); public: // from QChartSeries - QChartSeriesType type() const; + QSeriesType type() const; virtual bool setData(QList data); // TODO: remove this public: - void set(QList slices); + void replace(QList slices); void add(QList slices); void add(QPieSlice* slice); QPieSlice* add(qreal value, QString name); diff --git a/src/piechart/qpieslice.cpp b/src/piechart/qpieslice.cpp index edc0623..5c0471e 100644 --- a/src/piechart/qpieslice.cpp +++ b/src/piechart/qpieslice.cpp @@ -9,7 +9,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE /*! \class QPieSlice - \brief Defines a slice a pie series. + \brief Defines a slice in pie series. Holds all the data of a single slice in a QPieSeries and provides the means to modify slice data and customize the visual appearance of the slice. @@ -35,7 +35,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE Note that QPieSeries takes ownership of the slice when it is set/added. - \sa QPieSeries::set(), QPieSeries::add() + \sa QPieSeries::replace(), QPieSeries::add() */ QPieSlice::QPieSlice(QObject *parent) :QObject(parent), @@ -44,7 +44,7 @@ QPieSlice::QPieSlice(QObject *parent) m_isExploded(false), m_explodeDistance(DEFAULT_EXPOLODE_DISTANCE), m_percentage(0), - m_angle(0), + m_startAngle(0), m_angleSpan(0), m_pen(DEFAULT_PEN_COLOR), m_brush(DEFAULT_BRUSH_COLOR), @@ -57,7 +57,7 @@ QPieSlice::QPieSlice(QObject *parent) /*! Constructs an empty slice with given \a value, \a label and a \a parent. Note that QPieSeries takes ownership of the slice when it is set/added. - \sa QPieSeries::set(), QPieSeries::add() + \sa QPieSeries::replace(), QPieSeries::add() */ QPieSlice::QPieSlice(qreal value, QString label, QObject *parent) :QObject(parent), @@ -67,7 +67,7 @@ QPieSlice::QPieSlice(qreal value, QString label, QObject *parent) m_isExploded(false), m_explodeDistance(DEFAULT_EXPOLODE_DISTANCE), m_percentage(0), - m_angle(0), + m_startAngle(0), m_angleSpan(0), m_pen(DEFAULT_PEN_COLOR), m_brush(DEFAULT_BRUSH_COLOR), @@ -150,21 +150,21 @@ qreal QPieSlice::percentage() const Updated internally after the slice is added to the series. */ -qreal QPieSlice::angle() const +qreal QPieSlice::startAngle() const { - return m_angle; + return m_startAngle; } /*! - Returns the angle span of this slice in the series it belongs to. + Returns the end angle of this slice in the series it belongs to. Full pie is 360 degrees where 0 degrees is at 12 a'clock. Updated internally after the slice is added to the series. */ -qreal QPieSlice::angleSpan() const +qreal QPieSlice::endAngle() const { - return m_angleSpan; + return m_startAngle + m_angleSpan; } /*! diff --git a/src/piechart/qpieslice.h b/src/piechart/qpieslice.h index 3bb6425..009ede5 100644 --- a/src/piechart/qpieslice.h +++ b/src/piechart/qpieslice.h @@ -29,8 +29,8 @@ public: // generated data qreal percentage() const; - qreal angle() const; - qreal angleSpan() const; + qreal startAngle() const; + qreal endAngle() const; // customization QPen pen() const; @@ -70,6 +70,7 @@ private: // TODO: use private class friend class QPieSeries; friend class PiePresenter; + friend class PieSlice; // data qreal m_value; @@ -80,7 +81,7 @@ private: // generated data qreal m_percentage; - qreal m_angle; + qreal m_startAngle; qreal m_angleSpan; // customization diff --git a/src/qchart.cpp b/src/qchart.cpp index 6f061dd..f2a3586 100644 --- a/src/qchart.cpp +++ b/src/qchart.cpp @@ -65,7 +65,7 @@ QChart::~QChart() If auto scaling is enabled, re-scales the axes the series is bound to (both the x axis and the y axis). */ -void QChart::addSeries(QChartSeries* series, QChartAxis* axisY) +void QChart::addSeries(QSeries* series, QChartAxis* axisY) { m_dataset->addSeries(series, axisY); } @@ -76,7 +76,7 @@ void QChart::addSeries(QChartSeries* series, QChartAxis* axisY) It does not delete the pointed QChartSeries data object \sa addSeries(), removeAllSeries() */ -void QChart::removeSeries(QChartSeries* series) +void QChart::removeSeries(QSeries* series) { m_dataset->removeSeries(series); } diff --git a/src/qchart.h b/src/qchart.h index a396c5b..5f29265 100644 --- a/src/qchart.h +++ b/src/qchart.h @@ -2,7 +2,7 @@ #define QCHART_H #include -#include +#include #include #include #include @@ -12,7 +12,7 @@ class QGraphicsSceneResizeEvent; QTCOMMERCIALCHART_BEGIN_NAMESPACE class AxisItem; -class QChartSeries; +class QSeries; class PlotDomain; class BarPresenter; class QChartAxis; @@ -47,8 +47,8 @@ public: QChart(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0); ~QChart(); - void addSeries(QChartSeries* series, QChartAxis* axisY = 0); - void removeSeries(QChartSeries* series); //returns ownership , deletes axis if no series attached + void addSeries(QSeries* series, QChartAxis* axisY = 0); + void removeSeries(QSeries* series); //returns ownership , deletes axis if no series attached void removeAllSeries(); // deletes series and axis void setMargin(int margin); diff --git a/src/qchartaxis.cpp b/src/qchartaxis.cpp index 857768d..15d34bd 100644 --- a/src/qchartaxis.cpp +++ b/src/qchartaxis.cpp @@ -40,7 +40,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE */ /*! - \fn bool QChartAxis::isLabelsVisible() const + \fn bool QChartAxis::labelsVisible() const \brief Returns if grid is visible \sa setLabelsVisible() */ @@ -70,7 +70,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE */ /*! - \fn bool QChartAxis::isShadesVisible() const + \fn bool QChartAxis::shadesVisible() const \brief Returns if shades are visible. \sa setShadesVisible() */ diff --git a/src/qchartaxis.h b/src/qchartaxis.h index c7e5c39..98cb2ba 100644 --- a/src/qchartaxis.h +++ b/src/qchartaxis.h @@ -28,7 +28,7 @@ public: QPen gridPen() const {return m_gridPen;} //labels handling - bool isLabelsVisible() const { return m_labelsVisible;}; + bool labelsVisible() const { return m_labelsVisible;}; void setLabelsVisible(bool visible); void setLabelsPen(const QPen& pen); QPen labelsPen() const { return m_labelsPen;} @@ -40,7 +40,7 @@ public: int labelsAngle() const { return m_labelsAngle;}; //shades handling - bool isShadesVisible() const { return m_shadesVisible;}; + bool shadesVisible() const { return m_shadesVisible;}; void setShadesVisible(bool visible); void setShadesPen(const QPen& pen); QPen shadesPen() const { return m_shadesPen;} diff --git a/src/qchartview.cpp b/src/qchartview.cpp index 54ad249..ad900d9 100644 --- a/src/qchartview.cpp +++ b/src/qchartview.cpp @@ -75,7 +75,7 @@ void QChartView::resizeEvent(QResizeEvent *event) the y axis). \sa removeSeries(), removeAllSeries() */ -void QChartView::addSeries(QChartSeries* series,QChartAxis *axisY) +void QChartView::addSeries(QSeries* series,QChartAxis *axisY) { m_chart->addSeries(series,axisY); } @@ -86,7 +86,7 @@ void QChartView::addSeries(QChartSeries* series,QChartAxis *axisY) It does not delete the pointed QChartSeries data object \sa addSeries(), removeAllSeries() */ -void QChartView::removeSeries(QChartSeries* series) +void QChartView::removeSeries(QSeries* series) { m_chart->removeSeries(series); } diff --git a/src/qchartview.h b/src/qchartview.h index 237092c..0272edb 100644 --- a/src/qchartview.h +++ b/src/qchartview.h @@ -2,7 +2,7 @@ #define QCHARTWIDGET_H #include "qchartglobal.h" -#include "qchartseries.h" +#include "qseries.h" #include "qchart.h" #include @@ -24,8 +24,8 @@ public: //implement from QWidget void resizeEvent(QResizeEvent *event); - void addSeries(QChartSeries* series,QChartAxis* axisY=0);// takes series ownership , takes axis ownership - void removeSeries(QChartSeries* series); //returns ownership , deletes axis if no series attached + void addSeries(QSeries* series,QChartAxis* axisY=0);// takes series ownership , takes axis ownership + void removeSeries(QSeries* series); //returns ownership , deletes axis if no series attached void removeAllSeries(); // deletes series and axis int margin() const; diff --git a/src/qchartseries.cpp b/src/qseries.cpp similarity index 82% rename from src/qchartseries.cpp rename to src/qseries.cpp index 5df08fc..01fc4a0 100644 --- a/src/qchartseries.cpp +++ b/src/qseries.cpp @@ -1,7 +1,7 @@ -#include "qchartseries.h" +#include "qseries.h" /*! - \class QChartSeries + \class QSeries \brief Base class for all QtCommercial Chart series. \mainclass @@ -10,7 +10,7 @@ */ /*! - \enum QChartSeries::QChartSeriesType + \enum QSeries::QSeriesType The type of the series object. @@ -25,22 +25,22 @@ */ /*! - \fn QChartSeries::QChartSeries(QObject *parent) + \fn QSeries::QSeries(QObject *parent) \brief Constructs ChartSeries object with \a parent. */ /*! - \fn QChartSeries::~QChartSeries() + \fn QSeries::~QSeries() \brief Virtual destructor for the chart series. */ /*! - \fn QChartSeriesType QChartSeries::type() const + \fn QSeriesType QSeries::type() const \brief The type of the series. */ /*! - \fn bool QChartSeries::setModel(QAbstractItemModel *model) + \fn bool QSeries::setModel(QAbstractItemModel *model) \brief Use the \a model to provide data for the series. The model overrides possible user data set with QChartSeries type specific data setters. For example if you call both QScatterSeries::addData() and QScatterSeries::setModel, only the data provided by the model is @@ -48,5 +48,5 @@ */ QTCOMMERCIALCHART_BEGIN_NAMESPACE -#include "moc_qchartseries.cpp" +#include "moc_qseries.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/qchartseries.h b/src/qseries.h similarity index 66% rename from src/qchartseries.h rename to src/qseries.h index e8ff21f..0b5fafc 100644 --- a/src/qchartseries.h +++ b/src/qseries.h @@ -1,17 +1,18 @@ -#ifndef QCHARTSERIES_H -#define QCHARTSERIES_H +#ifndef QSERIES_H +#define QSERIES_H #include "qchartglobal.h" #include #include +#include QTCOMMERCIALCHART_BEGIN_NAMESPACE -class QTCOMMERCIALCHART_EXPORT QChartSeries : public QObject +class QTCOMMERCIALCHART_EXPORT QSeries : public QObject { Q_OBJECT public: - enum QChartSeriesType { + enum QSeriesType { SeriesTypeLine, SeriesTypeArea, SeriesTypeBar, @@ -22,14 +23,24 @@ public: SeriesTypeSpline }; + // Helper class to contain legend and color for it + // TODO: This as private class? + class Legend { + public: + QString mName; + QPen mPen; + }; + protected: - QChartSeries(QObject *parent = 0) : QObject(parent) {} + QSeries(QObject *parent = 0) : QObject(parent) {} public: - virtual ~QChartSeries() {} - virtual QChartSeriesType type() const = 0; + virtual ~QSeries() {} + virtual QSeriesType type() const = 0; // TODO virtual bool setModel(QAbstractItemModel* /*model*/) { return false; } + + virtual QList legend() { QList l; return l; } }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/scatterseries/qscatterseries.cpp b/src/scatterseries/qscatterseries.cpp index 6b17764..e99b4fa 100644 --- a/src/scatterseries/qscatterseries.cpp +++ b/src/scatterseries/qscatterseries.cpp @@ -41,16 +41,6 @@ */ /*! - \fn void QScatterSeries::hoverEnter() - \brief TODO -*/ - -/*! - \fn void QScatterSeries::hoverLeave() - \brief TODO -*/ - -/*! \fn void QScatterSeries::changed() \brief TODO */ @@ -59,20 +49,17 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE QScatterSeriesPrivate::QScatterSeriesPrivate() : m_data(QList()), - m_markerPen(QPen()), - m_markerBrush(QBrush()), + m_markerPen(QPen(QColor::Invalid)), + m_markerBrush(QBrush(QColor::Invalid)), m_markerShape(QScatterSeries::MarkerShapeDefault) { - // Initialize pen color to invalid to use a theme color by default - m_markerPen.setColor(QColor::Invalid); - m_markerBrush.setColor(QColor::Invalid); } /*! Constructs a series object which is a child of \a parent. */ QScatterSeries::QScatterSeries(QObject *parent) : - QChartSeries(parent), + QSeries(parent), d(new QScatterSeriesPrivate()) { } @@ -86,11 +73,18 @@ QScatterSeries::~QScatterSeries() } /*! + Add single data point with \a x and \a y coordinates to the series. +*/ +void QScatterSeries::add(qreal x, qreal y) +{ + d->m_data.append(QPointF(x, y)); + emit changed(); +} + +/*! Add single data point with \a value to the series. - For example: - \snippet ../example/scatter/main.cpp 2 */ -void QScatterSeries::addData(QPointF value) +void QScatterSeries::add(QPointF value) { d->m_data.append(value); emit changed(); @@ -99,7 +93,7 @@ void QScatterSeries::addData(QPointF value) /*! Add list of \a points to the series. */ -void QScatterSeries::addData(QList points) +void QScatterSeries::add(QList points) { d->m_data.append(points); emit changed(); @@ -107,7 +101,7 @@ void QScatterSeries::addData(QList points) /*! Stream operator for adding a data point with \a value to the series. - \sa addData() + \sa add() For example: \snippet ../example/scatter/main.cpp 3 @@ -121,7 +115,7 @@ QScatterSeries& QScatterSeries::operator << (const QPointF &value) /*! Stream operator for adding a list of points to the series. - \sa addData() + \sa add() */ QScatterSeries& QScatterSeries::operator << (QList value) { @@ -158,10 +152,10 @@ QList QScatterSeries::data() beatiful markers defined by the chart's theme: \image scatter_example_pen.jpg - \sa setMarkerBrush() + \sa setBrush() \sa QChart::setChartTheme() */ -void QScatterSeries::setMarkerPen(QPen pen) +void QScatterSeries::setPen(QPen pen) { d->m_markerPen = pen; } @@ -169,7 +163,7 @@ void QScatterSeries::setMarkerPen(QPen pen) /*! Returns the pen used for drawing markers. */ -QPen QScatterSeries::markerPen() +QPen QScatterSeries::pen() { return d->m_markerPen; } @@ -184,10 +178,10 @@ QPen QScatterSeries::markerPen() Would fill your scatter markers with an opaque red color: \image scatter_example_brush.jpg - \sa setMarkerPen() + \sa setPen() \sa QChart::setChartTheme() */ -void QScatterSeries::setMarkerBrush(QBrush brush) +void QScatterSeries::setBrush(QBrush brush) { d->m_markerBrush = brush; } @@ -195,7 +189,7 @@ void QScatterSeries::setMarkerBrush(QBrush brush) /*! Returns the brush used for drawing markers. */ -QBrush QScatterSeries::markerBrush() +QBrush QScatterSeries::brush() { return d->m_markerBrush; } @@ -210,7 +204,7 @@ QBrush QScatterSeries::markerBrush() Would make your scatter marker items rectangle: \image scatter_example_shape.jpg */ -void QScatterSeries::setMarkerShape(MarkerShape shape) +void QScatterSeries::setShape(MarkerShape shape) { d->m_markerShape = shape; } @@ -218,7 +212,7 @@ void QScatterSeries::setMarkerShape(MarkerShape shape) /*! Returns the shape used for drawing markers. */ -QScatterSeries::MarkerShape QScatterSeries::markerShape() +QScatterSeries::MarkerShape QScatterSeries::shape() { return (QScatterSeries::MarkerShape) d->m_markerShape; } diff --git a/src/scatterseries/qscatterseries.h b/src/scatterseries/qscatterseries.h index 640637a..0063390 100644 --- a/src/scatterseries/qscatterseries.h +++ b/src/scatterseries/qscatterseries.h @@ -1,14 +1,14 @@ #ifndef QSCATTERSERIES_H #define QSCATTERSERIES_H -#include "qchartseries.h" +#include "qseries.h" #include #include QTCOMMERCIALCHART_BEGIN_NAMESPACE class QScatterSeriesPrivate; -class QTCOMMERCIALCHART_EXPORT QScatterSeries : public QChartSeries +class QTCOMMERCIALCHART_EXPORT QScatterSeries : public QSeries { Q_OBJECT @@ -30,31 +30,28 @@ public: ~QScatterSeries(); public: // from QChartSeries - QChartSeriesType type() const { return QChartSeries::SeriesTypeScatter; } + QSeriesType type() const { return QSeries::SeriesTypeScatter; } public: - void addData(QPointF value); - void addData(QList points); + void add(qreal x, qreal y); + void add(QPointF value); + void add(QList points); void setData(QList points); QScatterSeries& operator << (const QPointF &value); QScatterSeries& operator << (QList points); QList data(); - //TODO: insertData? + //TODO: insert, replace, remove, clear...? - QPen markerPen(); - QBrush markerBrush(); - MarkerShape markerShape(); + QPen pen(); + void setPen(QPen pen); + QBrush brush(); + void setBrush(QBrush brush); + MarkerShape shape(); + void setShape(MarkerShape shape); // TODO: marker size? -public Q_SLOTS: - void setMarkerPen(QPen pen); - void setMarkerBrush(QBrush brush); - void setMarkerShape(MarkerShape shape); - Q_SIGNALS: void clicked(/* TODO: parameters? */); - void hoverEnter(/* TODO: parameters? */); - void hoverLeave(/* TODO: parameters? */); // TODO: move to PIMPL for simplicity or does the user ever need changed signals? // TODO: more finegrained signaling for performance reasons // (check QPieSeries implementation with change sets) diff --git a/src/scatterseries/scatterpresenter.cpp b/src/scatterseries/scatterpresenter.cpp index 619306b..a8c93f8 100644 --- a/src/scatterseries/scatterpresenter.cpp +++ b/src/scatterseries/scatterpresenter.cpp @@ -1,9 +1,11 @@ #include "scatterpresenter_p.h" #include "qscatterseries.h" +#include "chartpresenter_p.h" #include #include #include #include +#include #include #include @@ -13,8 +15,6 @@ ScatterPresenter::ScatterPresenter(QScatterSeries *series, QGraphicsObject *pare ChartItem(parent), m_series(series), m_boundingRect(), - //m_markerColor(QColor()), -// m_markerColor(QColor(255, 0, 0)), m_visibleChartArea() { if (parent) @@ -23,6 +23,14 @@ ScatterPresenter::ScatterPresenter(QScatterSeries *series, QGraphicsObject *pare if (series) { connect(series, SIGNAL(changed()), this, SLOT(handleModelChanged())); } + + setZValue(ChartPresenter::ScatterSeriesZValue); + + // TODO: how to draw a drop shadow? +// QGraphicsDropShadowEffect *dropShadow = new QGraphicsDropShadowEffect(); +// dropShadow->setOffset(2.0); +// dropShadow->setBlurRadius(2.0); +// setGraphicsEffect(dropShadow); } void ScatterPresenter::handleDomainChanged(const Domain& domain) @@ -48,25 +56,34 @@ void ScatterPresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem * painter->save(); painter->setClipRect(m_boundingRect); + // TODO: how to draw a drop shadow? + // Now using a custom implementation for drop shadow instead of QGraphicsDropShadowEffect. + // It seems QGraphicsDropShadowEffect is quite heavy, at least on windows without open gl. + QPen dropShadowPen(QColor(0, 0, 0, 70)); + dropShadowPen.setWidth(3); + painter->setPen(dropShadowPen); + painter->setBrush(dropShadowPen.color()); +// painter->setRenderHint(QPainter::Antialiasing); + painter->drawPath(m_path.translated(2, 2)); + // Paint the shape // The custom settings in series override those defined by the theme QPen pen = m_markerPen; - if (m_series->markerPen().color().isValid()) - pen = m_series->markerPen(); - if (m_series->markerBrush().color().isValid()) - painter->setBrush(m_series->markerBrush()); + if (m_series->pen().color().isValid()) + pen = m_series->pen(); + painter->setPen(pen); + if (m_series->brush().color().isValid()) + painter->setBrush(m_series->brush()); else painter->setBrush(m_markerBrush); - painter->setPen(pen); - painter->drawPath(m_path); - // TODO: how to draw a drop shadow? - QPen dropShadowPen(QColor(0, 0, 0, 70)); - dropShadowPen.setWidth(3); - painter->setPen(dropShadowPen); - painter->setBrush(Qt::NoBrush); - painter->setRenderHint(QPainter::Antialiasing); - painter->drawPath(m_path.translated(2, 2)); + // If either pen or brush is opaque, we need to draw the polygons one-by-one + if (painter->pen().color().alpha() < 255 || painter->brush().color().alpha() < 255) { + foreach (QPolygonF pol, m_path.toSubpathPolygons()) + painter->drawPolygon(pol); + } else { + painter->drawPath(m_path); + } painter->restore(); } @@ -87,8 +104,9 @@ void ScatterPresenter::changeGeometry() qreal scalex = m_boundingRect.width() / m_visibleChartArea.spanX(); qreal scaley = m_boundingRect.height() / m_visibleChartArea.spanY(); - int shape = m_series->markerShape(); + int shape = m_series->shape(); m_path = QPainterPath(); + m_path.setFillRule(Qt::WindingFill); foreach (QPointF point, m_series->data()) { // Convert relative coordinates to absolute pixel coordinates that can be used for drawing @@ -109,14 +127,8 @@ void ScatterPresenter::changeGeometry() m_path.addRect(x, y, 9, 9); break; case QScatterSeries::MarkerShapeTiltedRectangle: { - // TODO: -// static const QPointF points[4] = { -// QPointF(-1.0 + x, 0.0 + y), -// QPointF(0.0 + x, 1.0 + y), -// QPointF(1.0 + x, 0.0 + y), -// QPointF(0.0 + x, -1.0 + y) -// }; - //m_path.addPolygon(QPolygon(4, &points)); + // TODO: tilt the rectangle + m_path.addRect(x, y, 9, 9); break; } default: diff --git a/src/scatterseries/scatterseries_p.h b/src/scatterseries/scatterseries_p.h index 8ca522e..4518812 100644 --- a/src/scatterseries/scatterseries_p.h +++ b/src/scatterseries/scatterseries_p.h @@ -2,7 +2,7 @@ #define QSCATTERSERIESPRIVATE_H #include "qchartglobal.h" -#include "qchartseries.h" +#include "qseries.h" #include QTCOMMERCIALCHART_BEGIN_NAMESPACE diff --git a/src/src.pro b/src/src.pro index 9a29bd6..1bc5f5c 100644 --- a/src/src.pro +++ b/src/src.pro @@ -6,8 +6,7 @@ QT += core \ gui CONFIG += debug_and_release CONFIG(debug, debug|release):TARGET = QtCommercialChartd -SOURCES += \ - axisitem.cpp \ +SOURCES += axisitem.cpp \ axisanimationitem.cpp \ chartdataset.cpp \ chartpresenter.cpp \ @@ -15,28 +14,24 @@ SOURCES += \ domain.cpp \ qchart.cpp \ qchartaxis.cpp \ - qchartseries.cpp \ - qchartview.cpp -PRIVATE_HEADERS += \ - axisitem_p.h \ + qchartview.cpp \ + qseries.cpp +PRIVATE_HEADERS += axisitem_p.h \ axisanimationitem_p.h \ chartdataset_p.h \ chartitem_p.h \ chartpresenter_p.h \ charttheme_p.h \ domain_p.h -PUBLIC_HEADERS += \ - qchart.h \ +PUBLIC_HEADERS += qchart.h \ qchartaxis.h \ qchartglobal.h \ - qchartseries.h \ - qchartview.h \ - -include(linechart/linechart.pri) -include(barchart/barchart.pri) + qseries.h \ + qchartview.h +include(linechart/linechart.pri) +include(barchart/barchart.pri) include(piechart/piechart.pri) include(scatterseries/scatter.pri) - THEMES += themes/chartthemeicy_p.h \ themes/chartthemegrayscale_p.h \ themes/chartthemescientific_p.h \ @@ -74,7 +69,8 @@ install_build_private_headers.commands = $$QMAKE_COPY \ $$CHART_BUILD_PRIVATE_HEADER_DIR install_build_private_headers.CONFIG += target_predeps \ no_link -QMAKE_EXTRA_COMPILERS += install_build_public_headers install_build_private_headers +QMAKE_EXTRA_COMPILERS += install_build_public_headers \ + install_build_private_headers chartversion.target = qchartversion_p.h chartversion.commands = @echo \ "build_time" \ @@ -91,4 +87,3 @@ unix:QMAKE_DISTCLEAN += -r \ win32:QMAKE_DISTCLEAN += /Q \ $$CHART_BUILD_HEADER_DIR \ $$CHART_BUILD_LIB_DIR - diff --git a/test/auto/chartdataset/tst_chartdataset.cpp b/test/auto/chartdataset/tst_chartdataset.cpp index 9d6e5e6..2bf9185 100644 --- a/test/auto/chartdataset/tst_chartdataset.cpp +++ b/test/auto/chartdataset/tst_chartdataset.cpp @@ -1,7 +1,6 @@ #include #include -#include -#include +#include #include #include @@ -9,8 +8,8 @@ QTCOMMERCIALCHART_USE_NAMESPACE Q_DECLARE_METATYPE(Domain) Q_DECLARE_METATYPE(QChartAxis*) -Q_DECLARE_METATYPE(QChartSeries*) -Q_DECLARE_METATYPE(QLineChartSeries*) +Q_DECLARE_METATYPE(QSeries*) +Q_DECLARE_METATYPE(QLineSeries*) class tst_ChartDataSet: public QObject { Q_OBJECT @@ -47,7 +46,7 @@ void tst_ChartDataSet::initTestCase() { qRegisterMetaType("Domain"); qRegisterMetaType(); - qRegisterMetaType(); + qRegisterMetaType(); } void tst_ChartDataSet::cleanupTestCase() @@ -99,7 +98,7 @@ void tst_ChartDataSet::addDomain() ChartDataSet dataSet; Domain domain1(0, 1000, 0, 1000); - QLineChartSeries series; + QLineSeries series; series.add(0, 0); series.add(1000, 1000); @@ -111,10 +110,10 @@ void tst_ChartDataSet::addDomain() QSignalSpy spy1(&dataSet, SIGNAL(axisLabelsChanged(QChartAxis*, QStringList const&))); QSignalSpy spy2(&dataSet, SIGNAL(axisRemoved(QChartAxis*))); - QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QChartSeries*))); + QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QSeries*))); QSignalSpy spy4(&dataSet, - SIGNAL(seriesDomainChanged(QChartSeries*, Domain const&))); - QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QChartSeries*))); + SIGNAL(seriesDomainChanged(QSeries*, Domain const&))); + QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QSeries*))); Domain domain2 = dataSet.domain(dataSet.axisY()); QVERIFY(domain1 == domain2); @@ -157,10 +156,10 @@ void tst_ChartDataSet::addSeries() QSignalSpy spy1(&dataSet, SIGNAL(axisLabelsChanged(QChartAxis*, QStringList const&))); QSignalSpy spy2(&dataSet, SIGNAL(axisRemoved(QChartAxis*))); - QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QChartSeries*))); + QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QSeries*))); QSignalSpy spy4(&dataSet, - SIGNAL(seriesDomainChanged(QChartSeries*, Domain const&))); - QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QChartSeries*))); + SIGNAL(seriesDomainChanged(QSeries*, Domain const&))); + QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QSeries*))); QList axisList; @@ -173,7 +172,7 @@ void tst_ChartDataSet::addSeries() for (int i = 0; i < seriesCount; i++) { QChartAxis* axisY = 0; - QLineChartSeries* series = new QLineChartSeries(); + QLineSeries* series = new QLineSeries(); if (iterator != axisList.end()) { axisY = *iterator; iterator++; @@ -218,10 +217,10 @@ void tst_ChartDataSet::axisY() QVERIFY2(defaultAxisY, "Missing axisY."); - QLineChartSeries* series1 = new QLineChartSeries(); + QLineSeries* series1 = new QLineSeries(); dataSet.addSeries(series1); - QLineChartSeries* series2 = new QLineChartSeries(); + QLineSeries* series2 = new QLineSeries(); dataSet.addSeries(series2, axisY); QVERIFY(dataSet.axisY(series1) == defaultAxisY); @@ -244,7 +243,7 @@ void tst_ChartDataSet::clearDomains() QFETCH(int, indexCount); Domain domain1(0, 100, 0, 100); - QLineChartSeries* series = new QLineChartSeries(); + QLineSeries* series = new QLineSeries(); series->add(0, 0); series->add(100, 100); @@ -271,10 +270,10 @@ void tst_ChartDataSet::clearDomains() QSignalSpy spy1(&dataSet, SIGNAL(axisLabelsChanged(QChartAxis*, QStringList const&))); QSignalSpy spy2(&dataSet, SIGNAL(axisRemoved(QChartAxis*))); - QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QChartSeries*))); + QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QSeries*))); QSignalSpy spy4(&dataSet, - SIGNAL(seriesDomainChanged(QChartSeries*, Domain const&))); - QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QChartSeries*))); + SIGNAL(seriesDomainChanged(QSeries*, Domain const&))); + QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QSeries*))); dataSet.clearDomains(indexCount); @@ -315,13 +314,13 @@ void tst_ChartDataSet::domain() QFETCH(Domain, domain); ChartDataSet dataSet; - QLineChartSeries* series1 = new QLineChartSeries(); + QLineSeries* series1 = new QLineSeries(); series1->add(domain1.m_minX, domain1.m_minY); series1->add(domain1.m_maxX, domain1.m_maxY); - QLineChartSeries* series2 = new QLineChartSeries(); + QLineSeries* series2 = new QLineSeries(); series2->add(domain2.m_minX, domain2.m_minY); series2->add(domain2.m_maxX, domain2.m_maxY); - QLineChartSeries* series3 = new QLineChartSeries(); + QLineSeries* series3 = new QLineSeries(); series3->add(domain3.m_minX, domain3.m_minY); series3->add(domain3.m_maxX, domain3.m_maxY); @@ -329,10 +328,10 @@ void tst_ChartDataSet::domain() QSignalSpy spy1(&dataSet, SIGNAL(axisLabelsChanged(QChartAxis*, QStringList const&))); QSignalSpy spy2(&dataSet, SIGNAL(axisRemoved(QChartAxis*))); - QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QChartSeries*))); + QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QSeries*))); QSignalSpy spy4(&dataSet, - SIGNAL(seriesDomainChanged(QChartSeries*, Domain const&))); - QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QChartSeries*))); + SIGNAL(seriesDomainChanged(QSeries*, Domain const&))); + QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QSeries*))); dataSet.addSeries(series1); dataSet.addSeries(series2); @@ -370,7 +369,7 @@ void tst_ChartDataSet::nextpreviousDomain() ChartDataSet dataSet; Domain domain1(0, 1000, 0, 1000); - QLineChartSeries* series = new QLineChartSeries(); + QLineSeries* series = new QLineSeries(); series->add(0, 0); series->add(1000, 1000); @@ -406,10 +405,10 @@ void tst_ChartDataSet::nextpreviousDomain() QSignalSpy spy1(&dataSet, SIGNAL(axisLabelsChanged(QChartAxis*, QStringList const&))); QSignalSpy spy2(&dataSet, SIGNAL(axisRemoved(QChartAxis*))); - QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QChartSeries*))); + QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QSeries*))); QSignalSpy spy4(&dataSet, - SIGNAL(seriesDomainChanged(QChartSeries*, Domain const&))); - QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QChartSeries*))); + SIGNAL(seriesDomainChanged(QSeries*, Domain const&))); + QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QSeries*))); Domain domain; @@ -476,7 +475,7 @@ void tst_ChartDataSet::removeSeries() ChartDataSet dataSet; QList axisList; - QList seriesList; + QList seriesList; for (int i = 0; i < axisYCount; i++) { QChartAxis* axis = new QChartAxis(); @@ -487,7 +486,7 @@ void tst_ChartDataSet::removeSeries() for (int i = 0; i < seriesCount; i++) { QChartAxis* axisY = 0; - QLineChartSeries* series = new QLineChartSeries(); + QLineSeries* series = new QLineSeries(); if (iterator != axisList.end()) { axisY = *iterator; iterator++; @@ -504,10 +503,10 @@ void tst_ChartDataSet::removeSeries() QSignalSpy spy1(&dataSet, SIGNAL(axisLabelsChanged(QChartAxis*, QStringList const&))); QSignalSpy spy2(&dataSet, SIGNAL(axisRemoved(QChartAxis*))); - QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QChartSeries*))); + QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QSeries*))); QSignalSpy spy4(&dataSet, - SIGNAL(seriesDomainChanged(QChartSeries*, Domain const&))); - QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QChartSeries*))); + SIGNAL(seriesDomainChanged(QSeries*, Domain const&))); + QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QSeries*))); for (int i = 0; i < seriesCount; i++) { dataSet.removeSeries(seriesList.at(i)); @@ -559,7 +558,7 @@ void tst_ChartDataSet::removeAllSeries() for (int i = 0; i < seriesCount; i++) { QChartAxis* axisY = 0; - QLineChartSeries* series = new QLineChartSeries(); + QLineSeries* series = new QLineSeries(); if (iterator != axisList.end()) { axisY = *iterator; iterator++; @@ -574,9 +573,9 @@ void tst_ChartDataSet::removeAllSeries() QSignalSpy spy0(&dataSet, SIGNAL(axisAdded(QChartAxis*))); QSignalSpy spy1(&dataSet, SIGNAL(axisLabelsChanged(QChartAxis*, QStringList const&))); QSignalSpy spy2(&dataSet, SIGNAL(axisRemoved(QChartAxis*))); - QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QChartSeries*))); - QSignalSpy spy4(&dataSet, SIGNAL(seriesDomainChanged(QChartSeries*, Domain const&))); - QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QChartSeries*))); + QSignalSpy spy3(&dataSet, SIGNAL(seriesAdded(QSeries*))); + QSignalSpy spy4(&dataSet, SIGNAL(seriesDomainChanged(QSeries*, Domain const&))); + QSignalSpy spy5(&dataSet, SIGNAL(seriesRemoved(QSeries*))); dataSet.removeAllSeries(); //default axis diff --git a/test/chartwidgettest/dataseriedialog.cpp b/test/chartwidgettest/dataseriedialog.cpp index 78bd77c..4d2f2eb 100644 --- a/test/chartwidgettest/dataseriedialog.cpp +++ b/test/chartwidgettest/dataseriedialog.cpp @@ -8,7 +8,7 @@ #include #include -DataSerieDialog::DataSerieDialog(QString defaultType, QWidget *parent) : +DataSerieDialog::DataSerieDialog(QWidget *parent) : QDialog(parent) { QDialogButtonBox *addSeriesBox = new QDialogButtonBox(Qt::Horizontal); @@ -53,6 +53,7 @@ QGroupBox *DataSerieDialog::seriesTypeSelector() QGroupBox *groupBox = new QGroupBox("Series type"); groupBox->setLayout(layout); + selectRadio(groupBox, 0); return groupBox; } @@ -72,6 +73,7 @@ QGroupBox *DataSerieDialog::columnCountSelector() QGroupBox *groupBox = new QGroupBox("Column count"); groupBox->setLayout(layout); + selectRadio(groupBox, 0); return groupBox; } @@ -91,6 +93,7 @@ QGroupBox *DataSerieDialog::rowCountSelector() QGroupBox *groupBox = new QGroupBox("Row count"); groupBox->setLayout(layout); + selectRadio(groupBox, 0); return groupBox; } @@ -99,9 +102,7 @@ QGroupBox *DataSerieDialog::dataCharacteristicsSelector() { QVBoxLayout *layout = new QVBoxLayout(); - QRadioButton *radio1 = new QRadioButton("Linear"); - radio1->setChecked(true); - layout->addWidget(radio1); + layout->addWidget(new QRadioButton("Linear")); layout->addWidget(new QRadioButton("Constant")); layout->addWidget(new QRadioButton("Random")); layout->addWidget(new QRadioButton("Sin")); @@ -109,6 +110,7 @@ QGroupBox *DataSerieDialog::dataCharacteristicsSelector() QGroupBox *groupBox = new QGroupBox("Data Characteristics"); groupBox->setLayout(layout); + selectRadio(groupBox, 0); return groupBox; } @@ -123,6 +125,24 @@ void DataSerieDialog::accept() QDialog::accept(); } +void DataSerieDialog::selectRadio(QGroupBox *groupBox, int defaultSelection) +{ + QVBoxLayout *layout = qobject_cast(groupBox->layout()); + Q_ASSERT(layout); + Q_ASSERT(layout->count()); + + QLayoutItem *item = 0; + if (defaultSelection == -1) { + item = layout->itemAt(0); + } else if (layout->count() > defaultSelection) { + item = layout->itemAt(defaultSelection); + } + Q_ASSERT(item); + QRadioButton *radio = qobject_cast(item->widget()); + Q_ASSERT(radio); + radio->setChecked(true); +} + QString DataSerieDialog::radioSelection(QGroupBox *groupBox) { QString selection; diff --git a/test/chartwidgettest/dataseriedialog.h b/test/chartwidgettest/dataseriedialog.h index 9ba83c6..fc016dc 100644 --- a/test/chartwidgettest/dataseriedialog.h +++ b/test/chartwidgettest/dataseriedialog.h @@ -10,7 +10,7 @@ class DataSerieDialog : public QDialog { Q_OBJECT public: - explicit DataSerieDialog(QString defaultType, QWidget *parent = 0); + explicit DataSerieDialog(QWidget *parent = 0); signals: void accepted(QString series, int columnCount, int rowCount, QString dataCharacteristics, bool labelsDefined); @@ -23,6 +23,7 @@ private: QGroupBox *columnCountSelector(); QGroupBox *rowCountSelector(); QGroupBox *dataCharacteristicsSelector(); + void selectRadio(QGroupBox *groupBox, int defaultSelection); QString radioSelection(QGroupBox *groupBox); QGroupBox *m_seriesTypeSelector; QGroupBox *m_columnCountSelector; diff --git a/test/chartwidgettest/mainwidget.cpp b/test/chartwidgettest/mainwidget.cpp index 735ecce..42cb270 100644 --- a/test/chartwidgettest/mainwidget.cpp +++ b/test/chartwidgettest/mainwidget.cpp @@ -1,14 +1,12 @@ #include "mainwidget.h" #include "dataseriedialog.h" -#include "qchartseries.h" #include "qpieseries.h" #include "qscatterseries.h" -#include +#include #include -#include -#include -#include -#include +#include +#include +#include #include #include #include @@ -26,10 +24,12 @@ QTCOMMERCIALCHART_USE_NAMESPACE MainWidget::MainWidget(QWidget *parent) : - QWidget(parent) + QWidget(parent), + m_addSerieDialog(0), + m_chartView(0) { - m_chartWidget = new QChartView(this); - m_chartWidget->setRubberBandPolicy(QChartView::HorizonalRubberBand); + m_chartView = new QChartView(this); + m_chartView->setRubberBandPolicy(QChartView::HorizonalRubberBand); // Grid layout for the controls for configuring the chart widget QGridLayout *grid = new QGridLayout(); @@ -39,10 +39,8 @@ MainWidget::MainWidget(QWidget *parent) : initBackroundCombo(grid); initScaleControls(grid); initThemeCombo(grid); - QCheckBox *zoomCheckBox = new QCheckBox("Drag'n drop Zoom"); - connect(zoomCheckBox, SIGNAL(toggled(bool)), m_chartWidget, SLOT(setZoomEnabled(bool))); - zoomCheckBox->setChecked(true); - grid->addWidget(zoomCheckBox, grid->rowCount(), 0); + initCheckboxes(grid); + // add row with empty label to make all the other rows static grid->addWidget(new QLabel(""), grid->rowCount(), 0); grid->setRowStretch(grid->rowCount() - 1, 1); @@ -61,7 +59,7 @@ MainWidget::MainWidget(QWidget *parent) : // mainLayout->addLayout(m_scatterLayout, 1, 0); // Add layouts and the chart widget to the main layout - mainLayout->addWidget(m_chartWidget, 0, 1, 3, 1); + mainLayout->addWidget(m_chartView, 0, 1, 3, 1); setLayout(mainLayout); } @@ -135,6 +133,26 @@ void MainWidget::initThemeCombo(QGridLayout *grid) grid->addWidget(chartTheme, 8, 1); } +// Different check boxes for customizing chart +void MainWidget::initCheckboxes(QGridLayout *grid) +{ + // TODO: setZoomEnabled slot has been removed from QChartView -> Re-implement zoom on/off + QCheckBox *zoomCheckBox = new QCheckBox("Drag'n drop Zoom"); + connect(zoomCheckBox, SIGNAL(toggled(bool)), m_chartView, SLOT(setZoomEnabled(bool))); + zoomCheckBox->setChecked(true); + grid->addWidget(zoomCheckBox, grid->rowCount(), 0); + + QCheckBox *aliasCheckBox = new QCheckBox("Anti-alias"); + connect(aliasCheckBox, SIGNAL(toggled(bool)), this, SLOT(antiAliasToggled(bool))); + aliasCheckBox->setChecked(false); + grid->addWidget(aliasCheckBox, grid->rowCount(), 0); +} + +void MainWidget::antiAliasToggled(bool enabled) +{ + m_chartView->setRenderHint(QPainter::Antialiasing, enabled); +} + void MainWidget::initPieControls() { // Pie series specific settings @@ -164,10 +182,12 @@ void MainWidget::initPieControls() void MainWidget::addSeries() { - DataSerieDialog dialog(m_defaultSeriesName, this); - connect(&dialog, SIGNAL(accepted(QString, int, int, QString, bool)), - this, SLOT(addSeries(QString, int, int, QString, bool))); - dialog.exec(); + if (!m_addSerieDialog) { + m_addSerieDialog = new DataSerieDialog(this); + connect(m_addSerieDialog, SIGNAL(accepted(QString, int, int, QString, bool)), + this, SLOT(addSeries(QString, int, int, QString, bool))); + } + m_addSerieDialog->exec(); } QList MainWidget::generateTestData(int columnCount, int rowCount, QString dataCharacteristics) @@ -219,11 +239,11 @@ void MainWidget::addSeries(QString seriesName, int columnCount, int rowCount, QS if (seriesName.contains("line", Qt::CaseInsensitive)) { for (int j(0); j < data.count(); j ++) { QList column = data.at(j); - QLineChartSeries *series = new QLineChartSeries(); + QLineSeries *series = new QLineSeries(); for (int i(0); i < column.count(); i++) { series->add(i, column.at(i)); } - m_chartWidget->addSeries(series); + m_chartView->addSeries(series); setCurrentSeries(series); } } else if (seriesName.contains("scatter", Qt::CaseInsensitive)) { @@ -233,7 +253,7 @@ void MainWidget::addSeries(QString seriesName, int columnCount, int rowCount, QS for (int i(0); i < column.count(); i++) { (*series) << QPointF(i, column.at(i)); } - m_chartWidget->addSeries(series); + m_chartView->addSeries(series); setCurrentSeries(series); } } else if (seriesName.contains("pie", Qt::CaseInsensitive)) { @@ -244,24 +264,23 @@ void MainWidget::addSeries(QString seriesName, int columnCount, int rowCount, QS for (int i(0); i < column.count(); i++) { series->add(column.at(i), labels.at(i)); } - m_chartWidget->addSeries(series); + m_chartView->addSeries(series); setCurrentSeries(series); } } else if (seriesName == "Bar" || seriesName == "Stacked bar" || seriesName == "Percent bar") { - // TODO: replace QBarCategory with QStringList? - QBarCategory *category = new QBarCategory; + QStringList category; QStringList labels = generateLabels(rowCount); foreach(QString label, labels) - *category << label; - QBarChartSeries* series = 0; + category << label; + QBarSeries* series = 0; if (seriesName == "Bar") - series = new QBarChartSeries(category, this); + series = new QBarSeries(category, this); else if (seriesName == "Stacked bar") - series = new QStackedBarChartSeries(category, this); + series = new QStackedBarSeries(category, this); else - series = new QPercentBarChartSeries(category, this); + series = new QPercentBarSeries(category, this); for (int j(0); j < data.count(); j++) { QList column = data.at(j); @@ -271,34 +290,34 @@ void MainWidget::addSeries(QString seriesName, int columnCount, int rowCount, QS } series->addBarSet(set); } - series->enableFloatingValues(); - series->enableToolTip(); - series->enableSeparators(false); - m_chartWidget->addSeries(series); + series->setFloatingValuesEnabled(true); + series->setToolTipEnabled(true); + series->setSeparatorsEnabled(false); + m_chartView->addSeries(series); setCurrentSeries(series); } // TODO: spline and area } -void MainWidget::setCurrentSeries(QChartSeries *series) +void MainWidget::setCurrentSeries(QSeries *series) { if (series) { m_currentSeries = series; switch (m_currentSeries->type()) { - case QChartSeries::SeriesTypeLine: + case QSeries::SeriesTypeLine: break; - case QChartSeries::SeriesTypeScatter: + case QSeries::SeriesTypeScatter: break; - case QChartSeries::SeriesTypePie: + case QSeries::SeriesTypePie: break; - case QChartSeries::SeriesTypeBar: + case QSeries::SeriesTypeBar: qDebug() << "setCurrentSeries (bar)"; break; - case QChartSeries::SeriesTypeStackedBar: + case QSeries::SeriesTypeStackedBar: qDebug() << "setCurrentSeries (Stackedbar)"; break; - case QChartSeries::SeriesTypePercentBar: + case QSeries::SeriesTypePercentBar: qDebug() << "setCurrentSeries (Percentbar)"; break; default: @@ -350,7 +369,7 @@ void MainWidget::yMaxChanged(int value) void MainWidget::changeChartTheme(int themeIndex) { qDebug() << "changeChartTheme: " << themeIndex; - m_chartWidget->setChartTheme((QChart::ChartTheme) themeIndex); + m_chartView->setChartTheme((QChart::ChartTheme) themeIndex); //TODO: remove this hack. This is just to make it so that theme change is seen immediately. QSize s = size(); s.setWidth(s.width()+1); diff --git a/test/chartwidgettest/mainwidget.h b/test/chartwidgettest/mainwidget.h index 21fe2fc..2bcbddc 100644 --- a/test/chartwidgettest/mainwidget.h +++ b/test/chartwidgettest/mainwidget.h @@ -12,6 +12,7 @@ class QGridLayout; QTCOMMERCIALCHART_USE_NAMESPACE #define RealList QList +class DataSerieDialog; class MainWidget : public QWidget { @@ -25,6 +26,7 @@ private: void initBackroundCombo(QGridLayout *grid); void initScaleControls(QGridLayout *grid); void initThemeCombo(QGridLayout *grid); + void initCheckboxes(QGridLayout *grid); void initPieControls(); private slots: @@ -36,7 +38,8 @@ private slots: void xMaxChanged(int value); void yMinChanged(int value); void yMaxChanged(int value); - void setCurrentSeries(QChartSeries *series); + void antiAliasToggled(bool enabled); + void setCurrentSeries(QSeries *series); void changeChartTheme(int themeIndex); void setPieSizeFactor(double margin); void setPiePosition(int position); @@ -44,14 +47,15 @@ private slots: QStringList generateLabels(int count); private: - QChartView *m_chartWidget; + DataSerieDialog *m_addSerieDialog; + QChartView *m_chartView; QCheckBox *m_autoScaleCheck; QSpinBox *m_xMinSpin; QSpinBox *m_xMaxSpin; QSpinBox *m_yMinSpin; QSpinBox *m_yMaxSpin; QString m_defaultSeriesName; - QChartSeries *m_currentSeries; + QSeries *m_currentSeries; QGridLayout *m_scatterLayout; QGridLayout *m_pieLayout; };
linechartlinechart barchartpiechart
linechartpiechart
scatterchart themechart