/*************************************************************************** * This file is part of the Lime Report project * * Copyright (C) 2015 by Alexander Arin * * arin_a@bk.ru * * * ** GNU General Public License Usage ** * * * This library is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ** GNU Lesser General Public License ** * * * 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 3 of the * * License, or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public * * License along with this library. * * If not, see . * * * * 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 General Public License for more details. * ****************************************************************************/ #include #include #include #include "lrglobal.h" #include "lrreportrender.h" #include "lrpagedesignintf.h" #include "lrbanddesignintf.h" #include "lritemdesignintf.h" #include "lrscriptenginemanager.h" #include "serializators/lrxmlreader.h" #include "serializators/lrxmlwriter.h" namespace LimeReport{ void ReportRender::initColumns(){ m_maxHeightByColumn.clear(); m_currentStartDataPos.clear(); m_maxHeightByColumn.append(0); m_currentStartDataPos.append(0); } bool ReportRender::isNeedToRearrangeColumnsItems() { if (m_columnedBandItems.size()<=1) return false; if (m_columnedBandItems[0]->columnsFillDirection()!=BandDesignIntf::VerticalUniform) return false; int avg = m_columnedBandItems.size()/m_columnedBandItems[0]->columnsCount(); for (int i=0;imaxHeight){ maxHeight = m_maxHeightByColumn[i]; maxHeightColumn = i; } if (maxHeightColumn>0 && columnItemsCount(maxHeightColumn) lastColumnItem(maxHeightColumn-1)->height() ){ return true; } } return false; } BandDesignIntf *ReportRender::lastColumnItem(int columnIndex) { if (columnIndex<0) return 0; for(int i=0;icolumnIndex()>columnIndex) return m_columnedBandItems[i-1]; } return m_columnedBandItems.last(); } void ReportRender::rearrangeColumnsItems() { if (isNeedToRearrangeColumnsItems()){ qreal startHeight = columnHeigth(0); int avg = m_columnedBandItems.size()/m_columnedBandItems[0]->columnsCount(); for (int i=1;icolumnsCount();++i){ if (columnItemsCount(i)columnsCount()-i) - columnItemsCount(i); for (int j=0;jsetPos(band->pos().x()+band->width(),m_columnedBandItems[0]->pos().y()); band->setColumnIndex(i); } } } m_renderPageItem->relocateBands(); m_maxHeightByColumn[0]+=startHeight-maxColumnHeight(); m_currentStartDataPos[0]-=startHeight-maxColumnHeight(); m_columnedBandItems.clear(); } } int ReportRender::columnItemsCount(int columnIndex) { int result = 0; foreach(BandDesignIntf* band, m_columnedBandItems){ if (band->columnIndex()==columnIndex) ++result; if (band->columnIndex()>columnIndex) break; } return result; } qreal ReportRender::columnHeigth(int columnIndex) { qreal result = 0; for(int i=0;icolumnIndex()==columnIndex) result += m_columnedBandItems[i]->height(); if (m_columnedBandItems[i]->columnIndex()>columnIndex) break; } return result; } qreal ReportRender::maxColumnHeight() { qreal result = 0; for (int i=0;icolumnsCount();++i){ qreal curColumnHeight = columnHeigth(i); if (curColumnHeight>result) result = curColumnHeight; } return result; } void ReportRender::renameChildItems(BaseDesignIntf *item){ foreach(BaseDesignIntf* child, item->childBaseItems()){ if (!child->childBaseItems().isEmpty()) renameChildItems(child); child->setObjectName(child->metaObject()->className()+QString::number(++m_curentNameIndex)); } } ReportRender::ReportRender(QObject *parent) :QObject(parent), m_renderPageItem(0), m_pageCount(0), m_lastDataBand(0), m_lastRenderedFooter(0), m_currentColumn(0) { initColumns(); } void ReportRender::setDatasources(DataSourceManager *value) { m_datasources=value; initVariables(); resetPageNumber(BandReset); } void ReportRender::setScriptContext(ScriptEngineContext* scriptContext) { m_scriptEngineContext=scriptContext; } bool ReportRender::runInitScript(){ if (m_scriptEngineContext){ QScriptEngine* engine = ScriptEngineManager::instance().scriptEngine(); engine->pushContext(); QScriptValue res = engine->evaluate(m_scriptEngineContext->initScript()); if (res.isBool()) return res.toBool(); if (engine->hasUncaughtException()) { QMessageBox::critical(0,tr("Error"), QString("Line %1: %2 ").arg(engine->uncaughtExceptionLineNumber()) .arg(engine->uncaughtException().toString()) ); return false; } } return true; } void ReportRender::initDatasources(){ try{ datasources()->setAllDatasourcesToFirst(); } catch(ReportError &exception){ //TODO possible should thow exeption QMessageBox::critical(0,tr("Error"),exception.what()); return; } } void ReportRender::initDatasource(const QString& name){ try{ if (datasources()->containsDatasource(name)){ IDataSource* ds = datasources()->dataSource(name); if (ds) ds->first(); } } catch(ReportError &exception){ QMessageBox::critical(0,tr("Error"),exception.what()); return; } } void ReportRender::renderPage(PageDesignIntf* patternPage) { m_curentNameIndex = 0; m_patternPageItem = patternPage->pageItem(); if (m_patternPageItem->resetPageNumber() && m_pageCount>0) { resetPageNumber(PageReset); } m_renderCanceled = false; BandDesignIntf* reportFooter = m_patternPageItem->bandByType(BandDesignIntf::ReportFooter); m_reportFooterHeight = 0; if (reportFooter) m_reportFooterHeight = reportFooter->height(); initGroups(); #ifdef HAVE_UI_LOADER initDialogs(); #endif if (m_scriptEngineContext){ baseDesignIntfToScript(patternPage->pageItem()); foreach (BaseDesignIntf* item, patternPage->pageItem()->childBaseItems()){ baseDesignIntfToScript(item); } } if (runInitScript()){ clearPageMap(); try{ datasources()->setAllDatasourcesToFirst(); datasources()->clearGroupFuntionsExpressions(); } catch(ReportError &exception){ //TODO possible should thow exeption QMessageBox::critical(0,tr("Error"),exception.what()); return; } clearPageMap(); startNewPage(); renderBand(m_patternPageItem->bandByType(BandDesignIntf::ReportHeader), 0, StartNewPageAsNeeded); BandDesignIntf* lastRenderedBand = 0; for (int i=0;idataBandCount() && !m_renderCanceled;i++){ lastRenderedBand = m_patternPageItem->dataBandAt(i); initDatasource(lastRenderedBand->datasourceName()); renderDataBand(lastRenderedBand); if (idataBandCount()-1) closeFooterGroup(lastRenderedBand); } if (reportFooter) renderBand(reportFooter, 0, StartNewPageAsNeeded); if (lastRenderedBand && lastRenderedBand->keepFooterTogether()) closeFooterGroup(lastRenderedBand); BandDesignIntf* tearOffBand = m_patternPageItem->bandByType(BandDesignIntf::TearOffBand); if (tearOffBand) renderBand(tearOffBand, 0, StartNewPageAsNeeded); savePage(true); ScriptEngineManager::instance().scriptEngine()->popContext(); } } int ReportRender::pageCount() { return m_renderedPages.count(); } PageItemDesignIntf::Ptr ReportRender::pageAt(int index) { if ((index>m_renderedPages.count()-1)||(index<0)) throw ReportError(tr("page index out of range")); else return m_renderedPages.at(index); } QString ReportRender::renderPageToString(PageDesignIntf *patternPage) { renderPage(patternPage); return toString(); } ReportPages ReportRender::renderPageToPages(PageDesignIntf *patternPage) { renderPage(patternPage); return m_renderedPages; } void ReportRender::initRenderPage() { if (!m_renderPageItem) { m_renderPageItem = new PageItemDesignIntf(m_patternPageItem->pageSize(), m_patternPageItem->pageRect()); m_renderPageItem->initFromItem(m_patternPageItem); m_renderPageItem->setItemMode(PreviewMode); m_renderPageItem->setPatternName(m_patternPageItem->objectName()); } } void ReportRender::initVariables() { m_datasources->setReportVariable("#PAGE",1); m_datasources->setReportVariable("#PAGE_COUNT",0); } #ifdef HAVE_UI_LOADER void ReportRender::initDialogs(){ if (m_scriptEngineContext){ QScriptEngine* se = ScriptEngineManager::instance().scriptEngine(); foreach(DialogDescriber::Ptr dialog, m_scriptEngineContext->dialogsDescriber()){ QScriptValue sv = se->newQObject(m_scriptEngineContext->getDialog(dialog->name())); se->globalObject().setProperty(dialog->name(),sv); } } } #endif void ReportRender::clearPageMap() { m_renderedPages.clear(); } void ReportRender::extractGroupFuntionsFromItem(ContentItemDesignIntf* contentItem, BandDesignIntf* band){ if ( contentItem && contentItem->content().contains(QRegExp("\\$S\\s*\\{.*\\}"))){ foreach(const QString &functionName, m_datasources->groupFunctionNames()){ QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName)); QRegExp rxName(QString(Const::GROUP_FUNCTION_NAME_RX).arg(functionName)); if (rx.indexIn(contentItem->content())>=0){ int pos = 0; while ( (pos = rx.indexIn(contentItem->content(),pos)) != -1){ QVector captures = normalizeCaptures(rx); if (captures.size()>=3){ int dsIndex = captures.size() == 3 ? Const::DATASOURCE_INDEX - 1 : Const::DATASOURCE_INDEX; BandDesignIntf* dataBand = m_patternPageItem->bandByName(captures.at(dsIndex)); if (dataBand){ GroupFunction* gf = datasources()->addGroupFunction(functionName,captures.at(Const::VALUE_INDEX),band->objectName(),dataBand->objectName()); if (gf){ connect(dataBand,SIGNAL(bandRendered(BandDesignIntf*)),gf,SLOT(slotBandRendered(BandDesignIntf*))); } } else { GroupFunction* gf = datasources()->addGroupFunction(functionName,captures.at(Const::VALUE_INDEX),band->objectName(),captures.at(dsIndex)); gf->setInvalid(tr("Databand \"%1\" not found").arg(captures.at(dsIndex))); } } pos += rx.matchedLength(); } } else if (rxName.indexIn(contentItem->content())>=0){ GroupFunction* gf = datasources()->addGroupFunction(functionName,rxName.cap(1),band->objectName(),""); gf->setInvalid(tr("Wrong using function %1").arg(functionName)); } } } } void ReportRender::extractGroupFunctionsFromContainer(BaseDesignIntf* baseItem, BandDesignIntf* band){ foreach (BaseDesignIntf* item, baseItem->childBaseItems()) { ContentItemDesignIntf* contentItem = dynamic_cast(item); if (contentItem) extractGroupFuntionsFromItem(contentItem, band); else extractGroupFunctionsFromContainer(item, band); } } void ReportRender::extractGroupFunctions(BandDesignIntf *band) { extractGroupFunctionsFromContainer(band, band); } void ReportRender::replaceGroupFunctionsInItem(ContentItemDesignIntf* contentItem, BandDesignIntf* band){ if (contentItem){ QString content = contentItem->content(); foreach(const QString &functionName, m_datasources->groupFunctionNames()){ QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName)); if (rx.indexIn(content)>=0){ int pos = 0; while ( (pos = rx.indexIn(content,pos))!= -1 ){ QVector captures = normalizeCaptures(rx); if (captures.size() >= 3){ QString expressionIndex = datasources()->putGroupFunctionsExpressions(captures.at(Const::VALUE_INDEX)); content.replace(captures.at(0),QString("%1(%2,%3)").arg(functionName).arg('"'+expressionIndex+'"').arg('"'+band->objectName()+'"')); } pos += rx.matchedLength(); } contentItem->setContent(content); } } } } void ReportRender::replaceGroupFunctionsInContainer(BaseDesignIntf* baseItem, BandDesignIntf* band) { foreach(BaseDesignIntf* item, baseItem->childBaseItems()){ ContentItemDesignIntf* contentItem = dynamic_cast(item); if (contentItem) replaceGroupFunctionsInItem(contentItem, band); else replaceGroupFunctionsInContainer(item, band); } } void ReportRender::replaceGroupsFunction(BandDesignIntf *band) { replaceGroupFunctionsInContainer(band, band); } BandDesignIntf* ReportRender::renderBand(BandDesignIntf *patternBand, BandDesignIntf* bandData, ReportRender::DataRenderMode mode, bool isLast) { QApplication::processEvents(); if (patternBand){ BandDesignIntf* bandClone = 0; if (bandData){ bandClone = bandData; } else { bandClone=renderData(patternBand); } if (mode == ForcedStartPage){ savePage(); startNewPage(); } if (patternBand->isFooter()) m_lastRenderedFooter = patternBand; bandClone->setBackgroundColor( (datasources()->variable(QLatin1String("line_")+patternBand->objectName().toLower()).toInt() %2 !=0 ? bandClone->backgroundColor(): bandClone->alternateBackgroundColor() ) ); patternBand->emitBandRendered(bandClone); emit(patternBand->afterRender()); if ( isLast && bandClone->keepFooterTogether() && bandClone->sliceLastRow() ){ if (m_maxHeightByColumn[m_currentColumn] < (bandClone->height()+m_reportFooterHeight)) m_maxHeightByColumn[m_currentColumn] -= ((m_maxHeightByColumn[m_currentColumn]-bandClone->height())+(bandClone->height()*calcSlicePercent(bandClone->height()))); } if (!bandClone->isEmpty() || patternBand->printIfEmpty()){ if (!registerBand(bandClone)){ if (bandClone->canBeSplitted(m_maxHeightByColumn[m_currentColumn])){ bandClone = sliceBand(bandClone,patternBand,isLast); } else { qreal percent = (bandClone->height()-m_maxHeightByColumn[m_currentColumn])/(bandClone->height()/100); if (bandClone->maxScalePercent()>=percent){ if (percentmaxScalePercent()){ percent += 2; bandClone->setScale((100-percent)/100); BandDesignIntf* upperPart = dynamic_cast(bandClone->cloneUpperPart(m_maxHeightByColumn[m_currentColumn])); registerBand(upperPart); delete bandClone; bandClone = NULL; } } else { if (mode==StartNewPageAsNeeded){ if (bandClone->columnsCount()>1 && (bandClone->columnsFillDirection()==BandDesignIntf::Vertical || bandClone->columnsFillDirection()==BandDesignIntf::VerticalUniform)) { startNewColumn(); } else { savePage(); startNewPage(); } if (!registerBand(bandClone)) { BandDesignIntf* upperPart = dynamic_cast(bandClone->cloneUpperPart(m_maxHeightByColumn[m_currentColumn])); registerBand(upperPart); delete bandClone; bandClone = NULL; }; } else { bandClone->setHeight(m_maxHeightByColumn[m_currentColumn]); registerBand(bandClone); } } } } } else { delete bandClone; return 0; } if (patternBand->isFooter()) datasources()->clearGroupFunctionValues(patternBand->objectName()); return bandClone; } return 0; } void ReportRender::renderDataBand(BandDesignIntf *dataBand) { if (dataBand == NULL ) return; IDataSource* bandDatasource = 0; m_lastRenderedFooter = 0; if (!dataBand->datasourceName().isEmpty()) bandDatasource = datasources()->dataSource(dataBand->datasourceName()); BandDesignIntf* header = dataBand->bandHeader(); BandDesignIntf* footer = dataBand->bandFooter(); if (header && header->printAlways()) renderBand(header, 0); if(bandDatasource && !bandDatasource->eof() && !m_renderCanceled){ QString varName = QLatin1String("line_")+dataBand->objectName().toLower(); datasources()->setReportVariable(varName,1); if (header && !header->printAlways()) renderBand(header, 0); if (dataBand->bandHeader() && dataBand->bandHeader()->reprintOnEachPage()) m_reprintableBands.append(dataBand->bandHeader()); renderChildHeader(dataBand,PrintNotAlwaysPrintable); renderGroupHeader(dataBand, bandDatasource, true); bool firstTime = true; while(!bandDatasource->eof() && !m_renderCanceled){ BandDesignIntf* rawData = renderData(dataBand); if (!rawData->isEmpty() || dataBand->printIfEmpty()){ if ((firstTime && dataBand->startFromNewPage()) || (!firstTime && dataBand->startNewPage())) { savePage(); startNewPage(); } if (dataBand->tryToKeepTogether()) openDataGroup(dataBand); if (dataBand->keepFooterTogether() && !bandDatasource->hasNext()) openFooterGroup(dataBand); datasources()->updateChildrenData(dataBand->datasourceName()); m_lastDataBand = dataBand; if (header && !firstTime && header->repeatOnEachRow()) renderBand(header, 0, StartNewPageAsNeeded); renderBand(dataBand, rawData, StartNewPageAsNeeded, !bandDatasource->hasNext()); renderChildBands(dataBand); } bandDatasource->next(); datasources()->setReportVariable(varName,datasources()->variable(varName).toInt()+1); foreach (BandDesignIntf* band, dataBand->childrenByType(BandDesignIntf::GroupHeader)){ QString groupLineVar = QLatin1String("line_")+band->objectName().toLower(); if (datasources()->containsVariable(groupLineVar)) datasources()->setReportVariable(groupLineVar,datasources()->variable(groupLineVar).toInt()+1); } renderGroupHeader(dataBand, bandDatasource, false); if (dataBand->tryToKeepTogether()) closeDataGroup(dataBand); firstTime = false; } m_reprintableBands.removeOne(dataBand->bandHeader()); if (bandDatasource->prior()){ renderGroupFooter(dataBand); bandDatasource->next(); } if (footer && !footer->printAlways()) renderBand(footer, 0, StartNewPageAsNeeded); datasources()->deleteVariable(varName); } else if (bandDatasource==0) { renderBand(dataBand, 0, StartNewPageAsNeeded); } if (footer && footer->printAlways()) renderBand(footer, 0, StartNewPageAsNeeded); } void ReportRender::renderPageHeader(PageItemDesignIntf *patternPage) { BandDesignIntf* band = patternPage->bandByType(BandDesignIntf::PageHeader); if (band){ if (m_datasources->variable("#PAGE").toInt()!=1 || band->property("printOnFirstPage").toBool() ) renderBand(band, 0); } } void ReportRender::renderPageFooter(PageItemDesignIntf *patternPage) { BandDesignIntf* band = patternPage->bandByType(BandDesignIntf::PageFooter); if (band){ BandDesignIntf* bandClone = dynamic_cast(band->cloneItem(PreviewMode, m_renderPageItem,m_renderPageItem)); replaceGroupsFunction(bandClone); bandClone->updateItemSize(m_datasources); bandClone->setItemPos(m_patternPageItem->pageRect().x(),m_patternPageItem->pageRect().bottom()-bandClone->height()); bandClone->setHeight(m_pageFooterHeight); for(int i=0;iclearGroupFunctionValues(band->objectName()); } } void ReportRender::renderPageItems(PageItemDesignIntf* patternPage) { QList pageItems; foreach (BaseDesignIntf* item, patternPage->childBaseItems()) { ItemDesignIntf* id = dynamic_cast(item); if (id&&id->itemLocation()==ItemDesignIntf::Page){ BaseDesignIntf* cloneItem = item->cloneItem(m_renderPageItem->itemMode(), m_renderPageItem, m_renderPageItem); pageItems.append(cloneItem); //cloneItem->updateItemSize(m_datasources); } } m_renderPageItem->restoreLinks(); m_renderPageItem->updateSubItemsSize(FirstPass,m_datasources); // foreach(BaseDesignIntf* item, pageItems){ // item->updateItemSize(m_datasources); // } } qreal ReportRender::calcPageFooterHeight(PageItemDesignIntf *patternPage) { BandDesignIntf* band = patternPage->bandByType(BandDesignIntf::PageFooter); if (band){ if (m_datasources->variable("#PAGE")!=1) return band->height(); else if (band->property("printOnFirstPage").toBool()) return band->height(); } return 0; } void ReportRender::renderChildHeader(BandDesignIntf *parent, BandPrintMode printMode) { foreach(BandDesignIntf* band,parent->childrenByType(BandDesignIntf::SubDetailHeader)){ bool printAlways=false; if (band->metaObject()->indexOfProperty("printAlways")>0){ printAlways=band->property("printAlways").toBool(); } if (printAlways == (printMode==PrintAlwaysPrintable) ) renderBand(band, 0, StartNewPageAsNeeded); } } void ReportRender::renderChildFooter(BandDesignIntf *parent, BandPrintMode printMode) { foreach(BandDesignIntf* band,parent->childrenByType(BandDesignIntf::SubDetailFooter)){ bool printAlways=false; if (band->metaObject()->indexOfProperty("printAlways")>0){ printAlways=band->property("printAlways").toBool(); } if ( (band != m_lastRenderedFooter) && (printAlways == (printMode == PrintAlwaysPrintable)) ) renderBand(band, 0, StartNewPageAsNeeded); } } void ReportRender::renderChildBands(BandDesignIntf *parentBand) { foreach(BandDesignIntf* band,parentBand->childrenByType(BandDesignIntf::SubDetailBand)){ IDataSource* ds = 0; if (!band->datasourceName().isEmpty()) ds = m_datasources->dataSource(band->datasourceName()); if (ds) ds->first(); renderChildHeader(band,PrintAlwaysPrintable); renderDataBand(band); renderChildFooter(band,PrintAlwaysPrintable); closeFooterGroup(band); } } void ReportRender::renderGroupHeader(BandDesignIntf *parentBand, IDataSource* dataSource, bool firstTime) { foreach(BandDesignIntf* band,parentBand->childrenByType(BandDesignIntf::GroupHeader)){ IGroupBand* gb = dynamic_cast(band); if (gb&&gb->isNeedToClose(m_datasources)){ if (band->childBands().count()>0){ bool didGoBack = dataSource->prior(); foreach (BandDesignIntf* subBand, band->childrenByType(BandDesignIntf::GroupHeader)) { foreach(BandDesignIntf* footer, subBand->childrenByType(BandDesignIntf::GroupFooter)){ renderBand(footer, 0); closeDataGroup(subBand); } } foreach (BandDesignIntf* footer, band->childrenByType(BandDesignIntf::GroupFooter)) { renderBand(footer, 0, StartNewPageAsNeeded); } if (didGoBack){ dataSource->next(); } } closeDataGroup(band); // if (gb->isNeedToStartNewPage()){ // savePage(); // startNewPage(); // } } if (gb && !gb->isStarted()){ if (band->reprintOnEachPage()) m_reprintableBands.append(band); gb->startGroup(m_datasources); openDataGroup(band); if (!firstTime && gb->startNewPage()){ if (gb->resetPageNumber()) resetPageNumber(BandReset); renderBand(band, 0, ForcedStartPage); } else { renderBand(band, 0, StartNewPageAsNeeded); } } renderGroupHeader(band, dataSource, firstTime); } } void ReportRender::renderGroupFooterByHeader(BandDesignIntf* groupHeader){ foreach (BandDesignIntf* header, groupHeader->childrenByType(BandDesignIntf::GroupHeader)){ renderGroupFooterByHeader(header); } foreach (BandDesignIntf* footer, groupHeader->childrenByType(BandDesignIntf::GroupFooter)){ renderBand(footer, 0, StartNewPageAsNeeded); } } void ReportRender::renderGroupFooter(BandDesignIntf *parentBand) { foreach(BandDesignIntf* band,parentBand->childrenByType(BandDesignIntf::GroupHeader)){ IGroupBand* gb = dynamic_cast(band); if (gb && gb->isStarted()){ if (band->reprintOnEachPage()) m_reprintableBands.removeOne(band); foreach(BandDesignIntf* header, band->childrenByType(BandDesignIntf::GroupHeader)){ renderGroupFooterByHeader(header); } foreach(BandDesignIntf* footer, band->childrenByType(BandDesignIntf::GroupFooter)){ renderBand(footer, 0, StartNewPageAsNeeded); } closeDataGroup(band); } } } void ReportRender::initGroups() { m_datasources->clearGroupFunction(); foreach(BandDesignIntf* band, m_patternPageItem->childBands()){ if (band->isFooter()) extractGroupFunctions(band); if (band->isHeader()){ IGroupBand* gb = dynamic_cast(band); if (gb) gb->closeGroup(); } } } void ReportRender::popPageFooterGroupValues(BandDesignIntf *dataBand) { BandDesignIntf* pageFooter = m_patternPageItem->bandByType(BandDesignIntf::PageFooter); if (pageFooter){ foreach(GroupFunction* gf, datasources()->groupFunctionsByBand(pageFooter->objectName())){ if ((gf->dataBandName()==dataBand->objectName())){ // FIXME Probably coincidence Field and Variables if ((!m_popupedExpression.contains(dataBand))||(!m_popupedExpression.values(dataBand).contains(gf->data()))){ m_popupedExpression.insert(dataBand,gf->data()); m_popupedValues.insert(QString("%1").arg((quintptr)dataBand)+'|'+gf->data(), gf->values()[gf->values().count()-1]); gf->values().pop_back(); } } } } } void ReportRender::pushPageFooterGroupValues(BandDesignIntf *dataBand) { BandDesignIntf* pageFooter = m_patternPageItem->bandByType(BandDesignIntf::PageFooter); if (pageFooter){ foreach(GroupFunction* gf, datasources()->groupFunctionsByBand(pageFooter->objectName())){ if ((gf->dataBandName()==dataBand->objectName())){ // FIXME Probably coincidence Field and Variables if ((m_popupedExpression.contains(dataBand))&&(m_popupedExpression.values(dataBand).contains(gf->data()))){ gf->values().push_back(m_popupedValues.value(QString("%1").arg((quintptr)dataBand)+'|'+gf->data())); } } } } } void ReportRender::closeGroup(BandDesignIntf *band) { QMultiMap< BandDesignIntf*, GroupBandsHolder* >::iterator it; it = m_childBands.find(band); while (it!=m_childBands.end()&&it.key()==band){ GroupBandsHolder* bl = it.value(); if (bl){ bl->clear(); delete bl; } it++; } m_childBands.remove(band); } void ReportRender::openDataGroup(BandDesignIntf *band) { m_childBands.insert(band,new GroupBandsHolder(band->tryToKeepTogether())); } void ReportRender::openFooterGroup(BandDesignIntf *band) { GroupBandsHolder* holder = new GroupBandsHolder(true); holder->setIsFooterGroup(); m_childBands.insert(band,holder); } void ReportRender::closeDataGroup(BandDesignIntf *band) { IGroupBand* groupBand = dynamic_cast(band); if (groupBand){ groupBand->closeGroup(); if (band->reprintOnEachPage()) m_reprintableBands.removeOne(band); } closeGroup(band); } void ReportRender::closeFooterGroup(BandDesignIntf *band){ closeGroup(band); } qreal maxVectorValue(QVector vector){ qreal curValue = 0; foreach (qreal value, vector) { if (curValue vector){ qreal curValue = vector[0]; foreach (qreal value, vector) { if (curValue>value) curValue=value; } return curValue; } bool ReportRender::registerBand(BandDesignIntf *band, bool registerInChildren) { if (band->columnsCount()==1 && m_maxHeightByColumn.size()>1){ if (band->bandType()!=BandDesignIntf::PageFooter){ rearrangeColumnsItems(); m_currentColumn = 0; qreal minValue = minVectorValue(m_maxHeightByColumn); m_maxHeightByColumn.clear(); m_maxHeightByColumn.append(minValue); qreal maxValue = maxVectorValue(m_currentStartDataPos); m_currentStartDataPos.clear(); m_currentStartDataPos.append(maxValue); } } if ( (band->columnsCount()>1) && !band->isHeader()){ if (m_maxHeightByColumn.size()!=band->columnsCount()){ for(int i=1;icolumnsCount();++i){ m_maxHeightByColumn.append(m_maxHeightByColumn[0]); m_currentStartDataPos.append(m_currentStartDataPos[0]); } m_currentColumn = 0; } else { if (band->columnsFillDirection()==BandDesignIntf::Horizontal){ if (m_currentColumncolumnsCount()-1) m_currentColumn = m_currentColumn+1; else m_currentColumn = 0; } } } if (band->height()<=m_maxHeightByColumn[m_currentColumn]){ if (band->bandType()==BandDesignIntf::PageFooter){ for (int i=0;iheight(); } else { m_maxHeightByColumn[m_currentColumn]-=band->height(); } if (band->isHeader() && band->columnsCount()>1){ qreal bandPos = m_currentStartDataPos[m_currentColumn]; m_currentStartDataPos[m_currentColumn]+=band->height(); for (int i=0;icolumnsCount();++i){ if (i!=0) band = dynamic_cast(band->cloneItem(PreviewMode)); band->setPos(m_renderPageItem->pageRect().x()+band->width()*i,bandPos); band->setBandIndex(++m_currentIndex); band->setColumnIndex(i); m_renderPageItem->registerBand(band); } } else { if (band->bandType()!=BandDesignIntf::PageFooter){ band->setPos(m_renderPageItem->pageRect().x()+band->width()*m_currentColumn, m_currentStartDataPos[m_currentColumn]); m_currentStartDataPos[m_currentColumn]+=band->height(); band->setBandIndex(++m_currentIndex); band->setColumnIndex(m_currentColumn); } if (band->columnsCount()>1){ m_columnedBandItems.append(band); } m_renderPageItem->registerBand(band); } foreach(QList* list,m_childBands.values()){ if (registerInChildren && band->bandType()!=BandDesignIntf::PageHeader && band->bandType()!=BandDesignIntf::PageFooter && band->bandType()!=BandDesignIntf::ReportHeader && band->bandType()!=BandDesignIntf::ReportFooter && !list->contains(band) && !band->reprintOnEachPage() ) list->append(band); } if (band->isData()) m_renderedDataBandCount++; band->setObjectName(band->objectName()+QString::number(++m_curentNameIndex)); renameChildItems(band); return true; } else return false; } qreal ReportRender::calcSlicePercent(qreal height){ return (height*3/(m_dataAreaSize))/100; } BandDesignIntf* ReportRender::sliceBand(BandDesignIntf *band, BandDesignIntf* patternBand, bool isLast) { while (band->height()>m_maxHeightByColumn[m_currentColumn]) { band = saveUppperPartReturnBottom(band,m_maxHeightByColumn[m_currentColumn],patternBand); if (!band->isEmpty()) { if (band->autoHeight()){ if (band->isNeedUpdateSize(FirstPass)){ band->setHeight(0); } band->updateItemSize(m_datasources); } DataBandDesignIntf* data = dynamic_cast(band); if (isLast && data && data->keepFooterTogether() && band->height()sliceLastRow() ){ if (band->height()>(m_maxHeightByColumn[m_currentColumn]-m_reportFooterHeight)){ m_maxHeightByColumn[m_currentColumn] -= ((m_maxHeightByColumn[m_currentColumn]-band->height())+(band->height()*calcSlicePercent(band->height()))); } } if (registerBand(band)) break; } else break; } if (band->isEmpty()) { delete band; band = 0; } return band; } void ReportRender::secondRenderPass(ReportPages renderedPages) { for(int i=0; isetReportVariable("#PAGE_COUNT",findLastPageNumber(i)); foreach(BaseDesignIntf* item, page->childBaseItems()){ item->updateItemSize(m_datasources, SecondPass); } // foreach(BandDesignIntf* band, page->childBands()){ // band->updateItemSize(m_datasources, SecondPass); // } } } BandDesignIntf *ReportRender::saveUppperPartReturnBottom(BandDesignIntf *band, int height, BandDesignIntf* patternBand) { int sliceHeight = height; BandDesignIntf* upperBandPart = dynamic_cast(band->cloneUpperPart(sliceHeight)); BandDesignIntf* bottomBandPart = dynamic_cast(band->cloneBottomPart(sliceHeight)); if (!bottomBandPart->isEmpty()){ //bottomBandPart->updateItemSize(FirstPass,height); if (patternBand->keepFooterTogether()) closeFooterGroup(patternBand); } if (!upperBandPart->isEmpty()){ upperBandPart->updateItemSize(m_datasources, FirstPass, height); registerBand(upperBandPart); } else delete upperBandPart; if (band->columnsCount()>1 && (band->columnsFillDirection()==BandDesignIntf::Vertical || band->columnsFillDirection()==BandDesignIntf::VerticalUniform)){ startNewColumn(); } else { savePage(); startNewPage(); } // if (!bottomBandPart->isEmpty() && patternBand->keepFooterTogether()) // openFooterGroup(patternBand); delete band; return bottomBandPart; } BandDesignIntf *ReportRender::renderData(BandDesignIntf *patternBand) { BandDesignIntf* bandClone = dynamic_cast(patternBand->cloneItem(PreviewMode)); baseDesignIntfToScript(bandClone); emit(patternBand->beforeRender()); if (patternBand->isFooter()){ replaceGroupsFunction(bandClone); } bandClone->updateItemSize(m_datasources); baseDesignIntfToScript(bandClone); emit(patternBand->afterData()); return bandClone; } void ReportRender::startNewColumn(){ if (m_currentColumn < m_maxHeightByColumn.size()-1){ m_currentColumn++; } else { savePage(); startNewPage(); } } void ReportRender::startNewPage() { m_renderPageItem=0; m_currentColumn=0; initColumns(); initRenderPage(); baseDesignIntfToScript(m_renderPageItem); m_renderPageItem->setObjectName(QLatin1String("ReportPage")+QString::number(m_pageCount)); m_maxHeightByColumn[m_currentColumn]=m_renderPageItem->pageRect().height(); m_currentStartDataPos[m_currentColumn]=m_patternPageItem->topMargin()*Const::mmFACTOR; m_currentIndex=0; emit m_patternPageItem->beforeRender(); renderPageHeader(m_patternPageItem); m_pageFooterHeight = calcPageFooterHeight(m_patternPageItem); m_maxHeightByColumn[m_currentColumn] -= m_pageFooterHeight; m_currentIndex=10; m_dataAreaSize = m_maxHeightByColumn[m_currentColumn]; m_renderedDataBandCount = 0; foreach (BandDesignIntf* band, m_reprintableBands) { renderBand(band, 0); } checkLostHeadersOnPrevPage(); pasteGroups(); } void ReportRender::resetPageNumber(ResetPageNuberType resetType) { PagesRange range; if (!m_ranges.isEmpty()){ m_ranges.last().lastPage = (resetType == BandReset)? m_pageCount : m_pageCount-1; range.firstPage = m_pageCount+((resetType == BandReset)? 1 : 0); } else { range.firstPage = m_pageCount; } range.lastPage = (resetType == BandReset)? 0 : m_pageCount; m_ranges.append(range); if (resetType == PageReset) m_datasources->setReportVariable("#PAGE",1); } int ReportRender::findLastPageNumber(int currentPage) { foreach (PagesRange range, m_ranges) { if ( range.firstPage<= (currentPage) && range.lastPage>= (currentPage) ) return (range.lastPage-(range.firstPage))+1; } return 0; } void ReportRender::cutGroups() { m_popupedExpression.clear(); m_popupedValues.clear(); foreach(BandDesignIntf* groupBand,m_childBands.keys()){ if (m_childBands.value(groupBand)->tryToKeepTogether()){ foreach(BandDesignIntf* band, *m_childBands.value(groupBand)){ m_renderPageItem->removeBand(band); popPageFooterGroupValues(band); band->setParent(0); band->setParentItem(0); } } } } void ReportRender::checkFooterGroup(BandDesignIntf *groupBand) { if (m_childBands.contains(groupBand)){ GroupBandsHolder* holder = m_childBands.value(groupBand); foreach(BandDesignIntf* band, *holder){ qreal percent = band->height()*100 / m_dataAreaSize; if (m_renderedDataBandCount<=1 || percent>20 ){ holder->removeAll(band); } } } } void ReportRender::pasteGroups() { BandDesignIntf* groupBand = findEnclosingGroup(); if (groupBand){ foreach(BandDesignIntf* band, *m_childBands.value(groupBand)){ registerBand(band,false); if (band->isData()) m_renderedDataBandCount++; pushPageFooterGroupValues(band); } foreach(GroupBandsHolder* holder, m_childBands.values()) holder->setTryToKeepTogether(false); } m_popupedExpression.clear(); m_popupedValues.clear(); } void ReportRender::checkLostHeadersOnPrevPage() { if (m_renderedPages.isEmpty()) return; PageItemDesignIntf::Ptr page = m_renderedPages.last(); if (page->bands().isEmpty()) return; QMutableListIteratorit(page->bands()); it.toBack(); if (it.hasPrevious()){ if (it.previous()->isFooter()){ if (it.hasPrevious()) it.previous(); else return; } } while (it.hasPrevious()){ if (it.value()->isHeader()){ if (it.value()->reprintOnEachPage()){ delete it.value(); } else { registerBand(it.value());} it.remove(); it.previous(); } else break; } } BandDesignIntf* ReportRender::findEnclosingGroup() { BandDesignIntf* result=0; int groupIndex = -1; if (!m_childBands.isEmpty()){ foreach(BandDesignIntf* gb, m_childBands.keys()){ if (m_childBands.value(gb)->tryToKeepTogether()&& ((gb->bandIndex()bandIndex(); } } } return result; } void ReportRender::moveTearOffBand(){ BandDesignIntf* tearOffBand = m_renderPageItem->bandByType(BandDesignIntf::TearOffBand); if (tearOffBand){ BandDesignIntf* pageFooter = m_renderPageItem->bandByType(BandDesignIntf::PageFooter); if (pageFooter){ tearOffBand->setItemPos(m_patternPageItem->pageRect().x(), m_patternPageItem->pageRect().bottom()-(tearOffBand->height()+pageFooter->height())); } else { tearOffBand->setItemPos(m_patternPageItem->pageRect().x(),m_patternPageItem->pageRect().bottom()-tearOffBand->height()); } } } void ReportRender::savePage(bool isLast) { renderPageItems(m_patternPageItem); checkFooterGroup(m_lastDataBand); cutGroups(); rearrangeColumnsItems(); m_columnedBandItems.clear(); BandDesignIntf* pf = m_patternPageItem->bandByType(BandDesignIntf::PageFooter); if (pf && m_datasources->variable("#PAGE").toInt()!=1 && !isLast){ renderPageFooter(m_patternPageItem); } else { if (pf && pf->property("printOnFirstPage").toBool() && m_datasources->variable("#PAGE").toInt()==1){ renderPageFooter(m_patternPageItem); } else if(pf && pf->property("printOnLastPage").toBool() && isLast){ renderPageFooter(m_patternPageItem); } } if (m_ranges.last().lastPage==0 && m_ranges.count()>1) { m_datasources->setReportVariable("#PAGE",1); } else { m_datasources->setReportVariable("#PAGE",m_datasources->variable("#PAGE").toInt()+1); } m_ranges.last().lastPage = m_pageCount; BandDesignIntf* pageFooter = m_renderPageItem->bandByType(BandDesignIntf::PageFooter); if (pageFooter) pageFooter->setBandIndex(++m_currentIndex); m_renderedPages.append(PageItemDesignIntf::Ptr(m_renderPageItem)); m_pageCount++; emit pageRendered(m_pageCount); if (isLast){ BandDesignIntf* ph = m_renderPageItem->bandByType(BandDesignIntf::PageHeader); if (ph && !ph->property("printOnLastPage").toBool()){ delete ph; } } moveTearOffBand(); emit m_patternPageItem->afterRender(); } QString ReportRender::toString() { QScopedPointer writer(new XMLWriter()); foreach(PageItemDesignIntf::Ptr page,m_renderedPages){ writer->putItem(page.data()); } return writer->saveToString(); } ReportRender::~ReportRender(){ m_renderedPages.clear(); } void ReportRender::cancelRender(){ m_renderCanceled = true; } void ReportRender::baseDesignIntfToScript(BaseDesignIntf *item) { if ( item ) { if (item->metaObject()->indexOfSignal("beforeRender()")!=-1) item->disconnect(SIGNAL(beforeRender())); if (item->metaObject()->indexOfSignal("afterData()")!=-1) item->disconnect(SIGNAL(afterData())); if (item->metaObject()->indexOfSignal("afterRender()")!=-1) item->disconnect(SIGNAL(afterRender())); QScriptEngine* engine = ScriptEngineManager::instance().scriptEngine(); QScriptValue sItem = engine->globalObject().property(item->patternName()); if (sItem.isValid()){ engine->newQObject(sItem, item); } else { sItem = engine->newQObject(item); engine->globalObject().setProperty(item->patternName(),sItem); } foreach(BaseDesignIntf* child, item->childBaseItems()){ baseDesignIntfToScript(child); } } } }