##// END OF EJS Templates
bug fix in bar charts. Crashed, if layout was set before data. Also integrated to test app.
sauimone -
r165:2ff4f264aa68
parent child
Show More
@@ -1,159 +1,157
1 1 #include <limits.h>
2 2 #include <QVector>
3 3 #include <QDebug>
4 4 #include "barchartmodel_p.h"
5 5
6 6 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7 7
8 8 BarChartModel::BarChartModel(QObject *parent) :
9 9 QObject(parent)
10 10 ,mRunningId(1)
11 11 {
12 12 }
13 13
14 14 BarChartModel::~BarChartModel()
15 15 {
16 qDebug() << "BarChartModel::~BarChartModel";
16 // qDebug() << "BarChartModel::~BarChartModel";
17 17 foreach (DataContainer* c, mDataModel) {
18 18 delete c;
19 19 }
20 20 }
21 21
22 22 int BarChartModel::addData(QList<qreal> data)
23 23 {
24 qDebug() << "BarChartModel::addData" << data.count();
24 // qDebug() << "BarChartModel::addData" << data.count();
25 25 DataContainer* c = new DataContainer(data,mRunningId);
26 26 mDataModel.append(c);
27 27 mRunningId++;
28 28 return mRunningId-1;
29 29 }
30 30
31 31 void BarChartModel::removeData(int id)
32 32 {
33 qDebug() << "BarChartModel::removeData";
33 // qDebug() << "BarChartModel::removeData";
34 34 foreach(DataContainer* c, mDataModel) {
35 35 if (c->mId == id) {
36 36 mDataModel.removeOne(c);
37 37 delete c;
38 38 }
39 39 }
40 40 }
41 41
42 42 int BarChartModel::countRows()
43 43 {
44 qDebug() << "BarChartModel::countRows";
44 // qDebug() << "BarChartModel::countRows";
45 45 return mDataModel.count();
46 46 }
47 47
48 48 int BarChartModel::countColumns()
49 49 {
50 qDebug() << "BarChartModel::countColumns";
50 // qDebug() << "BarChartModel::countColumns";
51 51 int count(0);
52 52 for (int i=0; i<mDataModel.count(); i++){
53 53 // TODO: can we assume that all series have same number of values? If not. then which values are empty?
54 54 int temp = mDataModel.at(i)->countColumns();
55 55 if (temp > count) {
56 56 count = temp;
57 57 }
58 58 }
59 59 return count;
60 60 }
61 61
62 62 int BarChartModel::countTotalItems()
63 63 {
64 qDebug() << "BarChartModel::countTotalItems";
64 // qDebug() << "BarChartModel::countTotalItems";
65 65 int total = mDataModel.count() * countColumns();
66 qDebug() << "BarChartModel::countTotalItems datamodel count" << mDataModel.count();
67 qDebug() << "BarChartModel::countTotalItems countColumns count" << countColumns();
68 66 return total;
69 67 }
70 68
71 69 int BarChartModel::min()
72 70 {
73 qDebug() << "BarChartModel::min";
71 // qDebug() << "BarChartModel::min";
74 72 Q_ASSERT(mDataModel.count() > 0);
75 73 // TODO: make min and max members and update them when data changes.
76 74 // This is slower since they are checked every time, even if data is same since previous call.
77 75 int min = INT_MAX;
78 76
79 77 for (int i=0; i <mDataModel.count(); i++) {
80 78 int itemCount = mDataModel.at(i)->countColumns();
81 79 for (int j=0; j<itemCount; j++) {
82 80 int temp = mDataModel.at(i)->valueAt(j);
83 81 if (temp < min) {
84 82 min = temp;
85 83 }
86 84 }
87 85 }
88 86 return min;
89 87 }
90 88
91 89 int BarChartModel::max()
92 90 {
93 qDebug() << "BarChartModel::max";
91 // qDebug() << "BarChartModel::max";
94 92 Q_ASSERT(mDataModel.count() > 0);
95 93
96 94 // TODO: make min and max members and update them when data changes.
97 95 // This is slower since they are checked every time, even if data is same since previous call.
98 96 int max = INT_MIN;
99 97
100 98 for (int i=0; i <mDataModel.count(); i++) {
101 99 int itemCount = mDataModel.at(i)->countColumns();
102 100 for (int j=0; j<itemCount; j++) {
103 101 int temp = mDataModel.at(i)->valueAt(j);
104 102 if (temp > max) {
105 103 max = temp;
106 104 }
107 105 }
108 106 }
109 107
110 108 return max;
111 109 }
112 110
113 111 qreal BarChartModel::valueAt(int series, int item)
114 112 {
115 qDebug() << "BarChartModel::valueAt" << series << item;
113 // qDebug() << "BarChartModel::valueAt" << series << item;
116 114 if ((series < 0) || (series >= mDataModel.count())) {
117 115 // No series, no value.
118 116 return 0;
119 117 } else if ((item < 0) || (item >= mDataModel.at(series)->countColumns())) {
120 118 // No item, no value.
121 119 return 0;
122 120 }
123 121
124 qDebug() << "ValueAt" << series << item << "=" << mDataModel.at(series)->valueAt(item);
122 // qDebug() << "ValueAt" << series << item << "=" << mDataModel.at(series)->valueAt(item);
125 123 return mDataModel.at(series)->valueAt(item);
126 124 }
127 125
128 126 qreal BarChartModel::columnSum(int column)
129 127 {
130 qDebug() << "BarChartModel::columnSum";
128 // qDebug() << "BarChartModel::columnSum";
131 129 int sum(0);
132 130 int count = mDataModel.count(); // Count rows
133 131
134 132 for (int row = 0; row < count; row++) {
135 133 if (column < mDataModel.at(row)->countColumns()) {
136 134 sum += mDataModel.at(row)->valueAt(column);
137 135 }
138 136 }
139 137 return sum;
140 138 }
141 139
142 140 qreal BarChartModel::maxColumnSum()
143 141 {
144 qDebug() << "BarChartModel::maxColumnSum";
142 // qDebug() << "BarChartModel::maxColumnSum";
145 143 int max = INT_MIN;
146 144 int count = countColumns();
147 145
148 146 for (int col=0; col<count; col++) {
149 147 int sum = columnSum(col);
150 148 if (sum > max) {
151 149 max = sum;
152 150 }
153 151 }
154 152 return max;
155 153 }
156 154
157 155 #include "moc_barchartmodel_p.cpp"
158 156
159 157 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,65 +1,70
1 1 #include "bargroup.h"
2 2 #include "bar_p.h"
3 3 #include "barlabel_p.h"
4 4 #include <QDebug>
5 5
6 6 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7 7
8 8 BarGroup::BarGroup(BarChartSeries& series, QGraphicsItem *parent) :
9 9 BarGroupBase(series,parent)
10 10 {
11 11 mBarDefaultWidth = 10;
12 12 }
13 13
14 14 void BarGroup::layoutChanged()
15 15 {
16 16 qDebug() << "BarGroup::layoutChanged";
17 17 // Scale bars to new layout
18 18 // Layout for bars:
19 19 if (mModel.countRows() <= 0) {
20 20 return;
21 21 }
22 22
23 if (childItems().count() == 0) {
24 qDebug() << "WARNING: BarGroup::layoutChanged called before graphics items are created!";
25 return;
26 }
27
23 28 // TODO: better way to auto-layout?
24 29 // Use reals for accurancy (we might get some compiler warnings... :)
25 30 int itemCount = mModel.countColumns();
26 31 int seriesCount = mModel.countRows();
27 32
28 33 qreal tW = mWidth;
29 34 qreal tH = mHeight;
30 35 qreal tM = mMax;
31 36 qreal scale = (tH/tM);
32 37
33 38 qreal tC = itemCount+1;
34 39 qreal xStepPerSeries = (tW/tC);
35 40
36 41 // Scaling.
37 42 int itemIndex(0);
38 43 int labelIndex = itemCount * seriesCount;
39 44
40 45 for (int item=0; item < itemCount; item++) {
41 46 qreal xPos = xStepPerSeries * item + ((tW + mBarDefaultWidth*seriesCount)/(itemCount*2));
42 47 qreal yPos = mHeight;
43 48 for (int series = 0; series < seriesCount; series++) {
44 49 qreal barHeight = mModel.valueAt(series, item) * scale;
45 50 Bar* bar = reinterpret_cast<Bar*> (childItems().at(itemIndex));
46 51
47 52 // TODO: width settable per bar?
48 53 bar->resize(mBarDefaultWidth, barHeight);
49 54 bar->setColor(mColors.at(series));
50 55 bar->setPos(xPos, yPos-barHeight); // item*posStep+startPos + series * mBarDefaultWidth, mHeight);
51 56 itemIndex++;
52 57 xPos += mBarDefaultWidth;
53 58 }
54 59
55 60 // TODO: Layout for labels, remove magic number
56 61 xPos = xStepPerSeries * item + ((tW + mBarDefaultWidth*seriesCount)/(itemCount*2));
57 62 BarLabel* label = reinterpret_cast<BarLabel*> (childItems().at(labelIndex));
58 63 label->setPos(xPos, mHeight + 20);
59 64 labelIndex++;
60 65 }
61 66
62 67 mLayoutDirty = true;
63 68 }
64 69
65 70 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,133 +1,127
1 1 #include "bargroupbase.h"
2 2 #include "bar_p.h"
3 3 #include "barlabel_p.h"
4 4 #include "separator_p.h"
5 5 #include "barchartseriesbase.h"
6 6 #include <QDebug>
7 7
8 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 9
10 10 BarGroupBase::BarGroupBase(BarChartSeriesBase& series, QGraphicsItem *parent)
11 11 : ChartItem(parent)
12 12 ,mBarDefaultWidth(20) // TODO: remove hard coding, when we have layout code ready
13 13 ,mLayoutSet(false)
14 14 ,mLayoutDirty(true)
15 15 ,mTheme(0)
16 16 ,mSeparatorsVisible(true)
17 17 ,mModel(series.model())
18 18 {
19 19 }
20 20
21 21 void BarGroupBase::setSeparatorsVisible(bool visible)
22 22 {
23 23 mSeparatorsVisible = visible;
24 24 }
25 25
26 26 void BarGroupBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
27 27 {
28 qDebug() << "BarGroupBase::paint" << childItems().count();
28 // qDebug() << "BarGroupBase::paint" << childItems().count();
29 29 if (!mLayoutSet) {
30 30 qDebug() << "BarGroupBase::paint called without layout set. Aborting.";
31 31 return;
32 32 }
33 33 // if (mLayoutDirty) {
34 34 // Layout or data has changed. Need to redraw.
35 35 foreach(QGraphicsItem* i, childItems()) {
36 36 i->paint(painter,option,widget);
37 37 }
38 38 // }
39 39 }
40 40
41 41 QRectF BarGroupBase::boundingRect() const
42 42 {
43 43 return QRectF(0,0,mWidth,mHeight);
44 44 }
45 /*
46 void BarGroupBase::themeChanged(ChartTheme *theme)
47 {
48 qDebug() << "BarGroupBase::themeChanged"
49 // mTheme = theme;
50 }
51 */
45
52 46 void BarGroupBase::setBarWidth( int w )
53 47 {
54 48 mBarDefaultWidth = w;
55 49 }
56 50
57 51 int BarGroupBase::addColor( QColor color )
58 52 {
59 qDebug() << "BarGroupBase::addColor";
53 // qDebug() << "BarGroupBase::addColor";
60 54 int colorIndex = mColors.count();
61 55 mColors.append(color);
62 56 return colorIndex;
63 57 }
64 58
65 59 void BarGroupBase::resetColors()
66 60 {
67 qDebug() << "BarGroupBase::resetColors";
61 // qDebug() << "BarGroupBase::resetColors";
68 62 mColors.clear();
69 63 }
70 64
71 65 void BarGroupBase::dataChanged()
72 66 {
73 qDebug() << "BarGroupBase::dataChanged";
67 // qDebug() << "BarGroupBase::dataChanged";
74 68
75 69 // Delete old bars
76 70 foreach (QGraphicsItem* item, childItems()) {
77 71 delete item;
78 72 }
79 73
80 74 // Create new graphic items for bars
81 75 int totalItems = mModel.countTotalItems(); // mSeries.countTotalItems();
82 76 for (int i=0; i<totalItems; i++) {
83 77 Bar *bar = new Bar(this);
84 78 childItems().append(bar);
85 79 }
86 80
87 81 // TODO: labels from series. This creates just some example labels
88 82 int count = mModel.countColumns(); // mSeries.countColumns();
89 83 for (int i=0; i<count; i++) {
90 84 BarLabel* label = new BarLabel(this);
91 85 QString text("Label " + QString::number(i));
92 86 label->set(text);
93 87 childItems().append(label);
94 88 }
95 89
96 90 count = mModel.countColumns() - 1; // mSeries.countColumns() - 1; // There is one less separator than columns
97 91 for (int i=0; i<count; i++) {
98 92 Separator* sep = new Separator(this);
99 93 sep->setColor(QColor(255,0,0,255)); // TODO: color for separations from theme
100 94 childItems().append(sep);
101 95 }
102 96
103 97 // TODO: if (autolayout) { layoutChanged() } or something
104 98 mLayoutDirty = true;
105 99 }
106 100
107 101 //handlers
108 102
109 103 void BarGroupBase::handleModelChanged(int index)
110 104 {
111 qDebug() << "BarGroupBase::handleModelChanged" << index;
105 // qDebug() << "BarGroupBase::handleModelChanged" << index;
112 106 dataChanged();
113 107 }
114 108
115 109 void BarGroupBase::handleDomainChanged(const Domain& domain)
116 110 {
117 qDebug() << "BarGroupBase::handleDomainChanged";
111 // qDebug() << "BarGroupBase::handleDomainChanged";
118 112 dataChanged();
119 113 }
120 114
121 115 void BarGroupBase::handleGeometryChanged(const QRectF& rect)
122 116 {
123 qDebug() << "BarGroupBase::handleGeometryChanged";
117 // qDebug() << "BarGroupBase::handleGeometryChanged";
124 118 mWidth = rect.width();
125 119 mHeight = rect.height();
126 120 layoutChanged();
127 121 mLayoutSet = true;
128 122 setPos(rect.topLeft());
129 123 }
130 124
131 125 #include "moc_bargroupbase.cpp"
132 126
133 127 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,73 +1,77
1 1 #include "percentbargroup.h"
2 2 #include "bar_p.h"
3 3 #include "barlabel_p.h"
4 4 #include "separator_p.h"
5 5 #include <QDebug>
6 6
7 7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8 8
9 9
10 10 PercentBarGroup::PercentBarGroup(PercentBarChartSeries& series, QGraphicsItem *parent) :
11 11 BarGroupBase(series, parent)
12 12 {
13 13 }
14 14
15 15 void PercentBarGroup::layoutChanged()
16 16 {
17 17 // Scale bars to new layout
18 18 // Layout for bars:
19 19 if (mModel.countRows() <= 0) {
20 20 // Nothing to do.
21 21 return;
22 22 }
23 23
24 if (childItems().count() == 0) {
25 qDebug() << "WARNING: PercentBarGroup::layoutChanged called before graphics items are created!";
26 return;
27 }
28
24 29 // TODO: better way to auto-layout
25 30 // Use reals for accurancy (we might get some compiler warnings... :)
26 31 int count = mModel.countColumns();
27 32 int itemIndex(0);
28 33 qreal tW = mWidth;
29 34 qreal tC = count+1;
30 35 qreal xStep = (tW/tC);
31 // qreal xPos = ((tW/tC) + mBarDefaultWidth / 2);
32 36 qreal xPos = ((tW/tC) - mBarDefaultWidth / 2);
33 37 int labelIndex = mModel.countColumns() * mModel.countRows();
34 38
35 39 for (int column = 0; column < mModel.countColumns(); column++) {
36 40 qreal colSum = mModel.columnSum(column);
37 41 qreal h = mHeight;
38 42 qreal scale = (h / colSum);
39 43 qreal yPos = h;
40 44 for (int row=0; row < mModel.countRows(); row++) {
41 45 qreal barHeight = mModel.valueAt(row, column) * scale;
42 46 Bar* bar = reinterpret_cast<Bar*> (childItems().at(itemIndex));
43 47
44 48 // TODO: width settable per bar?
45 49 bar->resize(mBarDefaultWidth, barHeight);
46 50 bar->setColor(mColors.at(row));
47 51 bar->setPos(xPos, yPos-barHeight);
48 52 itemIndex++;
49 53 yPos -= barHeight;
50 54 }
51 55
52 56 // TODO: Layout for labels, remove magic number
53 57 BarLabel* label = reinterpret_cast<BarLabel*> (childItems().at(labelIndex));
54 58 label->setPos(xPos, mHeight + 20);
55 59 labelIndex++;
56 60 xPos += xStep;
57 61 }
58 62
59 63 // Position separators
60 64 int separatorIndex = labelIndex; // Separators are after labels in childItems(). TODO: better way to store these?
61 65 xPos = xStep + xStep/2; // Initial position is between first and second group. ie one and half steps from left.
62 66 for (int s=0; s < mModel.countColumns() - 1; s++) {
63 67 Separator* sep = reinterpret_cast<Separator*> (childItems().at(separatorIndex));
64 68 sep->setPos(xPos,0);
65 69 sep->setSize(QSizeF(1,mHeight));
66 70 xPos += xStep;
67 71 separatorIndex++;
68 72 }
69 73
70 74 mLayoutDirty = true;
71 75 }
72 76
73 77 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,81 +1,86
1 1 #include "stackedbargroup.h"
2 2 #include "bar_p.h"
3 3 #include "barlabel_p.h"
4 4 #include "separator_p.h"
5 5 #include <QDebug>
6 6
7 7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8 8
9 9 StackedBarGroup::StackedBarGroup(StackedBarChartSeries& series, QGraphicsItem *parent) :
10 10 BarGroupBase(series,parent)
11 11 {
12 12 }
13 13
14 14 void StackedBarGroup::layoutChanged()
15 15 {
16 16 qDebug() << "StackedBarGroup::layoutChanged";
17 17 // Scale bars to new layout
18 18 // Layout for bars:
19 19 if (mModel.countRows() <= 0) {
20 20 // Nothing to do.
21 21 return;
22 22 }
23 23
24 24 if (mModel.countColumns() == 0) {
25 25 // Nothing to do
26 26 return;
27 27 }
28 28
29 if (childItems().count() == 0) {
30 qDebug() << "WARNING: StackedBarGroup::layoutChanged called before graphics items are created!";
31 return;
32 }
33
29 34 // TODO: better way to auto-layout
30 35 // Use reals for accurancy (we might get some compiler warnings... :)
31 36 // TODO: use temp variable for column count...
32 37 qreal maxSum = mModel.maxColumnSum();
33 38 qreal h = mHeight;
34 39 qreal scale = (h / maxSum);
35 40
36 41 int itemIndex(0);
37 42 qreal tW = mWidth;
38 43 qreal tC = mModel.countColumns() + 1;
39 44 qreal xStep = (tW/tC);
40 45 qreal xPos = ((tW/tC) - mBarDefaultWidth / 2);
41 46 int labelIndex = mModel.countRows() * mModel.countColumns();
42 47
43 48 for (int column = 0; column < mModel.countColumns(); column++) {
44 49 qreal yPos = h;
45 50 for (int row=0; row < mModel.countRows(); row++) {
46 51 qreal barHeight = mModel.valueAt(row, column) * scale;
47 52 Bar* bar = reinterpret_cast<Bar*> (childItems().at(itemIndex));
48 53
49 54 // TODO: width settable per bar?
50 55 // TODO: theme stuff
51 56 // mTheme->themeForSeries();
52 57 bar->resize(mBarDefaultWidth, barHeight);
53 58 bar->setColor(mColors.at(row));
54 59 bar->setPos(xPos, yPos-barHeight);
55 60 itemIndex++;
56 61 yPos -= barHeight;
57 62 }
58 63
59 64 // TODO: Layout for labels, remove magic number
60 65 BarLabel* label = reinterpret_cast<BarLabel*> (childItems().at(labelIndex));
61 66 label->setPos(xPos, mHeight + 20);
62 67 labelIndex++;
63 68 xPos += xStep;
64 69 }
65 70
66 71
67 72 // Position separators
68 73 int separatorIndex = labelIndex; // Separators are after labels in childItems(). TODO: better way to store these?
69 74 xPos = xStep + xStep/2; // Initial position is between first and second group. ie one and half steps from left.
70 75 for (int s=0; s < mModel.countColumns() - 1; s++) {
71 76 Separator* sep = reinterpret_cast<Separator*> (childItems().at(separatorIndex));
72 77 sep->setPos(xPos,0);
73 78 sep->setSize(QSizeF(1,mHeight));
74 79 xPos += xStep;
75 80 separatorIndex++;
76 81 }
77 82
78 83 mLayoutDirty = true;
79 84 }
80 85
81 86 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,62 +1,65
1 1 #include "dataseriedialog.h"
2 2 #include <QDialogButtonBox>
3 3 #include <QGridLayout>
4 4 #include <QComboBox>
5 5 #include <QPushButton>
6 6 #include <QLabel>
7 7 #include <QDebug>
8 8
9 9 DataSerieDialog::DataSerieDialog(QString defaultType, QWidget *parent) :
10 10 QDialog(parent)
11 11 {
12 12 // Combo box for selecting the series type
13 13 m_seriesTypeCombo = new QComboBox(this);
14 14 m_seriesTypeCombo->addItem("Line");
15 15 m_seriesTypeCombo->addItem("Area");
16 16 m_seriesTypeCombo->addItem("Bar");
17 m_seriesTypeCombo->addItem("StackedBar");
18 m_seriesTypeCombo->addItem("PercentBar");
17 19 m_seriesTypeCombo->addItem("Pie");
18 20 m_seriesTypeCombo->addItem("Scatter");
19 21 m_seriesTypeCombo->addItem("Spline");
20 22
21 23 // Allow pre-selection of a series type
22 24 if (defaultType != "") {
23 25 int index = m_seriesTypeCombo->findText(defaultType);
24 26 if (index > 0)
25 27 m_seriesTypeCombo->setCurrentIndex(index);
26 28 }
27 29
28 30 // Combo box for selecting data for the new series
29 31 m_testDataCombo = new QComboBox(this);
30 32 m_testDataCombo->addItem("linear");
31 33 m_testDataCombo->addItem("linear, 1M");
32 34 m_testDataCombo->addItem("SIN");
33 35 m_testDataCombo->addItem("SIN + random");
36 m_testDataCombo->addItem("Table, 5 series");
34 37 m_testDataCombo->addItem("TODO From file...");
35 38 m_testDataCombo->addItem("TODO From URL...");
36 39
37 40 QDialogButtonBox *addSeriesBox = new QDialogButtonBox(Qt::Horizontal);
38 41 QPushButton *b = addSeriesBox->addButton(QDialogButtonBox::Ok);
39 42 connect(b, SIGNAL(clicked()), this, SLOT(accept()));
40 43 b = addSeriesBox->addButton(QDialogButtonBox::Cancel);
41 44 connect(b, SIGNAL(clicked()), this, SLOT(reject()));
42 45
43 46 QGridLayout *grid = new QGridLayout();
44 47 grid->addWidget(new QLabel("Series type:"), 0, 0);
45 48 grid->addWidget(m_seriesTypeCombo, 0, 1);
46 49 grid->addWidget(new QLabel("Data:"), 1, 0);
47 50 grid->addWidget(m_testDataCombo, 1, 1);
48 51 grid->addWidget(addSeriesBox, 2, 1);
49 52
50 53 setLayout(grid);
51 54 }
52 55
53 56 void DataSerieDialog::accept()
54 57 {
55 58 accepted(m_seriesTypeCombo->currentText(), m_testDataCombo->currentText());
56 59 QDialog::accept();
57 60 }
58 61 //void DataSerieDialog::addSeries(QAbstractButton *button)
59 62 //{
60 63 // addSeries(button->text().toAscii());
61 64 // accept();
62 65 //}
@@ -1,379 +1,401
1 1 #include "mainwidget.h"
2 2 #include "dataseriedialog.h"
3 3 #include "qchartseries.h"
4 4 #include "qpieseries.h"
5 5 #include <qlinechartseries.h>
6 6 #include <barchartseries.h>
7 7 #include <stackedbarchartseries.h>
8 #include <percentbarchartseries.h>
8 9 #include <QPushButton>
9 10 #include <QComboBox>
10 11 #include <QSpinBox>
11 12 #include <QCheckBox>
12 13 #include <QGridLayout>
13 14 #include <QHBoxLayout>
14 15 #include <QLabel>
15 16 #include <QSpacerItem>
16 17 #include <QMessageBox>
17 18 #include <cmath>
18 19 #include <QDebug>
19 20 #include <QStandardItemModel>
20 21
21 22
22 23 QTCOMMERCIALCHART_USE_NAMESPACE
23 24
24 25 MainWidget::MainWidget(QWidget *parent) :
25 26 QWidget(parent)
26 27 {
27 28 m_chartWidget = new QChartView(this);
28 29 m_chartWidget->setRubberBandPolicy(QChartView::HorizonalRubberBand);
29 30
30 31 // Grid layout for the controls for configuring the chart widget
31 32 QGridLayout *grid = new QGridLayout();
32 33 QPushButton *addSeriesButton = new QPushButton("Add series");
33 34 connect(addSeriesButton, SIGNAL(clicked()), this, SLOT(addSeries()));
34 35 grid->addWidget(addSeriesButton, 0, 1);
35 36 initBackroundCombo(grid);
36 37 initScaleControls(grid);
37 38 initThemeCombo(grid);
38 39 QCheckBox *zoomCheckBox = new QCheckBox("Drag'n drop Zoom");
39 40 connect(zoomCheckBox, SIGNAL(toggled(bool)), m_chartWidget, SLOT(setZoomEnabled(bool)));
40 41 zoomCheckBox->setChecked(true);
41 42 grid->addWidget(zoomCheckBox, grid->rowCount(), 0);
42 43 // add row with empty label to make all the other rows static
43 44 grid->addWidget(new QLabel(""), grid->rowCount(), 0);
44 45 grid->setRowStretch(grid->rowCount() - 1, 1);
45 46
46 47 // Another grid layout as a main layout
47 48 QGridLayout *mainLayout = new QGridLayout();
48 49 mainLayout->addLayout(grid, 0, 0);
49 50
50 51 // Init series type specific controls
51 52 initPieControls();
52 53 mainLayout->addLayout(m_pieLayout, 2, 0);
53 54 // Scatter series specific settings
54 55 // m_scatterLayout = new QGridLayout();
55 56 // m_scatterLayout->addWidget(new QLabel("scatter"), 0, 0);
56 57 // m_scatterLayout->setEnabled(false);
57 58 // mainLayout->addLayout(m_scatterLayout, 1, 0);
58 59
59 60 // Add layouts and the chart widget to the main layout
60 61 mainLayout->addWidget(m_chartWidget, 0, 1, 3, 1);
61 62 setLayout(mainLayout);
62 63
63 64 // force an update to test data
64 65 testDataChanged(0);
65 66 }
66 67
67 68 // Combo box for selecting the chart's background
68 69 void MainWidget::initBackroundCombo(QGridLayout *grid)
69 70 {
70 71 QComboBox *backgroundCombo = new QComboBox(this);
71 72 backgroundCombo->addItem("Color");
72 73 backgroundCombo->addItem("Gradient");
73 74 backgroundCombo->addItem("Image");
74 75 connect(backgroundCombo, SIGNAL(currentIndexChanged(int)),
75 76 this, SLOT(backgroundChanged(int)));
76 77
77 78 grid->addWidget(new QLabel("Background:"), grid->rowCount(), 0);
78 79 grid->addWidget(backgroundCombo, grid->rowCount() - 1, 1);
79 80 }
80 81
81 82 // Scale related controls (auto-scale vs. manual min-max values)
82 83 void MainWidget::initScaleControls(QGridLayout *grid)
83 84 {
84 85 m_autoScaleCheck = new QCheckBox("Automatic scaling");
85 86 connect(m_autoScaleCheck, SIGNAL(stateChanged(int)), this, SLOT(autoScaleChanged(int)));
86 87 // Allow setting also non-sense values (like -2147483648 and 2147483647)
87 88 m_xMinSpin = new QSpinBox();
88 89 m_xMinSpin->setMinimum(INT_MIN);
89 90 m_xMinSpin->setMaximum(INT_MAX);
90 91 m_xMinSpin->setValue(0);
91 92 connect(m_xMinSpin, SIGNAL(valueChanged(int)), this, SLOT(xMinChanged(int)));
92 93 m_xMaxSpin = new QSpinBox();
93 94 m_xMaxSpin->setMinimum(INT_MIN);
94 95 m_xMaxSpin->setMaximum(INT_MAX);
95 96 m_xMaxSpin->setValue(10);
96 97 connect(m_xMaxSpin, SIGNAL(valueChanged(int)), this, SLOT(xMaxChanged(int)));
97 98 m_yMinSpin = new QSpinBox();
98 99 m_yMinSpin->setMinimum(INT_MIN);
99 100 m_yMinSpin->setMaximum(INT_MAX);
100 101 m_yMinSpin->setValue(0);
101 102 connect(m_yMinSpin, SIGNAL(valueChanged(int)), this, SLOT(yMinChanged(int)));
102 103 m_yMaxSpin = new QSpinBox();
103 104 m_yMaxSpin->setMinimum(INT_MIN);
104 105 m_yMaxSpin->setMaximum(INT_MAX);
105 106 m_yMaxSpin->setValue(10);
106 107 connect(m_yMaxSpin, SIGNAL(valueChanged(int)), this, SLOT(yMaxChanged(int)));
107 108
108 109 grid->addWidget(m_autoScaleCheck, grid->rowCount(), 0);
109 110 grid->addWidget(new QLabel("x min:"), grid->rowCount(), 0);
110 111 grid->addWidget(m_xMinSpin, grid->rowCount() - 1, 1);
111 112 grid->addWidget(new QLabel("x max:"), grid->rowCount(), 0);
112 113 grid->addWidget(m_xMaxSpin, grid->rowCount() - 1, 1);
113 114 grid->addWidget(new QLabel("y min:"), grid->rowCount(), 0);
114 115 grid->addWidget(m_yMinSpin, grid->rowCount() - 1, 1);
115 116 grid->addWidget(new QLabel("y max:"), grid->rowCount(), 0);
116 117 grid->addWidget(m_yMaxSpin, grid->rowCount() - 1, 1);
117 118
118 119 m_autoScaleCheck->setChecked(true);
119 120 }
120 121
121 122 // Combo box for selecting theme
122 123 void MainWidget::initThemeCombo(QGridLayout *grid)
123 124 {
124 125 QComboBox *chartTheme = new QComboBox();
125 126 chartTheme->addItem("Default");
126 127 chartTheme->addItem("Vanilla");
127 128 chartTheme->addItem("Icy");
128 129 chartTheme->addItem("Grayscale");
129 130 chartTheme->addItem("Scientific");
130 131 chartTheme->addItem("Unnamed1");
131 132 connect(chartTheme, SIGNAL(currentIndexChanged(int)),
132 133 this, SLOT(changeChartTheme(int)));
133 134 grid->addWidget(new QLabel("Chart theme:"), 8, 0);
134 135 grid->addWidget(chartTheme, 8, 1);
135 136 }
136 137
137 138 void MainWidget::initPieControls()
138 139 {
139 140 // Pie series specific settings
140 141 // Pie size factory
141 142 QDoubleSpinBox *pieSizeSpin = new QDoubleSpinBox();
142 143 pieSizeSpin->setMinimum(LONG_MIN);
143 144 pieSizeSpin->setMaximum(LONG_MAX);
144 145 pieSizeSpin->setValue(1.0);
145 146 pieSizeSpin->setSingleStep(0.1);
146 147 connect(pieSizeSpin, SIGNAL(valueChanged(double)), this, SLOT(setPieSizeFactor(double)));
147 148 // Pie position
148 149 QComboBox *piePosCombo = new QComboBox(this);
149 150 piePosCombo->addItem("Maximized");
150 151 piePosCombo->addItem("Top left");
151 152 piePosCombo->addItem("Top right");
152 153 piePosCombo->addItem("Bottom left");
153 154 piePosCombo->addItem("Bottom right");
154 155 connect(piePosCombo, SIGNAL(currentIndexChanged(int)),
155 156 this, SLOT(setPiePosition(int)));
156 157 m_pieLayout = new QGridLayout();
157 158 m_pieLayout->setEnabled(false);
158 159 m_pieLayout->addWidget(new QLabel("Pie size factor"), 0, 0);
159 160 m_pieLayout->addWidget(pieSizeSpin, 0, 1);
160 161 m_pieLayout->addWidget(new QLabel("Pie position"), 1, 0);
161 162 m_pieLayout->addWidget(piePosCombo, 1, 1);
162 163 }
163 164
164 165 void MainWidget::addSeries()
165 166 {
166 167 DataSerieDialog dialog(m_defaultSeriesName, this);
167 168 connect(&dialog, SIGNAL(accepted(QString, QString)), this, SLOT(addSeries(QString, QString)));
168 169 dialog.exec();
169 170 }
170 171
171 172 void MainWidget::addSeries(QString series, QString data)
172 173 {
173 174 qDebug() << "addSeries: " << series << " data: " << data;
174 175 m_defaultSeriesName = series;
175 176
176 177 // TODO: a dedicated data class for storing x and y values
177 178 QList<qreal> x;
178 179 QList<qreal> y;
179 180
181 QList<qreal> data0;
182 QList<qreal> data1;
183 QList<qreal> data2;
184 QList<qreal> data3;
185 QList<qreal> data4;
186
180 187 if (data == "linear") {
181 188 for (int i = 0; i < 20; i++) {
182 189 x.append(i);
183 190 y.append(i);
184 191 }
185 192 } else if (data == "linear, 1M") {
186 193 // 1 million data points from 0.0001 to 100
187 194 // TODO: What is the requirement? Should we be able to show this kind of data with
188 195 // reasonable performance, or can we expect the application developer to do "data mining"
189 196 // for us, so that the count of data points given to QtCommercial Chart is always
190 197 // reasonable?
191 198 for (qreal i = 0; i < 100; i += 0.0001) {
192 199 x.append(i);
193 200 y.append(20);
194 201 }
195 202 } else if (data == "SIN") {
196 203 for (int i = 0; i < 100; i++) {
197 204 x.append(i);
198 205 y.append(abs(sin(3.14159265358979 / 50 * i) * 100));
199 206 }
200 207 } else if (data == "SIN + random") {
201 208 for (qreal i = 0; i < 100; i += 0.1) {
202 209 x.append(i + (rand() % 5));
203 210 y.append(abs(sin(3.14159265358979 / 50 * i) * 100) + (rand() % 5));
204 211 }
212 } else if (data == "Table, 5 series"){
213 // Create some test data to chart
214 data0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10;
215 data1 << 5 << 0 << 0 << 4 << 0 << 7 << 8 << 9 << 9 << 0;
216 data2 << 3 << 5 << 8 << 13 << 8 << 5 << 3 << 2 << 1 << 1;
217 data3 << 5 << 6 << 7 << 3 << 4 << 5 << 8 << 9 << 10 << 5;
218 data4 << 9 << 7 << 5 << 3 << 1 << 2 << 4 << 6 << 8 << 10;
205 219 } else {
206 220 // TODO: check if data has a valid file name
207 221 Q_ASSERT(false);
208 222 }
209 223
210 224 // TODO: color of the series
211 225 QChartSeries *newSeries = 0;
212 226 if (series == "Scatter") {
213 227 newSeries = m_chartWidget->createSeries(QChartSeries::SeriesTypeScatter);
214 228 Q_ASSERT(newSeries->setData(x, y));
215 229 } else if (series == "Pie") {
216 230 newSeries = m_chartWidget->createSeries(QChartSeries::SeriesTypePie);
217 231 Q_ASSERT(newSeries->setData(y));
218 232 } else if (series == "Line") {
219 233 // TODO: adding data to an existing line series does not give any visuals for some reason
220 234 // newSeries = m_chartWidget->createSeries(QChartSeries::SeriesTypeLine);
221 235 // QXYChartSeries *lineSeries = static_cast<QXYChartSeries *>(newSeries);
222 236 // lineSeries->setColor(Qt::blue);
223 237 // for (int i(0); i < x.count() && i < y.count(); i++) {
224 238 // lineSeries->add(x.at(i), y.at(i));
225 239 // }
226 240 //Q_ASSERT(newSeries->setData(x, y));
227 241 QLineChartSeries* series0 = new QLineChartSeries();
228 242 for (int i(0); i < x.count() && i < y.count(); i++)
229 243 series0->add(x.at(i), y.at(i));
230 244 m_chartWidget->addSeries(series0);
231 245 newSeries = series0;
232 } else {
233 // TODO
234 }
235
236 // BarChart
237 if (series == "Bar") {
238 // This is the another way of creating series. Should we create test cases for both ways, if we support them?
246 } else if (series == "Bar") {
247 qDebug() << "Bar chart series";
248 BarChartSeries* series0 = new BarChartSeries(this);
249 series0->addData(data0);
250 series0->addData(data1);
251 series0->addData(data2);
252 series0->addData(data3);
253 series0->addData(data4);
254 m_chartWidget->addSeries(series0);
255 newSeries = series0;
256 } else if (series == "StackedBar") {
239 257 qDebug() << "Bar chart series";
240 258 StackedBarChartSeries* series0 = new StackedBarChartSeries(this);
241
242 // Create some test data to chart
243 QList<qreal> data0;
244 data0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10;
245 QList<qreal> data1;
246 data1 << 5 << 0 << 0 << 4 << 0 << 7 << 8 << 9 << 9 << 0;
247 QList<qreal> data2;
248 data2 << 3 << 5 << 8 << 13 << 8 << 5 << 3 << 2 << 1 << 1;
249 QList<qreal> data3;
250 data3 << 5 << 6 << 7 << 3 << 4 << 5 << 8 << 9 << 10 << 5;
251 QList<qreal> data4;
252 data4 << 9 << 7 << 5 << 3 << 1 << 2 << 4 << 6 << 8 << 10;
253
254 259 series0->addData(data0);
255 260 series0->addData(data1);
256 261 series0->addData(data2);
257 262 series0->addData(data3);
258 263 series0->addData(data4);
259
260 264 m_chartWidget->addSeries(series0);
261 265 newSeries = series0;
266 } else if (series == "PercentBar") {
267 qDebug() << "Bar chart series";
268 PercentBarChartSeries* series0 = new PercentBarChartSeries(this);
269 series0->addData(data0);
270 series0->addData(data1);
271 series0->addData(data2);
272 series0->addData(data3);
273 series0->addData(data4);
274 m_chartWidget->addSeries(series0);
275 newSeries = series0;
276 } else {
277 qDebug() << "Something weird going on in MainWidget::addSeries";
262 278 }
263 279
264 280 setCurrentSeries(newSeries);
265 281 }
266 282
267 283 void MainWidget::setCurrentSeries(QChartSeries *series)
268 284 {
269 285 m_currentSeries = series;
270 286 switch (m_currentSeries->type()) {
271 287 case QChartSeries::SeriesTypeLine:
272 288 break;
273 289 case QChartSeries::SeriesTypeScatter:
274 290 break;
275 291 case QChartSeries::SeriesTypePie:
276 292 break;
277 293 case QChartSeries::SeriesTypeBar:
278 294 qDebug() << "setCurrentSeries (bar)";
279 295 break;
296 case QChartSeries::SeriesTypeStackedBar:
297 qDebug() << "setCurrentSeries (Stackedbar)";
298 break;
299 case QChartSeries::SeriesTypePercentBar:
300 qDebug() << "setCurrentSeries (Percentbar)";
301 break;
280 302 default:
281 303 Q_ASSERT(false);
282 304 break;
283 305 }
284 306 }
285 307
286 308 void MainWidget::testDataChanged(int itemIndex)
287 309 {
288 310 qDebug() << "testDataChanged: " << itemIndex;
289 311
290 312 // switch (itemIndex) {
291 313 // case 0: {
292 314 // QList<QChartDataPoint> data;
293 315 // for (int x = 0; x < 20; x++) {
294 316 // data.append(QChartDataPoint() << x << x / 2);
295 317 // }
296 318 // m_chartWidget->setData(data);
297 319 // break;
298 320 // }
299 321 // case 1: {
300 322 // QList<QChartDataPoint> data;
301 323 // for (int x = 0; x < 100; x++) {
302 324 // data.append(QChartDataPoint() << x - 200 << 2 * (uint(sin(3.14159/50*x)*80) % 100));
303 325 // }
304 326 // m_chartWidget->setData(data);
305 327 // break;
306 328 // }
307 329 // case 2: {
308 330 // QList<QChartDataPoint> data;
309 331 // for (int x = 0; x < 1000; x++) {
310 332 // data.append(QChartDataPoint() << x - 200 << 2 * (uint(sin(3.14159/50*x)*80) % 100) + (rand() % 100 * 0.2));
311 333 // data.append(QChartDataPoint() << x - 200 << 2 * (uint(sin(3.14159/50*x)*80) % 100) + (rand() % 100 * 0.2));
312 334 // data.append(QChartDataPoint() << x - 200 << 2 * (uint(sin(3.14159/50*x)*80) % 100) + (rand() % 100 * 0.2));
313 335 // }
314 336 // m_chartWidget->setData(data);
315 337 // break;
316 338 // }
317 339 // default:
318 340 // break;
319 341 // }
320 342 }
321 343
322 344 void MainWidget::backgroundChanged(int itemIndex)
323 345 {
324 346 qDebug() << "backgroundChanged: " << itemIndex;
325 347 }
326 348
327 349 void MainWidget::autoScaleChanged(int value)
328 350 {
329 351 if (value) {
330 352 // TODO: enable auto scaling
331 353 } else {
332 354 // TODO: set scaling manually (and disable auto scaling)
333 355 }
334 356
335 357 m_xMinSpin->setEnabled(!value);
336 358 m_xMaxSpin->setEnabled(!value);
337 359 m_yMinSpin->setEnabled(!value);
338 360 m_yMaxSpin->setEnabled(!value);
339 361 }
340 362
341 363 void MainWidget::xMinChanged(int value)
342 364 {
343 365 qDebug() << "xMinChanged: " << value;
344 366 }
345 367
346 368 void MainWidget::xMaxChanged(int value)
347 369 {
348 370 qDebug() << "xMaxChanged: " << value;
349 371 }
350 372
351 373 void MainWidget::yMinChanged(int value)
352 374 {
353 375 qDebug() << "yMinChanged: " << value;
354 376 }
355 377
356 378 void MainWidget::yMaxChanged(int value)
357 379 {
358 380 qDebug() << "yMaxChanged: " << value;
359 381 }
360 382
361 383 void MainWidget::changeChartTheme(int themeIndex)
362 384 {
363 385 qDebug() << "changeChartTheme: " << themeIndex;
364 386 m_chartWidget->setChartTheme((QChart::ChartTheme) themeIndex);
365 387 }
366 388
367 389 void MainWidget::setPieSizeFactor(double size)
368 390 {
369 391 QPieSeries *pie = qobject_cast<QPieSeries *>(m_currentSeries);
370 392 if (pie)
371 393 pie->setSizeFactor(qreal(size));
372 394 }
373 395
374 396 void MainWidget::setPiePosition(int position)
375 397 {
376 398 QPieSeries *pie = qobject_cast<QPieSeries *>(m_currentSeries);
377 399 if (pie)
378 400 pie->setPosition((QPieSeries::PiePosition) position);
379 401 }
General Comments 0
You need to be logged in to leave comments. Login now