diff --git a/examples/examples.pro b/examples/examples.pro index cacdadf..d7fa2bc 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -20,4 +20,5 @@ SUBDIRS += \ stackedbarchartdrilldown \ zoomlinechart \ modeldata \ - groupedbarchart + groupedbarchart \ + legend diff --git a/examples/legend/legend.pro b/examples/legend/legend.pro new file mode 100644 index 0000000..b731c14 --- /dev/null +++ b/examples/legend/legend.pro @@ -0,0 +1,12 @@ +!include( ../examples.pri ) { + error( "Couldn't find the examples.pri file!" ) +} + +TARGET = legend +SOURCES += main.cpp \ + mainwidget.cpp + +!system_build:mac: QMAKE_POST_LINK += "$$MAC_POST_LINK_PREFIX $$MAC_EXAMPLES_BIN_DIR" + +HEADERS += \ + mainwidget.h diff --git a/examples/legend/main.cpp b/examples/legend/main.cpp new file mode 100644 index 0000000..c9e057d --- /dev/null +++ b/examples/legend/main.cpp @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwidget.h" + +#include +#include +#include +#include +#include +#include + +QTCOMMERCIALCHART_USE_NAMESPACE + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + MainWidget w; + w.resize(1024,768); + w.show(); + + return a.exec(); +} diff --git a/examples/legend/mainwidget.cpp b/examples/legend/mainwidget.cpp new file mode 100644 index 0000000..d09c8eb --- /dev/null +++ b/examples/legend/mainwidget.cpp @@ -0,0 +1,134 @@ +#include "mainwidget.h" +#include +#include +#include +#include +#include +#include +#include +#include + +QTCOMMERCIALCHART_USE_NAMESPACE + +MainWidget::MainWidget(QWidget *parent) : + QWidget(parent) +{ + m_setCount = 0; + m_chart = new QChart(); + + m_buttonLayout = new QGridLayout(); + QPushButton *detachLegendButton = new QPushButton("detach legend"); + connect(detachLegendButton, SIGNAL(clicked()), this, SLOT(detachLegend())); + m_buttonLayout->addWidget(detachLegendButton, 0, 0); + QPushButton *attachLegendButton = new QPushButton("attach legend"); + connect(attachLegendButton, SIGNAL(clicked()), this, SLOT(attachLegend())); + m_buttonLayout->addWidget(attachLegendButton, 1, 0); + + QPushButton *addSetButton = new QPushButton("add barset"); + connect(addSetButton, SIGNAL(clicked()), this, SLOT(addBarset())); + m_buttonLayout->addWidget(addSetButton, 2, 0); + QPushButton *removeBarsetButton = new QPushButton("remove barset"); + connect(removeBarsetButton, SIGNAL(clicked()), this, SLOT(removeBarset())); + m_buttonLayout->addWidget(removeBarsetButton, 3, 0); + + // add row with empty label to make all the other rows static + m_buttonLayout->addWidget(new QLabel(""), m_buttonLayout->rowCount(), 0); + m_buttonLayout->setRowStretch(m_buttonLayout->rowCount() - 1, 1); + + // Create chart view with the chart + m_chartView = new QChartView(m_chart, this); + m_chartView->setRubberBand(QChartView::HorizonalRubberBand); + + m_customView = new QGraphicsView(this); + m_customScene = new QGraphicsScene(this); + m_customView->setScene(m_customScene); + + // Create layout for grid and detached legend + m_mainLayout = new QGridLayout(); + m_mainLayout->addLayout(m_buttonLayout, 0, 0); + m_mainLayout->addWidget(m_chartView, 0, 1, 3, 1); + m_mainLayout->addWidget(m_customView, 0, 2, 3, 1); + setLayout(m_mainLayout); + + createSeries(); +} + +void MainWidget::createSeries() +{ +//![1] + m_series = new QBarSeries(); + + addBarset(); + addBarset(); + addBarset(); + addBarset(); +//![1] + +//![2] + m_chart->addSeries(m_series); + m_chart->setTitle("Legend detach example"); +//![2] + +//![3] + m_chart->legend()->setVisible(true); + m_chart->legend()->setAlignment(QLegend::AlignmentBottom); + m_chart->axisY()->setNiceNumbersEnabled(true); +//![3] + +//![4] + m_chartView->setRenderHint(QPainter::Antialiasing); +//![4] +} + +void MainWidget::attachLegend() +{ + qDebug() << "attach legend"; + QLegend *legend = m_chart->legend(); + + if (m_customScene->items().contains(legend)) { + qDebug() << "legend removed from other scene"; + m_customScene->removeItem(legend); + legend->setParent(m_chart); + legend->attachToChart(); + } + +// legend->attachToChart(); + // This causes redraw + QSize size(1,1); + this->resize(this->size() + size); + this->resize(this->size() - size); +} + +void MainWidget::detachLegend() +{ + qDebug() << "detach legend"; + QLegend *legend = m_chart->legend(); + legend->detachFromChart(); + + m_customScene->addItem(legend); +// m_mainLayout->addWidget(legend,0,2,3,1); +// setLayout(m_layout); + + // TODO: layout legend to somewhere else + // This causes redraw + QSize size(1,1); + this->resize(this->size() + size); + this->resize(this->size() - size); +} + +void MainWidget::addBarset() +{ + QBarSet *barSet = new QBarSet(QString("set ") + QString::number(m_setCount)); + m_setCount++; + qreal delta = m_series->barsetCount() * 0.1; + *barSet << QPointF(0.0 + delta, 1 + delta) << QPointF(1.0 + delta, 2 + delta) << QPointF(2.0 + delta, 3 + delta) << QPointF(3.0 + delta, 4 + delta); + m_series->append(barSet); +} + +void MainWidget::removeBarset() +{ + QList sets = m_series->barSets(); + if (sets.count() > 0) { + m_series->remove(sets.at(sets.count()-1)); + } +} diff --git a/examples/legend/mainwidget.h b/examples/legend/mainwidget.h new file mode 100644 index 0000000..5e7e59c --- /dev/null +++ b/examples/legend/mainwidget.h @@ -0,0 +1,49 @@ +#ifndef MAINWIDGET_H +#define MAINWIDGET_H + +#include "qchartglobal.h" +#include "qchart.h" +#include "qchartview.h" +#include +#include +#include +#include + +QTCOMMERCIALCHART_USE_NAMESPACE + +class MainWidget : public QWidget +//class MainWidget : public QGraphicsWidget +{ + Q_OBJECT +public: + explicit MainWidget(QWidget *parent = 0); + + void createSeries(); + +signals: + +public slots: + void attachLegend(); + void detachLegend(); + void addBarset(); + void removeBarset(); + +private: + + QChart *m_chart; + QBarSeries *m_series; + + QGraphicsScene *m_scene; + QChartView *m_chartView; + QGridLayout *m_mainLayout; + QGridLayout *m_buttonLayout; + + QGraphicsView *m_customView; + QGraphicsScene *m_customScene; + QGraphicsGridLayout *m_customLayout; + + + int m_setCount; +}; + +#endif // MAINWIDGET_H diff --git a/src/barchart/qbarseries.cpp b/src/barchart/qbarseries.cpp index cbe574b..34c342c 100644 --- a/src/barchart/qbarseries.cpp +++ b/src/barchart/qbarseries.cpp @@ -75,7 +75,10 @@ QBarSeries::QBarSeries(QObject *parent) : */ QBarSeries::~QBarSeries() { - // NOTE: d_ptr destroyed by QObject + Q_D(QBarSeries); + if(d->m_dataset){ + d->m_dataset->removeSeries(this); + } } /*! @@ -112,14 +115,7 @@ void QBarSeries::setCategories(QBarCategories categories) bool QBarSeries::append(QBarSet *set) { Q_D(QBarSeries); - if ((d->m_barSets.contains(set)) || (set == 0)) { - // Fail if set is already in list or set is null. - return false; - } - d->m_barSets.append(set); - QObject::connect(set->d_ptr.data(), SIGNAL(updatedBars()), d, SLOT(barsetChanged())); - emit d->restructuredBars(); - return true; + return d->append(set); } /*! @@ -129,14 +125,7 @@ bool QBarSeries::append(QBarSet *set) bool QBarSeries::remove(QBarSet *set) { Q_D(QBarSeries); - if (!d->m_barSets.contains(set)) { - // Fail if set is not in list - return false; - } - d->m_barSets.removeOne(set); - QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedBars()), d, SLOT(barsetChanged())); - emit d->restructuredBars(); - return true; + return d->remove(set); } /*! @@ -148,23 +137,7 @@ bool QBarSeries::remove(QBarSet *set) bool QBarSeries::append(QList sets) { Q_D(QBarSeries); - foreach (QBarSet* set, sets) { - if ((set == 0) || (d->m_barSets.contains(set))) { - // Fail if any of the sets is null or is already appended. - return false; - } - if (sets.count(set) != 1) { - // Also fail if same set is more than once in given list. - return false; - } - } - - foreach (QBarSet* set, sets) { - d->m_barSets.append(set); - QObject::connect(set->d_ptr.data(), SIGNAL(updatedBars()), d, SLOT(barsetChanged())); - } - emit d->restructuredBars(); - return true; + return d->append(sets); } /*! @@ -173,20 +146,7 @@ bool QBarSeries::append(QList sets) bool QBarSeries::remove(QList sets) { Q_D(QBarSeries); - - bool setsRemoved = false; - foreach (QBarSet* set, sets) { - if (d->m_barSets.contains(set)) { - d->m_barSets.removeOne(set); - QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedBars()), d, SLOT(barsetChanged())); - setsRemoved = true; - } - } - - if (setsRemoved) { - emit d->restructuredBars(); - } - return setsRemoved; + return d->remove(sets); } /*! @@ -454,7 +414,7 @@ void QBarSeriesPrivate::scaleDomain(Domain& domain) qreal y = max(); minX = qMin(minX, x) - 0.5; minY = qMin(minY, y); - maxX = qMax(maxX, x) - 0.5; + maxX = qMax(maxX, x) + 0.5; maxY = qMax(maxY, y); tickXCount = x+1; @@ -486,6 +446,84 @@ QList QBarSeriesPrivate::createLegendMarker(QLegend* legend) return markers; } +bool QBarSeriesPrivate::append(QBarSet *set) +{ + Q_Q(QBarSeries); + if ((m_barSets.contains(set)) || (set == 0)) { + // Fail if set is already in list or set is null. + return false; + } + m_barSets.append(set); + QObject::connect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SLOT(barsetChanged())); + if (m_dataset) { + m_dataset->updateSeries(q); // this notifies legend + } + emit restructuredBars(); // this notifies barchartitem + return true; +} + +bool QBarSeriesPrivate::remove(QBarSet *set) +{ + Q_Q(QBarSeries); + if (!m_barSets.contains(set)) { + // Fail if set is not in list + return false; + } + m_barSets.removeOne(set); + QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SLOT(barsetChanged())); + if (m_dataset) { + m_dataset->updateSeries(q); // this notifies legend + } + emit restructuredBars(); // this notifies barchartitem + return true; +} + +bool QBarSeriesPrivate::append(QList sets) +{ + Q_Q(QBarSeries); + foreach (QBarSet* set, sets) { + if ((set == 0) || (m_barSets.contains(set))) { + // Fail if any of the sets is null or is already appended. + return false; + } + if (sets.count(set) != 1) { + // Also fail if same set is more than once in given list. + return false; + } + } + + foreach (QBarSet* set, sets) { + m_barSets.append(set); + QObject::connect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SLOT(barsetChanged())); + } + if (m_dataset) { + m_dataset->updateSeries(q); // this notifies legend + } + emit restructuredBars(); // this notifies barchartitem + return true; +} + +bool QBarSeriesPrivate::remove(QList sets) +{ + Q_Q(QBarSeries); + bool setsRemoved = false; + foreach (QBarSet* set, sets) { + if (m_barSets.contains(set)) { + m_barSets.removeOne(set); + QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SLOT(barsetChanged())); + setsRemoved = true; + } + } + + if (setsRemoved) { + if (m_dataset) { + m_dataset->updateSeries(q); // this notifies legend + } + emit restructuredBars(); // this notifies barchartitem + } + return setsRemoved; +} + #include "moc_qbarseries.cpp" #include "moc_qbarseries_p.cpp" diff --git a/src/barchart/qbarseries_p.h b/src/barchart/qbarseries_p.h index 817b24c..4d260c3 100644 --- a/src/barchart/qbarseries_p.h +++ b/src/barchart/qbarseries_p.h @@ -57,6 +57,11 @@ public: Chart* createGraphics(ChartPresenter* presenter); QList createLegendMarker(QLegend* legend); + bool append(QBarSet *set); + bool remove(QBarSet *set); + bool append(QList sets); + bool remove(QList sets); + QBarSet* barsetAt(int index); QString categoryName(int category); qreal min(); diff --git a/src/chartdataset.cpp b/src/chartdataset.cpp index c1c0acc..69ad18e 100644 --- a/src/chartdataset.cpp +++ b/src/chartdataset.cpp @@ -286,6 +286,11 @@ QList ChartDataSet::series() const return m_seriesAxisMap.keys(); } +void ChartDataSet::updateSeries(QAbstractSeries *series) +{ + emit seriesUpdated(series); +} + #include "moc_chartdataset_p.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/chartdataset_p.h b/src/chartdataset_p.h index e7c6f69..bf2210c 100644 --- a/src/chartdataset_p.h +++ b/src/chartdataset_p.h @@ -49,6 +49,7 @@ public: void addSeries(QAbstractSeries* series,QAxis *axisY = 0); QAxis* removeSeries(QAbstractSeries* series); void removeAllSeries(); + void updateSeries(QAbstractSeries* series); void zoomInDomain(const QRectF& rect, const QSizeF& size); void zoomOutDomain(const QRectF& rect, const QSizeF& size); @@ -68,6 +69,7 @@ public: Q_SIGNALS: void seriesAdded(QAbstractSeries* series, Domain* domain); void seriesRemoved(QAbstractSeries* series); + void seriesUpdated(QAbstractSeries* series); void axisAdded(QAxis* axis,Domain* domain); void axisRemoved(QAxis* axis); diff --git a/src/legend/qlegend.cpp b/src/legend/qlegend.cpp index 033e0c8..9f8b247 100644 --- a/src/legend/qlegend.cpp +++ b/src/legend/qlegend.cpp @@ -93,6 +93,7 @@ d_ptr(new QLegendPrivate(chart->d_ptr->m_presenter,this)) setFlags(QGraphicsItem::ItemClipsChildrenToShape); QObject::connect(chart->d_ptr->m_dataset,SIGNAL(seriesAdded(QAbstractSeries*,Domain*)),d_ptr.data(),SLOT(handleSeriesAdded(QAbstractSeries*,Domain*))); QObject::connect(chart->d_ptr->m_dataset,SIGNAL(seriesRemoved(QAbstractSeries*)),d_ptr.data(),SLOT(handleSeriesRemoved(QAbstractSeries*))); + QObject::connect(chart->d_ptr->m_dataset,SIGNAL(seriesUpdated(QAbstractSeries*)),d_ptr.data(),SLOT(handleSeriesUpdated(QAbstractSeries*))); } /*! @@ -444,6 +445,15 @@ void QLegendPrivate::handleSeriesRemoved(QAbstractSeries *series) updateLayout(); } +void QLegendPrivate::handleSeriesUpdated(QAbstractSeries *series) +{ + // TODO: find out which markers are are added or removed. Update them + // TODO: better implementation + handleSeriesRemoved(series); + Domain domain; + handleSeriesAdded(series, &domain); +} + void QLegendPrivate::handleUpdatePieSeries() { //TODO: reimplement to be optimal diff --git a/src/legend/qlegend_p.h b/src/legend/qlegend_p.h index faa83af..c2e6453 100644 --- a/src/legend/qlegend_p.h +++ b/src/legend/qlegend_p.h @@ -50,6 +50,7 @@ public: public Q_SLOTS: void handleSeriesAdded(QAbstractSeries *series, Domain *domain); void handleSeriesRemoved(QAbstractSeries *series); + void handleSeriesUpdated(QAbstractSeries *series); void handleUpdatePieSeries(); //TODO remove this function private: