diff --git a/limereport/items/images/pie_chart2.png b/limereport/items/images/pie_chart2.png new file mode 100644 index 0000000..f4f788d Binary files /dev/null and b/limereport/items/images/pie_chart2.png differ diff --git a/limereport/items/items.qrc b/limereport/items/items.qrc index 86b8d74..44004cd 100644 --- a/limereport/items/items.qrc +++ b/limereport/items/items.qrc @@ -33,5 +33,6 @@ images/GroupFooter16.png images/GroupHeader16.png images/ReportPage16.png + images/pie_chart2.png diff --git a/limereport/items/lrchartitem.cpp b/limereport/items/lrchartitem.cpp new file mode 100644 index 0000000..28c2218 --- /dev/null +++ b/limereport/items/lrchartitem.cpp @@ -0,0 +1,1062 @@ +#include "lrchartitem.h" +#include +#include + +#include "lrdesignelementsfactory.h" +#include "lrchartitemeditor.h" +#include "lrdatasourcemanager.h" +#include "lrpagedesignintf.h" +#include "lrreportengine_p.h" +#include "lrdatadesignintf.h" + +namespace{ + +const QString xmlTag = "ChartItem"; + +LimeReport::BaseDesignIntf * createChartItem(QObject* owner, LimeReport::BaseDesignIntf* parent){ + return new LimeReport::ChartItem(owner,parent); +} +bool registred = LimeReport::DesignElementsFactory::instance().registerCreator( + xmlTag, LimeReport::ItemAttribs(QObject::tr("Chart Item"),"Item"), createChartItem + ); +} + +namespace LimeReport{ + +QColor generateColor() +{ + int red = (qrand()%(256 - 1)) + 1; + int green = (qrand()%(256 - 1)) + 1; + int blue = (qrand()%(256 - 1)) + 1;; + return QColor(red,green,blue); +} + +QColor color_map[39] = { + QColor(51,102,204), QColor(220,57,18), QColor(225, 153, 0), QColor(16, 150, 24), QColor(153,0,153), + QColor(0,153,198), QColor(221, 68, 119), + QColor(255,0,0), QColor(0,0,139), QColor(0,205,0), QColor(233,30,99), QColor(255,255,0), QColor(244,67,54), + QColor(156,39,176), QColor(103,58,183), QColor(63,81,181), QColor(33,153,243), + QColor(0,150,136), QColor(78,175,80), QColor(139,195,74), QColor(205,228,57), + QColor(0,139,0), QColor(0,0,255), QColor(255,235,59), QColor(255,193,7), + QColor(255,152,0), QColor(255,87,34), QColor(121,85,72), QColor(158,158,158), + QColor(96,125,139), QColor(241,153,185), QColor(64,64,64), + QColor(188,229,218), QColor(139,0,0), QColor(139,139,0), QColor(171, 130, 255), + QColor(139, 123, 139), QColor(255, 0, 255), QColor(139, 69, 19) + }; +//QColor color_map1[55] = { +// QColor(245,147,51), QColor(244,89,73), QColor(0,142,195), QColor(1,107,159), +// QColor(242,219,127), QColor(1,127,111), QColor(143,149,166), QColor(1,173,235), +// QColor(35,63,142), QColor(121,78,38), QColor(254,195,115), QColor(237,38,110), +// QColor(240,102,125), QColor(92,97,98), QColor(0,101,94), QColor(239,59,31), +// QColor(1,73,133), QColor(0,89,151), QColor(237,27,35), QColor(219,3,107), +// QColor(0,173,239), QColor(167,138,117), QColor(0,134,124), QColor(0,110,68), +// QColor(242,199,17), QColor(247,168,114), QColor(65,174,74), QColor(1,142,76), +// QColor(1,82,165), QColor(0,111,134), QColor(69,128,43), QColor(254,222,86), +// QColor(152,262,59), QColor(237,0,137), QColor(188,26,141), QColor(0,57,115), +// QColor(150,180,127), QColor(146,154,160), QColor(1,82,132), QColor(23,97,134), +// QColor(95,194,171), QColor(0,114,187), QColor(200,133,183), QColor(81,33,127), +// QColor(0,254,0), QColor(0,0,254), QColor(254,254,0), +// QColor(254,0,254),QColor(0,254,254), QColor(0,80,0), QColor(80,0,0), +// QColor(0,0,80), QColor(80,80,0), QColor(80,0,80), +// QColor(0,80,80), +//}; + +QString SeriesItem::name() const +{ + return m_name; +} + +void SeriesItem::setName(const QString &name) +{ + m_name = name; +} + +QString SeriesItem::valuesColumn() const +{ + return m_valuesColumn; +} + +void SeriesItem::setValuesColumn(const QString &valuesColumn) +{ + m_valuesColumn = valuesColumn; +} + +QString SeriesItem::labelsColumn() const +{ + return m_labelsColumn; +} + +void SeriesItem::setLabelsColumn(const QString &labelsColumn) +{ + m_labelsColumn = labelsColumn; +} + +SeriesItem *SeriesItem::clone() +{ + SeriesItem* result = new SeriesItem(); + result->setName(name()); + result->setLabelsColumn(labelsColumn()); + result->setValuesColumn(valuesColumn()); + result->setColor(color()); + return result; +} + +void SeriesItem::fillSeriesData(IDataSource *dataSource) +{ + if (dataSource){ + dataSource->first(); + int currentColorIndex = 0; + while(!dataSource->eof()){ + if (!m_labelsColumn.isEmpty()) + m_data.labels().append(dataSource->data(m_labelsColumn).toString()); + m_data.values().append(dataSource->data(m_valuesColumn).toDouble()); + m_data.colors().append((currentColorIndex<32)?color_map[currentColorIndex]:generateColor()); + dataSource->next(); + currentColorIndex++; + } + } +} + +QColor SeriesItem::color() const +{ + return m_color; +} + +void SeriesItem::setColor(const QColor &color) +{ + m_color = color; +} + +ChartItem::ChartItem(QObject *owner, QGraphicsItem *parent) + : ItemDesignIntf(xmlTag, owner, parent), m_legendBorder(true), + m_legendAlign(LegendAlignCenter), m_titleAlign(TitleAlignCenter), + m_chartType(Pie), m_labelsField("") +{ + m_labels<<"First"<<"Second"<<"Thrid"; + m_chart = new PieChart(this); +} + +ChartItem::~ChartItem() +{ + foreach (SeriesItem* series, m_series) { + delete series; + } + m_series.clear(); + delete m_chart; +} + +ChartItem::TitleAlign ChartItem::titleAlign() const +{ + return m_titleAlign; +} + +void ChartItem::setTitleAlign(const TitleAlign &titleAlign) +{ + if (m_titleAlign != titleAlign){ + TitleAlign oldValue = m_titleAlign; + m_titleAlign = titleAlign; + notify("titleAlign",oldValue,m_titleAlign); + update(); + } +} + +void ChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + painter->save(); + setupPainter(painter); + painter->setFont(transformToSceneFont(painter->font())); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setRenderHint(QPainter::TextAntialiasing,true); + qreal borderMargin = (rect().height()*0.01>10)?(10):(rect().height()*0.01); + qreal maxTitleHeight = rect().height()*0.2; + + QFont tmpFont = painter->font(); + + qreal titleOffset = !m_title.isEmpty()?(((painter->fontMetrics().height()+borderMargin*2)fontMetrics().height()+borderMargin*2): + (maxTitleHeight)):0; + + QRectF titleRect = QRectF(borderMargin,borderMargin,rect().width()-borderMargin*2,titleOffset); + QRectF legendRect = m_chart->calcChartLegendRect(painter->font(), rect(), false, borderMargin, titleOffset); + QRectF diagramRect = rect().adjusted(borderMargin,titleOffset+borderMargin, + -(legendRect.width()+borderMargin*2),-borderMargin); + + paintChartTitle(painter, titleRect); + m_chart->paintChartLegend(painter,legendRect); + m_chart->paintChart(painter,diagramRect); + + painter->restore(); + ItemDesignIntf::paint(painter,option,widget); +} + +BaseDesignIntf *ChartItem::createSameTypeItem(QObject *owner, QGraphicsItem *parent) +{ + ChartItem* result = new ChartItem(owner,parent); + foreach (SeriesItem* series, m_series) { + result->m_series.append(series->clone()); + } + return result; +} + +QObject *ChartItem::createElement(const QString &collectionName, const QString &elementType) +{ + Q_UNUSED(elementType); + if (collectionName.compare("series")==0){ + SeriesItem* seriesItem = new SeriesItem(); + m_series.append(seriesItem); + return seriesItem; + } + return 0; +} + +int ChartItem::elementsCount(const QString &collectionName) +{ + if (collectionName.compare("series")==0) + return m_series.count(); + return 0; +} + +QObject *ChartItem::elementAt(const QString &collectionName, int index) +{ + if (collectionName.compare("series")==0) + return m_series.at(index); + return 0; +} + +void ChartItem::updateItemSize(DataSourceManager *dataManager, RenderPass , int ) +{ + if (dataManager && dataManager->dataSource(m_datasource)){ + IDataSource* ds = dataManager->dataSource(m_datasource); + foreach (SeriesItem* series, m_series) { + series->fillSeriesData(ds); + } + fillLabels(ds); + } +} + +void ChartItem::fillLabels(IDataSource *dataSource) +{ + m_labels.clear(); + if (dataSource && !m_labelsField.isEmpty()){ + dataSource->first(); + while(!dataSource->eof()){ + m_labels.append(dataSource->data(m_labelsField).toString()); + dataSource->next(); + } + } +} + +QWidget *ChartItem::defaultEditor() +{ + QSettings* l_settings = (page()->settings() != 0) ? + page()->settings() : + (page()->reportEditor()!=0) ? page()->reportEditor()->settings() : 0; + QWidget* editor = new ChartItemEditor(this,page(),l_settings); + editor->setAttribute(Qt::WA_DeleteOnClose); + return editor; +} + +QList ChartItem::labels() const +{ + return m_labels; +} + +void ChartItem::setLabels(const QList &labels) +{ + m_labels = labels; +} + +QString ChartItem::labelsField() const +{ + return m_labelsField; +} + +void ChartItem::setLabelsField(const QString &labelsField) +{ + m_labelsField = labelsField; +} + +ChartItem::ChartType ChartItem::chartType() const +{ + return m_chartType; +} + +void ChartItem::setChartType(const ChartType &chartType) +{ + if (m_chartType != chartType){ + ChartType oldValue = m_chartType; + m_chartType = chartType; + delete m_chart; + switch (m_chartType) { + case Pie: + m_chart = new PieChart(this); + break; + case VerticalBar: + m_chart = new VerticalBarChart(this); + break; + case HorizontalBar: + m_chart = new HorizontalBarChart(this); + break; + } + notify("chartType",oldValue,m_chartType); + update(); + } +} + +QString ChartItem::datasource() const +{ + return m_datasource; +} + +void ChartItem::setDatasource(const QString &datasource) +{ + m_datasource = datasource; +} + +void ChartItem::paintChartTitle(QPainter *painter, QRectF titleRect) +{ + painter->save(); + QFont tmpFont = painter->font(); + QFontMetrics fm(tmpFont); + while ((fm.height()>titleRect.height() || fm.width(m_title)>titleRect.width()) + && tmpFont.pixelSize()>1) { + tmpFont.setPixelSize(tmpFont.pixelSize()-1); + fm = QFontMetrics(tmpFont); + } + painter->setFont(tmpFont); + Qt::AlignmentFlag align = Qt::AlignCenter; + switch (m_titleAlign) { + case TitleAlignLeft: + align = Qt::AlignLeft; + break; + case TitleAlignCenter: + align = Qt::AlignCenter; + break; + case TitleAlignRight: + align = Qt::AlignRight; + break; + } + painter->drawText(titleRect, align, m_title); + painter->restore(); +} + + +ChartItem::LegendAlign ChartItem::legendAlign() const +{ + return m_legendAlign; +} + +void ChartItem::setLegendAlign(const LegendAlign &legendAlign) +{ + if (m_legendAlign != legendAlign){ + LegendAlign oldValue = m_legendAlign; + m_legendAlign = legendAlign; + notify("legendAlign",oldValue,m_legendAlign); + update(); + } +} + +bool ChartItem::drawLegendBorder() const +{ + return m_legendBorder; +} + +void ChartItem::setDrawLegendBorder(bool legendBorder) +{ + if (m_legendBorder!=legendBorder){ + m_legendBorder = legendBorder; + notify("legendBorder",!m_legendBorder,m_legendBorder); + update(); + } +} + +QString ChartItem::chartTitle() const +{ + return m_title; +} + +void ChartItem::setChartTitle(const QString &title) +{ + if (m_title != title){ + QString oldValue = m_title; + m_title = title; + update(); + notify("chartTitle",oldValue,title); + } +} + +QList &ChartItem::series() +{ + return m_series; +} + +void ChartItem::setSeries(const QList &series) +{ + m_series = series; +} + +bool ChartItem::isSeriesExists(const QString &name) +{ + foreach (SeriesItem* series, m_series) { + if (series->name().compare(name)==0) return true; + } + return false; +} + +AbstractChart::AbstractChart(ChartItem *chartItem) + :m_chartItem(chartItem) +{ + m_designLabels<legendAlign()) { + case ChartItem::LegendAlignTop: + legendTopMargin = titleOffset+borderMargin; + legendBottomMargin = parentRect.height()-(legendSize.height()+titleOffset); + break; + case ChartItem::LegendAlignCenter: + legendTopMargin = titleOffset+(parentRect.height()-titleOffset-legendSize.height())/2; + legendBottomMargin = (parentRect.height()-titleOffset-legendSize.height())/2; + break; + case ChartItem::LegendAlignBottom: + legendTopMargin = parentRect.height()-(legendSize.height()+titleOffset); + legendBottomMargin = borderMargin; + break; + } + + qreal rightOffset = !takeAllRect?((legendSize.width()>parentRect.width()/2-borderMargin)? + (parentRect.width()/2): + (parentRect.width()-legendSize.width())):0; + + QRectF legendRect = parentRect.adjusted( + rightOffset, + (legendSize.height()>(parentRect.height()-titleOffset))?(titleOffset):(legendTopMargin), + -borderMargin, + (legendSize.height()>(parentRect.height()-titleOffset))?(0):(-legendBottomMargin) + ); + + return legendRect; +} + +void AbstractChart::prepareLegendToPaint(QRectF &legendRect, QPainter *painter) +{ + QFont tmpFont = painter->font(); + QSizeF legendSize = calcChartLegendSize(tmpFont); + + if ((legendSize.height()>legendRect.height() || legendSize.width()>legendRect.width())){ + while ( (legendSize.height()>legendRect.height() || legendSize.width()>legendRect.width()) + && tmpFont.pixelSize()>1) + { + tmpFont.setPixelSize(tmpFont.pixelSize()-1); + painter->setFont(tmpFont); + legendSize = calcChartLegendSize(tmpFont); + } + painter->setFont(tmpFont); + legendRect = calcChartLegendRect(tmpFont, legendRect, true, 0, 0); + } +} + +void PieChart::drawPercent(QPainter *painter, QRectF chartRect, qreal startAngle, qreal angle) +{ + painter->save(); + + QPointF center(chartRect.left()+chartRect.width()/2,chartRect.top()+chartRect.height()/2); + qreal percent = angle/3.6; + qreal radAngle = qDegreesToRadians(angle/2+startAngle); + qreal radius = painter->fontMetrics().width("99,9%"); + qreal border = chartRect.height()*0.02; + qreal length = (chartRect.height())/2-(radius/2+border); + qreal x,y; + x = length*qCos(radAngle); + y = length*qSin(radAngle); + QPointF endPoint(center.x()+x,center.y()-y); + painter->setPen(Qt::white); + QRectF textRect(endPoint.x()-(radius/2),endPoint.y()-(radius/2),radius,radius); + + qreal arcLength = 3.14 * length * angle / 180; + if (arcLength >= radius) + painter->drawText(textRect,Qt::AlignCenter,QString::number(percent,'f',1)+"%"); + painter->restore(); + +} + +void PieChart::paintChart(QPainter *painter, QRectF chartRect) +{ + painter->save(); + QPen pen(Qt::white); + pen.setWidthF(2); + painter->setPen(pen); + + QBrush brush(Qt::transparent); + painter->setBrush(brush); + painter->setBackground(QBrush(Qt::NoBrush)); + + QRectF tmpRect = chartRect; + if (chartRect.height()>chartRect.width()){ + tmpRect.setHeight(chartRect.width()); + tmpRect.adjust(0,(chartRect.bottom()-tmpRect.bottom())/2, + 0,(chartRect.bottom()-tmpRect.bottom())/2); + } else { + tmpRect.setWidth(chartRect.height()); + } + + chartRect = tmpRect; + painter->drawRect(chartRect); + + if (!m_chartItem->series().isEmpty()&&!m_chartItem->series().at(0)->data()->values().isEmpty()){ + SeriesItem* si = m_chartItem->series().at(0); + qreal sum = 0; + foreach(qreal value, si->data()->values()){ + sum+=value; + } + qreal onePercent = sum / 100; + qreal currentDegree = 0; + int currentColor = 0; + for(int i=0; idata()->values().count();++i){ + qreal value = si->data()->values().at(i); + qreal sectorDegree = (value/onePercent)*3.6; + painter->setBrush(si->data()->colors().at(i)); + painter->drawPie(chartRect,currentDegree*16,sectorDegree*16); + drawPercent(painter, chartRect, currentDegree, sectorDegree); + currentDegree += sectorDegree; + currentColor++; + } + } else { + painter->setBrush(color_map[0]); + painter->drawPie(chartRect,0,260*16); + drawPercent(painter, chartRect, 0, 260); + painter->setBrush(color_map[1]); + painter->drawPie(chartRect,260*16,40*16); + drawPercent(painter, chartRect, 260, 40); + painter->setBrush(color_map[2]); + painter->drawPie(chartRect,300*16,60*16); + drawPercent(painter, chartRect, 300, 60); + } + + pen.setWidthF(1); + pen.setColor(Qt::gray); + painter->setPen(pen); + painter->setBrush(Qt::NoBrush); + painter->drawEllipse(chartRect); + painter->restore(); +} + +void PieChart::paintChartLegend(QPainter *painter, QRectF legendRect) +{ + prepareLegendToPaint(legendRect, painter); + + int indicatorSize = painter->fontMetrics().height()/2; + painter->setRenderHint(QPainter::Antialiasing,false); + + if (m_chartItem->drawLegendBorder()) + painter->drawRect(legendRect); + + painter->setRenderHint(QPainter::Antialiasing,true); + QRectF indicatorsRect = legendRect.adjusted(painter->fontMetrics().height()/2,painter->fontMetrics().height()/2,0,0); + + if (!m_chartItem->series().isEmpty() && !m_chartItem->series().at(0)->data()->labels().isEmpty()){ + qreal cw = 0; + SeriesItem* si = m_chartItem->series().at(0); + for (int i=0;idata()->labels().count();++i){ + QString label = si->data()->labels().at(i); + painter->setPen(Qt::black); + painter->drawText(indicatorsRect.adjusted(indicatorSize+indicatorSize/2,cw,0,0),label); + painter->setPen(si->data()->colors().at(i)); + painter->setBrush(si->data()->colors().at(i)); + painter->drawEllipse( + indicatorsRect.adjusted( + 0, + cw+indicatorSize/2, + -(indicatorsRect.width()-indicatorSize), + -(indicatorsRect.height()-(cw+indicatorSize+indicatorSize/2)) + ) + ); + cw += painter->fontMetrics().height(); + } + } else { + qreal cw = 0; + for (int i=0;isetPen(Qt::black); + painter->drawText(indicatorsRect.adjusted(indicatorSize+indicatorSize/2,cw,0,0),label); + painter->setBrush(color_map[i]); + painter->setPen(color_map[i]); + painter->drawEllipse( + indicatorsRect.adjusted( + 0, + cw+indicatorSize/2, + -(indicatorsRect.width()-indicatorSize), + -(indicatorsRect.height()-(cw+indicatorSize+indicatorSize/2)) + ) + ); + cw += painter->fontMetrics().height(); + } + + } +} + +QSizeF PieChart::calcChartLegendSize(const QFont &font) +{ + QFontMetrics fm(font); + + qreal cw = 0; + qreal maxWidth = 0; + + if (!m_chartItem->series().isEmpty() && !m_chartItem->series().at(0)->data()->labels().isEmpty()){ + SeriesItem* si = m_chartItem->series().at(0); + foreach(QString label, si->data()->labels()){ + cw += fm.height(); + if (maxWidthfontMetrics().width(QString::number(delta))+4; +} + +qreal VerticalBarChart::valuesVMargin(QPainter *painter) +{ + return painter->fontMetrics().height(); +} + +QRectF VerticalBarChart::labelsRect(QPainter *painter, QRectF labelsRect) +{ + qreal maxWidth = 0; + + foreach (QString label, m_chartItem->labels()) { + if (painter->fontMetrics().width(label)>maxWidth) + maxWidth = painter->fontMetrics().width(label); + } + + if (maxWidth+vPadding(m_chartItem->rect())> labelsRect.height()) + return labelsRect; + else + return labelsRect.adjusted(0,(labelsRect.height()-(maxWidth+vPadding(m_chartItem->rect()))),0,0); +} + +void VerticalBarChart::paintChart(QPainter *painter, QRectF chartRect) +{ + QRectF calcRect = labelsRect(painter, chartRect.adjusted( + hPadding(chartRect)*2+valuesHMargin(painter), + chartRect.height()*0.5, + -(hPadding(chartRect)*2), + -vPadding(chartRect) + )); + + qreal barsShift = calcRect.height(); + paintVerticalGrid(painter, chartRect.adjusted( + hPadding(chartRect), + vPadding(chartRect)+valuesVMargin(painter), + -hPadding(chartRect),-(vPadding(chartRect)+barsShift) )); + + paintVerticalBars(painter, chartRect.adjusted( + hPadding(chartRect)*2+valuesHMargin(painter), + vPadding(chartRect)+valuesVMargin(painter), + -(hPadding(chartRect)*2), + -(vPadding(chartRect)+barsShift) )); + paintLabels(painter,calcRect); +} + + +void VerticalBarChart::paintVerticalGrid(QPainter *painter, QRectF gridRect) +{ + int delta = int(maxValue()-minValue()); + delta = genNextValue(delta); + + painter->setRenderHint(QPainter::Antialiasing,false); + qreal vStep = gridRect.height() / 4; + + for (int i=0;i<5;i++){ + painter->drawText(QRectF(gridRect.bottomLeft()-QPointF(0,vStep*i+painter->fontMetrics().height()), + QSizeF(valuesHMargin(painter),painter->fontMetrics().height())), + QString::number(minValue()+i*delta/4)); + painter->drawLine(gridRect.bottomLeft()-QPointF(-valuesHMargin(painter),vStep*i), + gridRect.bottomRight()-QPointF(0,vStep*i)); + } + + painter->setRenderHint(QPainter::Antialiasing,true); +} + + + +void VerticalBarChart::paintVerticalBars(QPainter *painter, QRectF barsRect) +{ + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,false); + int delta = int(maxValue()-minValue()); + delta = genNextValue(delta); + + qreal vStep = barsRect.height() / delta; + qreal hStep = (barsRect.width() / valuesCount()) / seriesCount(); + qreal topShift = (delta - (maxValue()-minValue())) * vStep +barsRect.top(); + + if (!m_chartItem->series().isEmpty() && !m_chartItem->series().at(0)->data()->labels().isEmpty()){ + int curSeries = 0; + foreach (SeriesItem* series, m_chartItem->series()) { + qreal curHOffset = curSeries*hStep+barsRect.left(); + painter->setBrush(series->color()); + foreach (qreal value, series->data()->values()) { + painter->drawRect(QRectF(curHOffset, maxValue()*vStep+topShift, hStep, -value*vStep)); + curHOffset+=hStep*seriesCount(); + } + curSeries++; + } + } else { + qreal curHOffset = barsRect.left(); + int curColor = 0; + for (int i=0; i<9; ++i){ + if (curColor==3) curColor=0; + painter->setBrush(color_map[curColor]); + painter->drawRect(QRectF(curHOffset, maxValue()*vStep+barsRect.top(), hStep, -designValues()[i]*vStep)); + curHOffset+=hStep; + curColor++; + } + } + painter->restore(); +} + + + +void VerticalBarChart::paintLabels(QPainter *painter, QRectF labelsRect) +{ + painter->save(); + qreal hStep = (labelsRect.width() / valuesCount()); + int curLabel = 0; + + if (!m_chartItem->labels().isEmpty()){ + painter->rotate(270); + painter->translate(-(labelsRect.top()+labelsRect.height()),labelsRect.left()); + foreach (QString label, m_chartItem->labels()) { + painter->drawText(QRectF(QPoint(0,0), + QSize(labelsRect.height()-4,hStep)),Qt::AlignVCenter|Qt::AlignRight,label); + curLabel++; + painter->translate(0,hStep); + } + painter->rotate(-270); + } + painter->restore(); +} + +AbstractSeriesChart::AbstractSeriesChart(ChartItem *chartItem) + :AbstractChart(chartItem) +{ + m_designValues[0] = 10; + m_designValues[1] = 35; + m_designValues[2] = 15; + m_designValues[3] = 5; + m_designValues[4] = 20; + m_designValues[5] = 10; + m_designValues[6] = 40; + m_designValues[7] = 20; + m_designValues[8] = 5; +} + +qreal AbstractSeriesChart::maxValue() +{ + if (m_chartItem->itemMode()==DesignMode) return 40; + qreal maxValue = 0; + foreach(SeriesItem* series, m_chartItem->series()){ + foreach(qreal value, series->data()->values()){ + if (value>maxValue) maxValue=value; + } + } + return maxValue; +} + +qreal AbstractSeriesChart::minValue() +{ + if (m_chartItem->itemMode()==DesignMode) return 0; + qreal minValue = 0; + foreach(SeriesItem* series, m_chartItem->series()){ + foreach(qreal value, series->data()->values()){ + if (valueitemMode()==DesignMode) return 3; + return (m_chartItem->series().isEmpty())?(0):(m_chartItem->series().at(0)->data()->labels().count()); +} + +int AbstractSeriesChart::seriesCount() +{ + if (m_chartItem->itemMode()==DesignMode) return 3; + return m_chartItem->series().count(); +} + +QSizeF AbstractSeriesChart::calcChartLegendSize(const QFont &font) +{ + QFontMetrics fm(font); + + qreal cw = 0; + qreal maxWidth = 0; + + if (!m_chartItem->series().isEmpty()){ + foreach(SeriesItem* series, m_chartItem->series()){ + cw += fm.height(); + if (maxWidthname())) + maxWidth = fm.width(series->name())+10; + } + } else { + foreach(QString label, m_designLabels){ + cw += fm.height(); + if (maxWidthfontMetrics().width(QString::number(delta))+4; +} + +qreal HorizontalBarChart::valuesVMargin(QPainter *painter) +{ + return painter->fontMetrics().height(); +} + +void HorizontalBarChart::paintChart(QPainter *painter, QRectF chartRect) +{ + QRectF calcRect = labelsRect(painter, chartRect.adjusted( + hPadding(chartRect), + vPadding(chartRect)*2, + -(chartRect.width()*0.5), + -(vPadding(chartRect)*2+valuesVMargin(painter)) + )); + + qreal barsShift = calcRect.width(); + + paintHorizontalGrid(painter, chartRect.adjusted( + hPadding(chartRect)+barsShift, + vPadding(chartRect), + -(hPadding(chartRect)),-vPadding(chartRect))); + paintHorizontalBars(painter, chartRect.adjusted( + hPadding(chartRect)+barsShift, + vPadding(chartRect)*2, + -(hPadding(chartRect)), + -(vPadding(chartRect)*2) )); + + paintLabels(painter,calcRect); +} + +void HorizontalBarChart::paintHorizontalGrid(QPainter *painter, QRectF gridRect) +{ + painter->save(); + int delta = int(maxValue()-minValue()); + delta = genNextValue(delta); + + painter->setRenderHint(QPainter::Antialiasing,false); + qreal hStep = (gridRect.width()-painter->fontMetrics().width(QString::number(maxValue()))) / 4; + + painter->setFont(adaptValuesFont(hStep-4,painter->font())); + + for (int i=0;i<5;i++){ + painter->drawText(QRectF(gridRect.left()+4+hStep*i,gridRect.bottom()-painter->fontMetrics().height(), + hStep,painter->fontMetrics().height()), + QString::number(minValue()+i*delta/4)); + painter->drawLine( gridRect.left()+hStep*i, gridRect.bottom(), + gridRect.left()+hStep*i, gridRect.top()); + + } + painter->restore(); +} + +void HorizontalBarChart::paintHorizontalBars(QPainter *painter, QRectF barsRect) +{ + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,false); + int delta = int(maxValue()-minValue()); + delta = genNextValue(delta); + + qreal vStep = (barsRect.height()-painter->fontMetrics().height()) / valuesCount() / seriesCount(); + qreal hStep = (barsRect.width()-painter->fontMetrics().width(QString::number(maxValue()))) / delta; + + if (!m_chartItem->series().isEmpty() && !m_chartItem->series().at(0)->data()->labels().isEmpty()){ + int curSeries = 0; + foreach (SeriesItem* series, m_chartItem->series()) { + qreal curVOffset = curSeries*vStep+barsRect.top(); + painter->setBrush(series->color()); + foreach (qreal value, series->data()->values()) { + painter->drawRect(QRectF((-minValue()*hStep)+barsRect.left(), curVOffset, value*hStep, vStep)); + curVOffset+=vStep*seriesCount(); + } + curSeries++; + } + } else { + qreal curVOffset = barsRect.top(); + int curColor = 0; + for (int i=0; i<9; ++i){ + if (curColor==3) curColor=0; + painter->setBrush(color_map[curColor]); + painter->drawRect(QRectF(barsRect.left(), curVOffset, designValues()[i]*hStep, vStep)); + curVOffset+=vStep; + curColor++; + } + } + painter->restore(); +} + +QRectF HorizontalBarChart::labelsRect(QPainter *painter, QRectF labelsRect) +{ + qreal maxWidth = 0; + + foreach (QString label, m_chartItem->labels()) { + if (painter->fontMetrics().width(label)>maxWidth) + maxWidth = painter->fontMetrics().width(label); + } + + if (maxWidth+hPadding(m_chartItem->rect())*2> labelsRect.width()) + return labelsRect; + else + return labelsRect.adjusted(0,0,-(labelsRect.width()-(maxWidth+hPadding(m_chartItem->rect())*2)),0); +} + +QFont HorizontalBarChart::adaptLabelsFont(QRectF rect, QFont font) +{ + QString maxWord; + QFontMetrics fm(font); + + foreach(QString label, m_chartItem->labels()){ + foreach (QString currentWord, label.split(QRegExp("\\W+"))){ + if (fm.width(maxWord)rect.width() && tmpFont.pixelSize()>1){ + tmpFont.setPixelSize(tmpFont.pixelSize()-1); + QFontMetricsF tmpFM(tmpFont); + curWidth = tmpFM.width(maxWord); + } + return tmpFont; +} + +QFont HorizontalBarChart::adaptValuesFont(qreal width, QFont font) +{ + QString strValue = QString::number(maxValue()); + QFont tmpFont = font; + QScopedPointer fm(new QFontMetricsF(tmpFont)); + qreal curWidth = fm->width(strValue); + while (curWidth>width && tmpFont.pixelSize()>1){ + tmpFont.setPixelSize(tmpFont.pixelSize()-1); + fm.reset(new QFontMetricsF(tmpFont)); + curWidth = fm->width(strValue); + } + return tmpFont; +} + +void HorizontalBarChart::paintLabels(QPainter *painter, QRectF labelsRect) +{ + painter->save(); + painter->setFont(adaptLabelsFont(labelsRect.adjusted(0,0,-hPadding(m_chartItem->rect()),0), + painter->font())); + qreal vStep = (labelsRect.height() / valuesCount()); + int curLabel = 0; + + painter->translate(labelsRect.topLeft()); + if (!m_chartItem->labels().isEmpty()){ + foreach (QString label, m_chartItem->labels()) { + painter->drawText(QRectF(QPoint(0,vStep*curLabel), + QSize(labelsRect.width()-hPadding(m_chartItem->rect()),vStep)), + Qt::AlignVCenter | Qt::AlignRight | Qt::TextWordWrap,label); + + curLabel++; + } + } + painter->restore(); +} + +qreal AbstractBarChart::hPadding(QRectF chartRect) +{ + return (chartRect.width()*0.02); +} + +qreal AbstractBarChart::vPadding(QRectF chartRect) +{ + return (chartRect.height()*0.02); +} + +void AbstractBarChart::paintChartLegend(QPainter *painter, QRectF legendRect) +{ + prepareLegendToPaint(legendRect, painter); + int indicatorSize = painter->fontMetrics().height()/2; + painter->setPen(Qt::black); + painter->setRenderHint(QPainter::Antialiasing,false); + if (m_chartItem->drawLegendBorder()) + painter->drawRect(legendRect); + painter->setRenderHint(QPainter::Antialiasing,true); + QRectF indicatorsRect = legendRect.adjusted(painter->fontMetrics().height()/2,painter->fontMetrics().height()/2,0,0); + + if (!m_chartItem->series().isEmpty()){ + qreal cw = 0; + foreach(SeriesItem* series, m_chartItem->series()){ + QString label = series->name(); + painter->drawText(indicatorsRect.adjusted(indicatorSize+indicatorSize/2,cw,0,0),label); + painter->setBrush(series->color()); + painter->drawEllipse( + indicatorsRect.adjusted( + 0, + cw+indicatorSize/2, + -(indicatorsRect.width()-indicatorSize), + -(indicatorsRect.height()-(cw+indicatorSize+indicatorSize/2)) + ) + ); + cw += painter->fontMetrics().height(); + } + } else { + qreal cw = 0; + for (int i=0;idrawText(indicatorsRect.adjusted(indicatorSize+indicatorSize/2,cw,0,0),label); + painter->setBrush(color_map[i]); + painter->drawEllipse( + indicatorsRect.adjusted( + 0, + cw+indicatorSize/2, + -(indicatorsRect.width()-indicatorSize), + -(indicatorsRect.height()-(cw+indicatorSize+indicatorSize/2)) + ) + ); + cw += painter->fontMetrics().height(); + } + + } +} + +} // namespace LimeReport diff --git a/limereport/items/lrchartitem.h b/limereport/items/lrchartitem.h new file mode 100644 index 0000000..c89ea76 --- /dev/null +++ b/limereport/items/lrchartitem.h @@ -0,0 +1,208 @@ +#ifndef LRCHARTITEM_H +#define LRCHARTITEM_H +#include "lritemdesignintf.h" + +namespace LimeReport{ + +QColor generateColor(); +extern QColor color_map[39]; + +class IDataSource; + +class SeriesItemData : public QObject{ + Q_OBJECT +public: + QList& values(){ return m_values;} + QList& labels(){ return m_labels;} + QList& colors() { return m_colors;} +private: + QList m_values; + QList m_labels; + QList m_colors; +}; + +class SeriesItem : public QObject{ + Q_OBJECT + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QString valuesColumn READ valuesColumn WRITE setValuesColumn ) + Q_PROPERTY(QString labelsColumn READ labelsColumn WRITE setLabelsColumn ) + Q_PROPERTY(QColor color READ color WRITE setColor) +public: + SeriesItem(QObject* parent = 0):QObject(parent){} + QString name() const; + void setName(const QString &name); + QString valuesColumn() const; + void setValuesColumn(const QString &valuesColumn); + QString labelsColumn() const; + void setLabelsColumn(const QString &labelsColumn); + SeriesItem* clone(); + void fillSeriesData(IDataSource* dataSource); + SeriesItemData* data(){ return &m_data;} + QColor color() const; + void setColor(const QColor &color); +private: + QString m_name; + QString m_valuesColumn; + QString m_labelsColumn; + SeriesItemData m_data; + QColor m_color; +}; + +class ChartItem; + +class AbstractChart { +public: + AbstractChart(ChartItem* chartItem); + virtual ~AbstractChart(){} + virtual void paintChart(QPainter *painter, QRectF rect) = 0; + virtual void paintChartLegend(QPainter *painter, QRectF legendRect) =0; + virtual QSizeF calcChartLegendSize(const QFont &font) = 0; + virtual QRectF calcChartLegendRect(const QFont& font, const QRectF& parentRect, bool takeAllRect, qreal borderMargin, qreal titleOffset); +protected: + virtual void prepareLegendToPaint(QRectF& legendRect, QPainter *painter); +protected: + ChartItem* m_chartItem; + QList m_designLabels; +}; + +class AbstractSeriesChart: public AbstractChart{ +public: + AbstractSeriesChart(ChartItem* chartItem); +protected: + qreal maxValue(); + qreal minValue(); + int valuesCount(); + int seriesCount(); + QSizeF calcChartLegendSize(const QFont &font); + qreal* designValues(){ return m_designValues;} +private: + qreal m_designValues [9]; +}; + +class PieChart : public AbstractChart{ +public: + PieChart(ChartItem* chartItem):AbstractChart(chartItem){} + QSizeF calcChartLegendSize(const QFont &font); + void paintChart(QPainter *painter, QRectF chartRect); + void paintChartLegend(QPainter *painter, QRectF legendRect); +protected: + void drawPercent(QPainter *painter, QRectF chartRect, qreal startAngle, qreal angle); +}; + +class AbstractBarChart: public AbstractSeriesChart{ +public: + AbstractBarChart(ChartItem* chartItem):AbstractSeriesChart(chartItem){} + qreal hPadding(QRectF chartRect); + qreal vPadding(QRectF chartRect); + void paintChartLegend(QPainter *painter, QRectF legendRect); +}; + +class HorizontalBarChart: public AbstractBarChart{ +public: + HorizontalBarChart(ChartItem* chartItem):AbstractBarChart(chartItem){} + qreal valuesHMargin(QPainter *painter); + qreal valuesVMargin(QPainter *painter); + void paintChart(QPainter *painter, QRectF chartRect); + void paintHorizontalGrid(QPainter *painter, QRectF gridRect); + void paintHorizontalBars(QPainter *painter, QRectF barsRect); + QRectF labelsRect(QPainter* painter, QRectF labelsRect); + void paintLabels(QPainter *painter, QRectF labelsRect); +protected: + QFont adaptLabelsFont(QRectF rect, QFont font); + QFont adaptValuesFont(qreal width, QFont font); +}; + +class VerticalBarChart: public AbstractBarChart{ +public: + VerticalBarChart(ChartItem* chartItem):AbstractBarChart(chartItem){} + qreal valuesHMargin(QPainter *painter); + qreal valuesVMargin(QPainter *painter); + QRectF labelsRect(QPainter* painter, QRectF labelsRect); + void paintChart(QPainter *painter, QRectF chartRect); + void paintVerticalGrid(QPainter *painter, QRectF gridRect); + void paintVerticalBars(QPainter *painter, QRectF barsRect); + void paintLabels(QPainter *painter, QRectF labelsRect); +}; + +class ChartItem : public LimeReport::ItemDesignIntf +{ + Q_OBJECT + Q_ENUMS(LegendAlign) + Q_ENUMS(TitleAlign) + Q_ENUMS(ChartType) + Q_PROPERTY(ACollectionProperty series READ fakeCollectionReader) + Q_PROPERTY(QString datasource READ datasource WRITE setDatasource) + Q_PROPERTY(QString chartTitle READ chartTitle WRITE setChartTitle) + Q_PROPERTY(bool drawLegendBorder READ drawLegendBorder WRITE setDrawLegendBorder) + Q_PROPERTY(LegendAlign legendAlign READ legendAlign WRITE setLegendAlign) + Q_PROPERTY(TitleAlign titleAlign READ titleAlign WRITE setTitleAlign) + Q_PROPERTY(ChartType chartType READ chartType WRITE setChartType) + Q_PROPERTY(QString labelsField READ labelsField WRITE setLabelsField) + friend class AbstractChart; +public: + + enum LegendAlign{LegendAlignTop,LegendAlignCenter,LegendAlignBottom}; + enum TitleAlign{TitleAlignLeft, TitleAlignCenter, TitleAlignRight}; + enum ChartType{Pie, VerticalBar, HorizontalBar}; + + ChartItem(QObject* owner, QGraphicsItem* parent); + ~ChartItem(); + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + + QList &series(); + void setSeries(const QList &series); + bool isSeriesExists(const QString& name); + + QString datasource() const; + void setDatasource(const QString &datasource); + + QString chartTitle() const; + void setChartTitle(const QString &chartTitle); + + bool drawLegendBorder() const; + void setDrawLegendBorder(bool drawLegendBorder); + + LegendAlign legendAlign() const; + void setLegendAlign(const LegendAlign &legendAlign); + + TitleAlign titleAlign() const; + void setTitleAlign(const TitleAlign &titleAlign); + + ChartType chartType() const; + void setChartType(const ChartType &chartType); + + QString labelsField() const; + void setLabelsField(const QString &labelsField); + + QList labels() const; + void setLabels(const QList &labels); + +protected: + void paintChartTitle(QPainter* painter, QRectF titleRect); + virtual BaseDesignIntf* createSameTypeItem(QObject *owner, QGraphicsItem *parent); + //ICollectionContainer + QObject* createElement(const QString& collectionName,const QString& elementType); + int elementsCount(const QString& collectionName); + QObject* elementAt(const QString& collectionName,int index); + void collectionLoadFinished(const QString& collectionName){Q_UNUSED(collectionName)} + void updateItemSize(DataSourceManager *dataManager, RenderPass, int); + void fillLabels(IDataSource* dataSource); + QWidget* defaultEditor(); + +private: + QList m_series; +// QList< QPointer > m_series; + QString m_datasource; + QPixmap m_chartImage; + QString m_title; + AbstractChart* m_chart; + bool m_legendBorder; + LegendAlign m_legendAlign; + TitleAlign m_titleAlign; + ChartType m_chartType; + QString m_labelsField; + QList m_labels; +}; + +} //namespace LimeReport +#endif // LRCHARTITEM_H diff --git a/limereport/items/lrchartitemeditor.cpp b/limereport/items/lrchartitemeditor.cpp new file mode 100644 index 0000000..cfb9761 --- /dev/null +++ b/limereport/items/lrchartitemeditor.cpp @@ -0,0 +1,249 @@ +#include "lrchartitemeditor.h" +#include "ui_lrchartitemeditor.h" +#include "lrchartitem.h" +#include "lrpagedesignintf.h" +#include + +ChartItemEditor::ChartItemEditor(LimeReport::ChartItem *item, LimeReport::PageDesignIntf *page, QSettings *settings, QWidget *parent): + QWidget(parent), ui(new Ui::ChartItemEditor), m_charItem(item), m_page(page), + m_settings(settings), m_ownedSettings(false), m_isReadingSetting(false) +{ + ui->setupUi(this); + QHBoxLayout* colorLayout = new QHBoxLayout(); + colorLayout->setMargin(0); + m_colorButton = new QToolButton(); + m_colorButton->setText("..."); + m_colorButton->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum); + m_colorIndicator = new ColorIndicator(); + m_colorIndicator->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum); + ui->colorWidget->setLayout(colorLayout); + colorLayout->addWidget(m_colorIndicator); + colorLayout->addWidget(m_colorButton); + colorLayout->insertStretch(0); + readSetting(); + init(); + + connect(m_colorButton, SIGNAL(clicked(bool)), this, SLOT(slotChangeSeriesColor())); +} + +ChartItemEditor::~ChartItemEditor() +{ +#ifdef Q_OS_WIN + writeSetting(); +#endif +#ifdef Q_OS_MAC + writeSetting(); +#endif + delete ui; +} + +QSettings* ChartItemEditor::settings() +{ + if (m_settings){ + return m_settings; + } else { + m_settings = new QSettings("LimeReport",QApplication::applicationName()); + m_ownedSettings = true; + return m_settings; + } +} + +void ChartItemEditor::readSetting() +{ + if (settings()==0) return; + + m_isReadingSetting = true; + + settings()->beginGroup("ChartItemEditor"); + QVariant v = settings()->value("Geometry"); + if (v.isValid()){ + restoreGeometry(v.toByteArray()); + } + v = settings()->value("State"); + if (v.isValid()){ + ui->splitter->restoreState(v.toByteArray()); + } + + settings()->endGroup(); + + m_isReadingSetting = false; +} + +void ChartItemEditor::writeSetting() +{ + if (settings()!=0){ + settings()->beginGroup("ChartItemEditor"); + settings()->setValue("Geometry",saveGeometry()); + settings()->setValue("State",ui->splitter->saveState()); + settings()->endGroup(); + } +} + +void ChartItemEditor::rebuildTable() +{ + ui->tableWidget->clearContents(); + ui->tableWidget->setRowCount(m_charItem->series().count()); + for( int i=0;iseries().count();++i){ + QTableWidgetItem* newRow = new QTableWidgetItem(m_charItem->series().at(i)->name()); + ui->tableWidget->setItem(i,0,newRow); + } +} + +void ChartItemEditor::init() +{ + m_initing = true; + + ui->tableWidget->setColumnCount(1); + ui->tableWidget->setRowCount(m_charItem->series().count()); + ui->tableWidget->horizontalHeader()->setStretchLastSection(true); + ui->tableWidget->setHorizontalHeaderItem(0,new QTableWidgetItem("Series name")); + + rebuildTable(); + + if (!m_charItem->datasource().isEmpty()){ + if (m_page && m_page->datasourceManager()){ + LimeReport::IDataSource* ds = m_page->datasourceManager()->dataSource(m_charItem->datasource()); + if (ds){ + for (int i=0;icolumnCount();++i){ + ui->valuesFieldComboBox->addItem(ds->columnNameByIndex(i)); + ui->labelsFieldComboBox->addItem(ds->columnNameByIndex(i)); + } + } + } + + } + ui->labelsFieldComboBox->setCurrentText(m_charItem->labelsField()); + if (!m_charItem->series().isEmpty()){ + enableSeriesEditor(); + ui->tableWidget->selectRow(0); + } else { + disableSeriesEditor(); + } + + m_initing = false; +} + +void ChartItemEditor::enableSeriesEditor() +{ + ui->seriesNameLineEdit->setEnabled(true); + ui->valuesFieldComboBox->setEnabled(true); + m_colorButton->setEnabled(true); + m_colorIndicator->setEnabled(true); +} + +void ChartItemEditor::disableSeriesEditor() +{ + ui->seriesNameLineEdit->setText(""); + ui->seriesNameLineEdit->setDisabled(true); + ui->valuesFieldComboBox->setDisabled(true); + m_colorButton->setDisabled(true); + m_colorIndicator->setDisabled(true); + ui->valuesFieldComboBox->setCurrentText(""); +} + +LimeReport::SeriesItem *ChartItemEditor::currentSeries() +{ + int curRow = ui->tableWidget->currentRow(); + if ((curRow>-1) && !m_charItem->series().isEmpty() && m_charItem->series().count()>curRow){ + return m_charItem->series().at(curRow); + } + return 0; +} + +void ChartItemEditor::resizeEvent(QResizeEvent *) +{ +#ifdef Q_OS_UNIX + writeSetting(); +#endif +} + +void ChartItemEditor::moveEvent(QMoveEvent *) +{ +#ifdef Q_OS_UNIX + writeSetting(); +#endif +} + +void ChartItemEditor::on_splitter_splitterMoved(int , int ) +{ +#ifdef Q_OS_UNIX + writeSetting(); +#endif +} + + +void ChartItemEditor::on_pbOk_clicked() +{ + close(); +} + +void ChartItemEditor::slotAddSeries() +{ + LimeReport::SeriesItem* series = new LimeReport::SeriesItem(); + int curSeriesNumber = m_charItem->series().count(); + while (m_charItem->isSeriesExists("Series"+QString::number(curSeriesNumber))) curSeriesNumber++; + series->setName("Series"+QString::number(curSeriesNumber)); + series->setValuesColumn(""); + series->setLabelsColumn(""); + series->setColor((m_charItem->series().count()<32)?LimeReport::color_map[m_charItem->series().count()]:LimeReport::generateColor()); + m_charItem->series().append(series); + ui->tableWidget->setRowCount(m_charItem->series().count()); + ui->tableWidget->setItem(m_charItem->series().count()-1, 0, new QTableWidgetItem(series->name())); + ui->tableWidget->selectRow(m_charItem->series().count()-1); + ui->valuesFieldComboBox->setCurrentText(""); +} + +void ChartItemEditor::slotDeleteSeries() +{ + QList itemsToRemove; + foreach(QModelIndex index,ui->tableWidget->selectionModel()->selectedRows()){ + itemsToRemove.append(m_charItem->series().at(index.row())); + }; + foreach (LimeReport::SeriesItem* series, itemsToRemove){ + m_charItem->series().removeOne(series); + delete series; + } + rebuildTable(); + disableSeriesEditor(); +} + +void ChartItemEditor::on_tableWidget_itemSelectionChanged() +{ + if (ui->tableWidget->selectionModel()->hasSelection()){ + LimeReport::SeriesItem* series = m_charItem->series().at(ui->tableWidget->selectionModel()->currentIndex().row()); + ui->seriesNameLineEdit->setText(series->name()); + ui->valuesFieldComboBox->setCurrentText(series->valuesColumn()); + m_colorIndicator->setColor(series->color()); + enableSeriesEditor(); + } +} + +void ChartItemEditor::on_seriesNameLineEdit_textChanged(const QString &arg1) +{ + if (currentSeries()){ + currentSeries()->setName(arg1); + ui->tableWidget->currentItem()->setText(arg1); + } +} + +void ChartItemEditor::on_valuesFieldComboBox_currentTextChanged(const QString &arg1) +{ + if (currentSeries()){ + currentSeries()->setValuesColumn(arg1); + } +} + +void ChartItemEditor::on_labelsFieldComboBox_currentTextChanged(const QString &arg1) +{ + if (!m_initing) + m_charItem->setLabelsField(arg1); +} + +void ChartItemEditor::slotChangeSeriesColor() +{ + QColorDialog colorDialog; + if (colorDialog.exec()){ + currentSeries()->setColor(colorDialog.selectedColor()); + m_colorIndicator->setColor(colorDialog.selectedColor()); + } +} diff --git a/limereport/items/lrchartitemeditor.h b/limereport/items/lrchartitemeditor.h new file mode 100644 index 0000000..4e3d699 --- /dev/null +++ b/limereport/items/lrchartitemeditor.h @@ -0,0 +1,57 @@ +#ifndef CHARITEMEDITOR_H +#define CHARITEMEDITOR_H + +#include +#include "lrchartitem.h" +#include "lrcolorindicator.h" +#include +#include + +namespace Ui { +class ChartItemEditor; +} + +class ChartItemEditor : public QWidget +{ + Q_OBJECT +public: + ChartItemEditor(LimeReport::ChartItem* item, LimeReport::PageDesignIntf* page, + QSettings* settings=0, QWidget *parent = 0); + ~ChartItemEditor(); +public: + QSettings *settings(); + void rebuildTable(); + +protected: + void resizeEvent(QResizeEvent *); + void moveEvent(QMoveEvent *); +private slots: + void on_splitter_splitterMoved(int, int); + void on_pbOk_clicked(); + void slotAddSeries(); + void slotDeleteSeries(); + void on_tableWidget_itemSelectionChanged(); + void on_seriesNameLineEdit_textChanged(const QString &arg1); + void on_valuesFieldComboBox_currentTextChanged(const QString &arg1); + void on_labelsFieldComboBox_currentTextChanged(const QString &arg1); + void slotChangeSeriesColor(); +private: + void readSetting(); + void writeSetting(); + void init(); + void enableSeriesEditor(); + void disableSeriesEditor(); + LimeReport::SeriesItem* currentSeries(); +private: + Ui::ChartItemEditor *ui; + LimeReport::ChartItem* m_charItem; + LimeReport::PageDesignIntf* m_page; + QSettings* m_settings; + bool m_ownedSettings; + bool m_isReadingSetting; + QToolButton* m_colorButton; + ColorIndicator* m_colorIndicator; + bool m_initing; +}; + +#endif // CHARITEMEDITOR_H diff --git a/limereport/items/lrchartitemeditor.ui b/limereport/items/lrchartitemeditor.ui new file mode 100644 index 0000000..8e21a59 --- /dev/null +++ b/limereport/items/lrchartitemeditor.ui @@ -0,0 +1,223 @@ + + + ChartItemEditor + + + + 0 + 0 + 380 + 268 + + + + Form + + + + + + + 0 + 0 + + + + Series + + + + + + Qt::Horizontal + + + + + 4 + + + + + + + + + + Add + + + + + + + Delete + + + + + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + 4 + + + 2 + + + 2 + + + 2 + + + + + Name + + + + + + + + + + Values field + + + + + + + true + + + + + + + Color + + + + + + + + + + + + + + + + + + 16777215 + 10 + + + + QFrame::HLine + + + + + + + + + + + + Labels field + + + + + + + true + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Ok + + + + + + + + + + + + + pbAddSeries + clicked() + ChartItemEditor + slotAddSeries() + + + 57 + 136 + + + 8 + 75 + + + + + pbDeleteSeries + clicked() + ChartItemEditor + slotDeleteSeries() + + + 142 + 136 + + + 372 + 137 + + + + + + slotAddSeries() + slotDeleteSeries() + + diff --git a/limereport/limereport.pri b/limereport/limereport.pri index f7efc40..613ea8e 100644 --- a/limereport/limereport.pri +++ b/limereport/limereport.pri @@ -89,7 +89,10 @@ SOURCES += \ $$REPORT_PATH/lrsimplecrypt.cpp \ $$REPORT_PATH/lraboutdialog.cpp \ $$REPORT_PATH/lrsettingdialog.cpp \ - $$REPORT_PATH/scriptbrowser/lrscriptbrowser.cpp + $$REPORT_PATH/scriptbrowser/lrscriptbrowser.cpp \ + $$REPORT_PATH/lrcolorindicator.cpp \ + $$REPORT_PATH/items/lrchartitem.cpp \ + $$REPORT_PATH/items/lrchartitemeditor.cpp contains(CONFIG, zint){ SOURCES += $$REPORT_PATH/items/lrbarcodeitem.cpp @@ -188,8 +191,11 @@ HEADERS += \ $$REPORT_PATH/lrcallbackdatasourceintf.h \ $$REPORT_PATH/lrsettingdialog.h \ $$REPORT_PATH/lrpreviewreportwidget_p.h \ - $$REPORT_PATH/scriptbrowser/lrscriptbrowser.h - + $$REPORT_PATH/scriptbrowser/lrscriptbrowser.h \ + $$REPORT_PATH/lrcolorindicator.h \ + $$REPORT_PATH/items/lrchartitem.h \ + $$REPORT_PATH/items/lrchartitemeditor.h + contains(CONFIG,zint){ HEADERS += $$REPORT_PATH/items/lrbarcodeitem.h } @@ -206,6 +212,7 @@ FORMS += \ $$REPORT_PATH/lraboutdialog.ui \ $$REPORT_PATH/lrsettingdialog.ui \ $$REPORT_PATH/scriptbrowser/lrscriptbrowser.ui \ + $$REPORT_PATH/items/lrchartitemeditor.ui RESOURCES += \ diff --git a/limereport/lrcolorindicator.cpp b/limereport/lrcolorindicator.cpp new file mode 100644 index 0000000..73662f1 --- /dev/null +++ b/limereport/lrcolorindicator.cpp @@ -0,0 +1,38 @@ +#include "lrcolorindicator.h" +#include + +void ColorIndicator::paintEvent(QPaintEvent* event) +{ + QPainter painter(this); + painter.save(); + painter.setBrush(m_color); + painter.setPen(Qt::gray); + QRect rect = event->rect().adjusted(3,3,-4,-4); + rect.setWidth(rect.height()); + painter.setRenderHint(QPainter::Antialiasing); + painter.drawEllipse(rect); + painter.restore(); +} + +ColorIndicator::ColorIndicator(QWidget *parent) + :QWidget(parent), m_color(Qt::white){ + setAttribute(Qt::WA_StaticContents); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + setFocusPolicy(Qt::NoFocus); +} + +QColor ColorIndicator::color() const +{ + return m_color; +} + +void ColorIndicator::setColor(const QColor &color) +{ + m_color = color; + update(); +} + +QSize ColorIndicator::sizeHint() const +{ + return QSize(20,20); +} diff --git a/limereport/lrcolorindicator.h b/limereport/lrcolorindicator.h new file mode 100644 index 0000000..5ed1754 --- /dev/null +++ b/limereport/lrcolorindicator.h @@ -0,0 +1,20 @@ +#ifndef COLORINDICATOR_H +#define COLORINDICATOR_H + +#include +#include + +class ColorIndicator : public QWidget{ + Q_OBJECT +public: + ColorIndicator(QWidget* parent = 0); + QColor color() const; + void setColor(const QColor &color); + QSize sizeHint() const; +protected: + void paintEvent(QPaintEvent *event); +private: + QColor m_color; +}; + +#endif // COLORINDICATOR_H