Files
3rdparty
demo_r1
demo_r2
designer
docs
include
limereport
bands
base
databrowser
dialogdesigner
images
items
editors
images
items.qrc
lralignpropitem.cpp
lralignpropitem.h
lrbarcodeitem.cpp
lrbarcodeitem.h
lrchartitem.cpp
lrchartitem.h
lrchartitemeditor.cpp
lrchartitemeditor.h
lrchartitemeditor.ui
lrhorizontallayout.cpp
lrhorizontallayout.h
lrimageitem.cpp
lrimageitem.h
lrshapeitem.cpp
lrshapeitem.h
lrsimpletagparser.cpp
lrsimpletagparser.h
lrsubitemparentpropitem.cpp
lrsubitemparentpropitem.h
lrtextitem.cpp
lrtextitem.h
lrtextitemeditor.cpp
lrtextitemeditor.h
lrtextitemeditor.ui
objectinspector
objectsbrowser
scriptbrowser
serializators
translationeditor
LRCallbackDS
LRDataManager
LRScriptManager
LimeReport
limereport.pri
limereport.pro
lraboutdialog.cpp
lraboutdialog.h
lraboutdialog.ui
lrbanddesignintf.cpp
lrbanddesignintf.h
lrbandsmanager.cpp
lrbandsmanager.h
lrbasedesignintf.cpp
lrbasedesignintf.h
lrcallbackdatasourceintf.h
lrcollection.h
lrcolorindicator.cpp
lrcolorindicator.h
lrdatadesignintf.cpp
lrdatadesignintf.h
lrdatasourcemanager.cpp
lrdatasourcemanager.h
lrdatasourcemanagerintf.h
lrdesignelementsfactory.h
lrfactoryinitializer.cpp
lrfactoryinitializer.h
lrglobal.cpp
lrglobal.h
lrgraphicsviewzoom.cpp
lrgraphicsviewzoom.h
lrgroupfunctions.cpp
lrgroupfunctions.h
lritemdesignintf.cpp
lritemdesignintf.h
lritemscontainerdesignitf.cpp
lritemscontainerdesignitf.h
lrpagedesignintf.cpp
lrpagedesignintf.h
lrpageinitintf.h
lrpageitemdesignintf.cpp
lrpageitemdesignintf.h
lrpreviewreportwidget.cpp
lrpreviewreportwidget.h
lrpreviewreportwidget.ui
lrpreviewreportwidget_p.h
lrpreviewreportwindow.cpp
lrpreviewreportwindow.h
lrpreviewreportwindow.ui
lrreportdesignwidget.cpp
lrreportdesignwidget.h
lrreportdesignwindow.cpp
lrreportdesignwindow.h
lrreportengine.cpp
lrreportengine.h
lrreportengine_p.h
lrreportrender.cpp
lrreportrender.h
lrreporttranslation.cpp
lrreporttranslation.h
lrscriptenginemanager.cpp
lrscriptenginemanager.h
lrscriptenginemanagerintf.h
lrsettingdialog.cpp
lrsettingdialog.h
lrsettingdialog.ui
lrsimplecrypt.cpp
lrsimplecrypt.h
lrvariablesholder.cpp
lrvariablesholder.h
report.qrc
translations
.gitignore
.travis.yml
COPYING
LICENSE
README.md
common.pri
followTo.patch
limereport.pri
limereport.pro
qzint.pri
LimeReport/limereport/items/lrchartitem.cpp
2017-07-13 14:39:07 +03:00

1047 lines
33 KiB
C++

#include "lrchartitem.h"
#include <QStyleOptionGraphicsItem>
#include <QPainter>
#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)
};
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)<maxTitleHeight)?
(painter->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->setLabelsColumn(m_labelsField);
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<QString> ChartItem::labels() const
{
return m_labels;
}
void ChartItem::setLabels(const QList<QString> &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<SeriesItem *> &ChartItem::series()
{
return m_series;
}
void ChartItem::setSeries(const QList<SeriesItem *> &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<<QObject::tr("First")<<QObject::tr("Second")<<QObject::tr("Thrid");
}
QRectF AbstractChart::calcChartLegendRect(const QFont &font, const QRectF &parentRect, bool takeAllRect, qreal borderMargin, qreal titleOffset)
{
QSizeF legendSize = calcChartLegendSize(font);
qreal legendTopMargin = 0;
qreal legendBottomMargin = 0;
switch (m_chartItem->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; i<si->data()->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;i<si->data()->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;i<m_designLabels.size();++i){
QString label = m_designLabels.at(i);
painter->setPen(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 (maxWidth<fm.width(label))
maxWidth = fm.width(label)+10;
}
} else {
foreach(QString label, m_designLabels){
cw += fm.height();
if (maxWidth<fm.width(label))
maxWidth = fm.width(label)+10;
}
}
cw += fm.height();
return QSizeF(maxWidth+fm.height()*2,cw);
}
int genNextValue(int value){
int curValue = value;
while (curValue%4!=0){
curValue++;
}
return curValue;
}
qreal VerticalBarChart::valuesHMargin(QPainter* painter)
{
int delta = int(maxValue()-minValue());
delta = genNextValue(delta);
return painter->fontMetrics().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 (value<minValue) minValue=value;
}
}
return minValue;
}
int AbstractSeriesChart::valuesCount()
{
if (m_chartItem->itemMode()==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 (maxWidth<fm.width(series->name()))
maxWidth = fm.width(series->name())+10;
}
} else {
foreach(QString label, m_designLabels){
cw += fm.height();
if (maxWidth<fm.width(label))
maxWidth = fm.width(label)+10;
}
}
cw += fm.height();
return QSizeF(maxWidth+fm.height()*2,cw);
}
qreal HorizontalBarChart::valuesHMargin(QPainter *painter)
{
int delta = int(maxValue()-minValue());
delta = genNextValue(delta);
return painter->fontMetrics().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)<fm.width(currentWord)) maxWord = currentWord;
}
}
qreal curWidth = fm.width(maxWord);
QFont tmpFont = font;
while (curWidth>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<QFontMetricsF> 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;i<m_designLabels.size();++i){
QString label = m_designLabels.at(i);
painter->drawText(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