diff --git a/src/renderer/KoReportPreRenderer.cpp b/src/renderer/KoReportPreRenderer.cpp
index 2740bdb1..925cbbe7 100644
--- a/src/renderer/KoReportPreRenderer.cpp
+++ b/src/renderer/KoReportPreRenderer.cpp
@@ -1,669 +1,668 @@
/* This file is part of the KDE project
* Copyright (C) 2001-2007 by OpenMFG, LLC (info@openmfg.com)
* Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*/
#include "KoReportPreRenderer.h"
#include "KoReportPreRenderer_p.h"
#include "KoReportASyncItemManager.h"
#include "KReportOneRecordData.h"
#include "common/renderobjects.h"
#include "common/KoReportData.h"
#include "common/KoReportItemBase.h"
#include "common/krreportdata.h"
#include "common/krdetailsectiondata.h"
#include "common/labelsizeinfo.h"
#include "common/KReportPageFormat.h"
#ifdef KREPORT_SCRIPTING
#include "scripting/krscripthandler.h"
#include "scripting/kreportgrouptracker.h"
#endif
#include
#include
#include
#include "kreport_debug.h"
KoReportPreRendererPrivate::KoReportPreRendererPrivate()
{
m_valid = false;
m_reportData = 0;
m_document = 0;
m_page = 0;
m_yOffset = 0.0;
m_topMargin = m_bottomMargin = 0.0;
m_leftMargin = m_rightMargin = 0.0;
m_pageCounter = 0;
m_maxHeight = m_maxWidth = 0.0;
m_oneRecord = new KReportOneRecordData();
m_kodata = m_oneRecord;
-#ifdef KREPORT_SCRIPTING
m_scriptHandler = 0;
-#endif
asyncManager = new KoReportASyncItemManager(this);
connect(asyncManager, SIGNAL(finished()), this, SLOT(asyncItemsFinished()));
}
KoReportPreRendererPrivate::~KoReportPreRendererPrivate()
{
delete m_reportData;
delete m_oneRecord;
m_postProcText.clear();
}
void KoReportPreRendererPrivate::createNewPage()
{
//kreportDebug();
if (m_pageCounter > 0)
finishCurPage();
m_pageCounter++;
#ifdef KREPORT_SCRIPTING
//Update the page count script value
m_scriptHandler->setPageNumber(m_pageCounter);
m_scriptHandler->newPage();
#endif
m_page = new OROPage(0);
m_document->addPage(m_page);
//! @todo calculate past page
bool lastPage = false;
m_yOffset = m_topMargin;
if (m_pageCounter == 1 && m_reportData->m_pageHeaderFirst)
renderSection(*(m_reportData->m_pageHeaderFirst));
else if (lastPage == true && m_reportData->m_pageHeaderLast)
renderSection(*(m_reportData->m_pageHeaderLast));
else if ((m_pageCounter % 2) == 1 && m_reportData->m_pageHeaderOdd)
renderSection(*(m_reportData->m_pageHeaderOdd));
else if ((m_pageCounter % 2) == 0 && m_reportData->m_pageHeaderAny)
renderSection(*(m_reportData->m_pageHeaderAny));
else if (m_reportData->m_pageHeaderAny)
renderSection(*(m_reportData->m_pageHeaderAny));
}
qreal KoReportPreRendererPrivate::finishCurPageSize(bool lastPage)
{
qreal retval = 0.0;
if (lastPage && m_reportData->m_pageFooterLast)
retval = renderSectionSize(* (m_reportData->m_pageFooterLast));
else if (m_pageCounter == 1 && m_reportData->m_pageFooterFirst)
retval = renderSectionSize(* (m_reportData->m_pageFooterFirst));
else if ((m_pageCounter % 2) == 1 && m_reportData->m_pageFooterOdd)
retval = renderSectionSize(* (m_reportData->m_pageFooterOdd));
else if ((m_pageCounter % 2) == 0 && m_reportData->m_pageFooterEven)
retval = renderSectionSize(* (m_reportData->m_pageFooterEven));
else if (m_reportData->m_pageFooterAny)
retval = renderSectionSize(* (m_reportData->m_pageFooterAny));
//kreportDebug() << retval;
return retval;
}
qreal KoReportPreRendererPrivate::finishCurPage(bool lastPage)
{
qreal offset = m_maxHeight - m_bottomMargin;
qreal retval = 0.0;
//kreportDebug() << offset;
if (lastPage && m_reportData->m_pageFooterLast) {
//kreportDebug() << "Last Footer";
m_yOffset = offset - renderSectionSize(* (m_reportData->m_pageFooterLast));
retval = renderSection(* (m_reportData->m_pageFooterLast));
} else if (m_pageCounter == 1 && m_reportData->m_pageFooterFirst) {
//kreportDebug() << "First Footer";
m_yOffset = offset - renderSectionSize(* (m_reportData->m_pageFooterFirst));
retval = renderSection(* (m_reportData->m_pageFooterFirst));
} else if ((m_pageCounter % 2) == 1 && m_reportData->m_pageFooterOdd) {
//kreportDebug() << "Odd Footer";
m_yOffset = offset - renderSectionSize(* (m_reportData->m_pageFooterOdd));
retval = renderSection(* (m_reportData->m_pageFooterOdd));
} else if ((m_pageCounter % 2) == 0 && m_reportData->m_pageFooterEven) {
//kreportDebug() << "Even Footer";
m_yOffset = offset - renderSectionSize(* (m_reportData->m_pageFooterEven));
retval = renderSection(* (m_reportData->m_pageFooterEven));
} else if (m_reportData->m_pageFooterAny) {
//kreportDebug() << "Any Footer";
m_yOffset = offset - renderSectionSize(* (m_reportData->m_pageFooterAny));
retval = renderSection(* (m_reportData->m_pageFooterAny));
}
return retval;
}
void KoReportPreRendererPrivate::renderDetailSection(KRDetailSectionData *detailData)
{
if (detailData->m_detailSection) {
if (m_kodata/* && !curs->eof()*/) {
QStringList keys;
QStringList keyValues;
QList shownGroups;
ORDetailGroupSectionData * grp = 0;
bool status = m_kodata->moveFirst();
m_recordCount = m_kodata->recordCount();
//kreportDebug() << "Record Count:" << m_recordCount;
for (int i = 0; i < (int) detailData->m_groupList.count(); ++i) {
grp = detailData->m_groupList[i];
//If the group has a header or footer, then emit a change of group value
if(grp->m_groupFooter || grp->m_groupHeader) {
// we get here only if group is *shown*
shownGroups << i;
keys.append(grp->m_column);
if (!keys.last().isEmpty())
keyValues.append(m_kodata->value(m_kodata->fieldNumber(keys.last())).toString());
else
keyValues.append(QString());
//Tell interested parties we're about to render a header
emit(enteredGroup(keys.last(), keyValues.last()));
}
if (grp->m_groupHeader)
renderSection(*(grp->m_groupHeader));
}
while (status) {
long l = m_kodata->at();
//kreportDebug() << "At:" << l << "Y:" << m_yOffset << "Max Height:" << m_maxHeight;
if (renderSectionSize(*(detailData->m_detailSection)) + finishCurPageSize((l + 1 == m_recordCount)) + m_bottomMargin + m_yOffset >= m_maxHeight) {
//kreportDebug() << "Next section is too big for this page";
if (l > 0) {
m_kodata->movePrevious();
createNewPage();
m_kodata->moveNext();
}
}
renderSection(*(detailData->m_detailSection));
if (m_kodata)
status = m_kodata->moveNext();
if (status == true && keys.count() > 0) {
// check to see where it is we need to start
int pos = -1; // if it's still -1 by the time we are done then no keyValues changed
for (int i = 0; i < keys.count(); ++i) {
if (keyValues[i] != m_kodata->value(m_kodata->fieldNumber(keys[i])).toString()) {
pos = i;
break;
}
}
// don't bother if nothing has changed
if (pos != -1) {
// roll back the query and go ahead if all is good
status = m_kodata->movePrevious();
if (status == true) {
// print the footers as needed
// any changes made in this for loop need to be duplicated
// below where the footers are finished.
bool do_break = false;
for (int i = shownGroups.count() - 1; i >= 0; i--) {
if (do_break)
createNewPage();
do_break = false;
grp = detailData->m_groupList[shownGroups.at(i)];
if (grp->m_groupFooter) {
if (renderSectionSize(*(grp->m_groupFooter)) + finishCurPageSize() + m_bottomMargin + m_yOffset >= m_maxHeight)
createNewPage();
renderSection(*(grp->m_groupFooter));
}
if (ORDetailGroupSectionData::BreakAfterGroupFooter == grp->m_pagebreak)
do_break = true;
}
// step ahead to where we should be and print the needed headers
// if all is good
status = m_kodata->moveNext();
if (do_break)
createNewPage();
if (status == true) {
for (int i = 0; i < shownGroups.count(); ++i) {
grp = detailData->m_groupList[shownGroups.at(i)];
if (grp->m_groupHeader) {
if (renderSectionSize(*(grp->m_groupHeader)) + finishCurPageSize() + m_bottomMargin + m_yOffset >= m_maxHeight) {
m_kodata->movePrevious();
createNewPage();
m_kodata->moveNext();
}
if (!keys[i].isEmpty())
keyValues[i] = m_kodata->value(m_kodata->fieldNumber(keys[i])).toString();
//Tell interested parties thak key values changed
renderSection(*(grp->m_groupHeader));
}
}
}
}
}
}
}
if (keys.size() > 0 && m_kodata->movePrevious()) {
// finish footers
// duplicated changes from above here
for (int i = shownGroups.count() - 1; i >= 0; i--) {
grp = detailData->m_groupList[shownGroups.at(i)];
if (grp->m_groupFooter) {
if (renderSectionSize(*(grp->m_groupFooter)) + finishCurPageSize() + m_bottomMargin + m_yOffset >= m_maxHeight)
createNewPage();
renderSection(*(grp->m_groupFooter));
emit(exitedGroup(keys[i], keyValues[i]));
}
}
}
}
if (KRDetailSectionData::BreakAtEnd == detailData->m_pageBreak)
createNewPage();
}
}
qreal KoReportPreRendererPrivate::renderSectionSize(const KRSectionData & sectionData)
{
QScreen *srn = QApplication::screens().at(0);
qreal intHeight = POINT_TO_INCH(sectionData.height()) * srn->logicalDotsPerInchX();
int itemHeight = 0;
if (sectionData.objects().count() == 0)
return intHeight;
QList objects = sectionData.objects();
foreach(KoReportItemBase *ob, objects) {
QPointF offset(m_leftMargin, m_yOffset);
QVariant itemData = m_kodata->value(ob->itemDataSource());
//ASync objects cannot alter the section height
KoReportASyncItemBase *async_ob = qobject_cast(ob);
if (!async_ob) {
itemHeight = ob->renderSimpleData(0, 0, offset, itemData, m_scriptHandler);
if (itemHeight > intHeight) {
intHeight = itemHeight;
}
}
}
return intHeight;
}
qreal KoReportPreRendererPrivate::renderSection(const KRSectionData & sectionData)
{
QScreen *srn = QApplication::screens().at(0);
qreal sectionHeight = POINT_TO_INCH(sectionData.height()) * srn->logicalDotsPerInchX();
int itemHeight = 0;
//kreportDebug() << "Name: " << sectionData.name() << " Height: " << sectionHeight
// << "Objects: " << sectionData.objects().count();
emit(renderingSection(const_cast(§ionData), m_page, QPointF(m_leftMargin, m_yOffset)));
//Create a pre-rendered section for this section and add it to the document
OROSection *sec = new OROSection(m_document);
sec->setHeight(sectionData.height());
sec->setBackgroundColor(sectionData.backgroundColor());
sec->setType(sectionData.type());
m_document->addSection(sec);
//Render section background
ORORect* bg = new ORORect();
bg->setPen(QPen(Qt::NoPen));
bg->setBrush(sectionData.backgroundColor());
qreal w = m_page->document()->pageOptions().widthPx() - m_page->document()->pageOptions().getMarginRight() - m_leftMargin;
bg->setRect(QRectF(m_leftMargin, m_yOffset, w, sectionHeight));
m_page->addPrimitive(bg, true);
QList objects = sectionData.objects();
foreach(KoReportItemBase *ob, objects) {
QPointF offset(m_leftMargin, m_yOffset);
QVariant itemData = m_kodata->value(ob->itemDataSource());
if (ob->supportsSubQuery()) {
itemHeight = ob->renderReportData(m_page, sec, offset, m_kodata, m_scriptHandler);
} else {
KoReportASyncItemBase *async_ob = qobject_cast(ob);
if (async_ob){
//kreportDebug() << "async object";
asyncManager->addItem(async_ob, m_page, sec, offset, itemData, m_scriptHandler);
} else {
//kreportDebug() << "sync object";
itemHeight = ob->renderSimpleData(m_page, sec, offset, itemData, m_scriptHandler);
}
}
if (itemHeight > sectionHeight) {
sectionHeight = itemHeight;
}
}
for (int i = 0; i < m_page->primitives(); ++i) {
OROPrimitive *prim = m_page->primitive(i);
if (prim->type() == OROTextBox::TextBox) {
OROTextBox *text = static_cast(prim);
if (text->requiresPostProcessing()) {
m_postProcText.append(text);
}
}
}
m_yOffset += sectionHeight;
return sectionHeight;
}
#ifdef KREPORT_SCRIPTING
void KoReportPreRendererPrivate::initEngine()
{
delete m_scriptHandler;
m_scriptHandler = new KRScriptHandler(m_kodata, m_reportData);
connect(this, SIGNAL(enteredGroup(QString,QVariant)), m_scriptHandler, SLOT(slotEnteredGroup(QString,QVariant)));
connect(this, SIGNAL(exitedGroup(QString,QVariant)), m_scriptHandler, SLOT(slotExitedGroup(QString,QVariant)));
connect(this, SIGNAL(renderingSection(KRSectionData*,OROPage*,QPointF)), m_scriptHandler, SLOT(slotEnteredSection(KRSectionData*,OROPage*,QPointF)));
}
#endif
void KoReportPreRendererPrivate::asyncItemsFinished()
{
//kreportDebug() << "Finished rendering async items";
delete asyncManager;
}
//===========================KoReportPreRenderer===============================
KoReportPreRenderer::KoReportPreRenderer(const QDomElement & document)
: d(new KoReportPreRendererPrivate())
{
setDocument(document);
}
KoReportPreRenderer::~KoReportPreRenderer()
{
delete d;
}
void KoReportPreRenderer::setName(const QString &n)
{
d->m_reportData->setName(n);
}
ORODocument* KoReportPreRenderer::generate()
{
QScreen *srn = QApplication::screens().at(0);
int dpiX = srn->logicalDotsPerInchX();
int dpiY = srn->logicalDotsPerInchY();
if (d == 0 || !d->m_valid || d->m_reportData == 0 || d->m_kodata == 0)
return 0;
// Do this check now so we don't have to undo a lot of work later if it fails
LabelSizeInfo label;
if (d->m_reportData->page.getPageSize() == QLatin1String("Labels")) {
label = LabelSizeInfo::find(d->m_reportData->page.getLabelType());
if (label.isNull())
return 0;
}
//kreportDebug() << "Creating Document";
d->m_document = new ORODocument(d->m_reportData->m_title);
d->m_pageCounter = 0;
d->m_yOffset = 0.0;
//kreportDebug() << "Calculating Margins";
if (!label.isNull()) {
if (d->m_reportData->page.isPortrait()) {
d->m_topMargin = (label.startY() / 100.0);
d->m_bottomMargin = 0;
d->m_rightMargin = 0;
d->m_leftMargin = (label.startX() / 100.0);
} else {
d->m_topMargin = (label.startX() / 100.0);
d->m_bottomMargin = 0;
d->m_rightMargin = 0;
d->m_leftMargin = (label.startY() / 100.0);
}
} else {
d->m_topMargin = d->m_reportData->page.getMarginTop();
d->m_bottomMargin = d->m_reportData->page.getMarginBottom();
d->m_rightMargin = d->m_reportData->page.getMarginRight();
d->m_leftMargin = d->m_reportData->page.getMarginLeft();
//kreportDebug() << "Margins:" << d->m_topMargin << d->m_bottomMargin << d->m_rightMargin << d->m_leftMargin;
}
//kreportDebug() << "Calculating Page Size";
ReportPageOptions rpo(d->m_reportData->page);
// This should reflect the information of the report page size
if (d->m_reportData->page.getPageSize() == QLatin1String("Custom")) {
d->m_maxWidth = d->m_reportData->page.getCustomWidth();
d->m_maxHeight = d->m_reportData->page.getCustomHeight();
} else {
if (!label.isNull()) {
d->m_maxWidth = label.width();
d->m_maxHeight = label.height();
rpo.setPageSize(label.paper());
} else {
// lookup the correct size information for the specified size paper
d->m_maxWidth = KReportPageFormat::width(KReportPageFormat::formatFromString(d->m_reportData->page.getPageSize()), KReportPageFormat::Portrait);
d->m_maxHeight = KReportPageFormat::height(KReportPageFormat::formatFromString(d->m_reportData->page.getPageSize()), KReportPageFormat::Portrait);
KReportUnit pageUnit(KReportUnit::Millimeter);
d->m_maxWidth = KReportUnit::toInch(pageUnit.fromUserValue(d->m_maxWidth)) * dpiX;
d->m_maxHeight = KReportUnit::toInch(pageUnit.fromUserValue(d->m_maxHeight)) * dpiY;
}
}
if (!d->m_reportData->page.isPortrait()) {
qreal tmp = d->m_maxWidth;
d->m_maxWidth = d->m_maxHeight;
d->m_maxHeight = tmp;
}
//kreportDebug() << "Page Size:" << d->m_maxWidth << d->m_maxHeight;
d->m_document->setPageOptions(rpo);
d->m_kodata->setSorting(d->m_reportData->m_detailSection->m_sortedFields);
d->m_kodata->open();
#ifdef KREPORT_SCRIPTING
d->initEngine();
connect(d->m_scriptHandler, SIGNAL(groupChanged(QMap)),
this, SIGNAL(groupChanged(QMap)));
//Loop through all abjects that have been registered, and register them with the script handler
if (d->m_scriptHandler) {
QMapIterator i(d->m_scriptObjects);
while (i.hasNext()) {
i.next();
d->m_scriptHandler->registerScriptObject(i.value(), i.key());
}
//execute the script, if it fails, abort and return the empty document
if (!d->m_scriptHandler->trigger()) {
d->m_scriptHandler->displayErrors();
return d->m_document;
}
}
#endif
d->createNewPage();
if (!label.isNull()) {
// Label Print Run
// remember the initial margin setting as we will be modifying
// the value and restoring it as we move around
qreal margin = d->m_leftMargin;
d->m_yOffset = d->m_topMargin;
qreal w = (label.width() / 100.0);
qreal wg = (label.xGap() / 100.0);
qreal h = (label.height() / 100.0);
qreal hg = (label.yGap() / 100.0);
int numCols = label.columns();
int numRows = label.rows();
qreal tmp;
// flip the value around if we are printing landscape
if (!d->m_reportData->page.isPortrait()) {
w = (label.height() / 100.0);
wg = (label.yGap() / 100.0);
h = (label.width() / 100.0);
hg = (label.xGap() / 100.0);
numCols = label.rows();
numRows = label.columns();
}
KRDetailSectionData * detailData = d->m_reportData->m_detailSection;
if (detailData->m_detailSection) {
KoReportData *mydata = d->m_kodata;
if (mydata && mydata->recordCount() > 0) { /* && !((query = orqThis->getQuery())->eof()))*/
mydata->moveFirst();
int row = 0;
int col = 0;
do {
tmp = d->m_yOffset; // store the value as renderSection changes it
d->renderSection(*(detailData->m_detailSection));
d->m_yOffset = tmp; // restore the value that renderSection modified
col++;
d->m_leftMargin += w + wg;
if (col >= numCols) {
d->m_leftMargin = margin; // reset back to original value
col = 0;
row++;
d->m_yOffset += h + hg;
if (row >= numRows) {
d->m_yOffset = d->m_topMargin;
row = 0;
d->createNewPage();
}
}
} while (mydata->moveNext());
}
}
} else {
// Normal Print Run
if (d->m_reportData->m_reportHeader) {
d->renderSection(*(d->m_reportData->m_reportHeader));
}
if (d->m_reportData->m_detailSection) {
d->renderDetailSection(d->m_reportData->m_detailSection);
}
if (d->m_reportData->m_reportFooter) {
if (d->renderSectionSize(*(d->m_reportData->m_reportFooter)) + d->finishCurPageSize(true) + d->m_bottomMargin + d->m_yOffset >= d->m_maxHeight) {
d->createNewPage();
}
d->renderSection(*(d->m_reportData->m_reportFooter));
}
}
d->finishCurPage(true);
#ifdef KREPORT_SCRIPTING
// _postProcText contains those text boxes that need to be updated
// with information that wasn't available at the time it was added to the document
d->m_scriptHandler->setPageTotal(d->m_document->pages());
for (int i = 0; i < d->m_postProcText.size(); i++) {
OROTextBox * tb = d->m_postProcText.at(i);
d->m_scriptHandler->setPageNumber(tb->page()->page() + 1);
tb->setText(d->m_scriptHandler->evaluate(tb->text()).toString());
}
#endif
d->asyncManager->startRendering();
#ifdef KREPORT_SCRIPTING
d->m_scriptHandler->displayErrors();
#endif
d->m_kodata->close();
#ifdef KREPORT_SCRIPTING
delete d->m_scriptHandler;
+ d->m_scriptHandler = 0;
#endif
//! @todo check ownership delete d->m_kodata;
d->m_postProcText.clear();
return d->m_document;
}
void KoReportPreRenderer::setSourceData(KoReportData *data)
{
if (data) {
d->m_kodata = data;
}
}
bool KoReportPreRenderer::setDocument(const QDomElement &document)
{
delete d->m_reportData;
d->m_valid = false;
if (document.tagName() != QLatin1String("report:content")) {
kreportWarning() << "report schema is invalid";
return false;
}
d->m_reportData = new KoReportReportData(document);
d->m_valid = d->m_reportData->isValid();
return isValid();
}
bool KoReportPreRenderer::isValid() const
{
if (d && d->m_valid)
return true;
return false;
}
#ifdef KREPORT_SCRIPTING
void KoReportPreRenderer::registerScriptObject(QObject* obj, const QString& name)
{
//kreportDebug() << name;
d->m_scriptObjects[name] = obj;
}
KRScriptHandler *KoReportPreRenderer::scriptHandler()
{
return d->m_scriptHandler;
}
#endif
const KoReportReportData* KoReportPreRenderer::reportData() const
{
return d->m_reportData;
}