/*************************************************************************** * This file is part of the Lime Report project * * Copyright (C) 2021 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 "lrreportrender.h" #include "lrbanddesignintf.h" #include "lrglobal.h" #include "lritemdesignintf.h" #include "lrpagedesignintf.h" #include "lrscriptenginemanager.h" #include "serializators/lrxmlreader.h" #include "serializators/lrxmlwriter.h" #include #include namespace LimeReport { void ReportRender::initColumns() { m_maxHeightByColumn.clear(); m_currentStartDataPos.clear(); m_maxHeightByColumn.append(0); m_currentStartDataPos.append(0); m_currentColumn = 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; i < m_maxHeightByColumn.size(); ++i) { qreal maxHeight = 0; int maxHeightColumn = 0; if (m_maxHeightByColumn[i] > maxHeight) { maxHeight = m_maxHeightByColumn[i]; maxHeightColumn = i; } if (maxHeightColumn > 0 && columnItemsCount(maxHeightColumn) < avg && maxHeight > lastColumnItem(maxHeightColumn - 1)->height()) { return true; } } return false; } BandDesignIntf* ReportRender::lastColumnItem(int columnIndex) { if (columnIndex < 0) return 0; for (int i = 0; i < m_columnedBandItems.size(); ++i) { if (m_columnedBandItems[i]->columnIndex() > 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; i < m_columnedBandItems[0]->columnsCount(); ++i) { if (columnItemsCount(i) < avg) { int getCount = avg * (m_columnedBandItems[0]->columnsCount() - i) - columnItemsCount(i); for (int j = 0; j < getCount; ++j) { BandDesignIntf* band = lastColumnItem(i - 1); band->setPos(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; i < m_columnedBandItems.size(); ++i) { if (m_columnedBandItems[i]->columnIndex() == 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; i < m_columnedBandItems[0]->columnsCount(); ++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_currentNameIndex)); } } ReportRender::ReportRender(QObject* parent): QObject(parent), m_renderPageItem(0), m_pageCount(0), m_lastRenderedHeader(0), m_lastDataBand(0), m_lastRenderedFooter(0), m_lastRenderedBand(0), m_currentColumn(0), m_newPageStarted(false), m_lostHeadersMoved(false) { initColumns(); } void ReportRender::setDatasources(DataSourceManager* value) { m_datasources = value; initVariables(); resetPageNumber(BandReset); } void ReportRender::setScriptContext(ScriptEngineContext* scriptContext) { m_scriptEngineContext = scriptContext; } 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::analizeItem(ContentItemDesignIntf* contentItem, BandDesignIntf* band) { Q_UNUSED(band) if (contentItem) { QString content = contentItem->content(); QVector functions; foreach (const QString& functionName, m_datasources->groupFunctionNames()) { #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1) QRegularExpression rx = getGroupFunctionRegEx(functionName); if (content.indexOf(rx) >= 0) { functions.append(functionName); } #else QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName)); rx.setMinimal(true); if (rx.indexIn(content) >= 0) { functions.append(functionName); } #endif } if (functions.size() > 0) m_groupfunctionItems.insert(contentItem->patternName(), functions); } } void ReportRender::analizeContainer(BaseDesignIntf* item, BandDesignIntf* band) { if (item) { foreach (BaseDesignIntf* child, item->childBaseItems()) { ContentItemDesignIntf* contentItem = dynamic_cast(child); if (contentItem) analizeItem(contentItem, band); else analizeContainer(child, band); } } } void ReportRender::analizePage(PageItemDesignIntf* patternPage) { m_groupfunctionItems.clear(); foreach (BandDesignIntf* band, patternPage->bands()) { if (band->isFooter() || band->isHeader()) { analizeContainer(band, band); } } } void ReportRender::renderPage(PageItemDesignIntf* patternPage, bool isTOC, bool /*isFirst*/, bool /*resetPageNumbers*/) { m_currentNameIndex = 0; m_patternPageItem = patternPage; analizePage(patternPage); if (m_patternPageItem->resetPageNumber() && m_pageCount > 0 && !isTOC) { resetPageNumber(PageReset); } if (m_patternPageItem->resetPageNumber() && !isTOC && m_pageCount == 0) { m_pagesRanges.startNewRange(); } m_renderCanceled = false; BandDesignIntf* reportFooter = m_patternPageItem->bandByType(BandDesignIntf::ReportFooter); m_reportFooterHeight = 0; if (reportFooter) m_reportFooterHeight = reportFooter->height(); initGroups(); clearPageMap(); try { datasources()->setAllDatasourcesToFirst(); datasources()->clearGroupFuntionsExpressions(); } catch (ReportError& exception) { // TODO possible should thow exeption QMessageBox::critical(0, tr("Error"), exception.what()); return; } clearPageMap(); startNewPage(true); renderReportHeader(m_patternPageItem, AfterPageHeader); BandDesignIntf* lastRenderedBand = 0; for (int i = 0; i < m_patternPageItem->dataBandCount() && !m_renderCanceled; i++) { lastRenderedBand = m_patternPageItem->dataBandAt(i); initDatasource(lastRenderedBand->datasourceName()); renderDataBand(lastRenderedBand); if (i < m_patternPageItem->dataBandCount() - 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); } 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(PageItemDesignIntf* patternPage) { renderPage(patternPage); return toString(); } ReportPages ReportRender::renderPageToPages(PageItemDesignIntf* patternPage) { renderPage(patternPage); return m_renderedPages; } ReportPages ReportRender::renderTOC(PageItemDesignIntf* patternPage, bool first, bool resetPages) { renderPage(patternPage, true, first, resetPages); 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()); m_renderPageItem->setPatternItem(m_patternPageItem); ScriptValueType svCurrentPage; ScriptEngineType* se = ScriptEngineManager::instance().scriptEngine(); #ifdef USE_QJSENGINE svCurrentPage = getJSValue(*se, m_renderPageItem); se->globalObject().setProperty("currentPage", svCurrentPage); #else svCurrentPage = se->globalObject().property("currentPage"); if (svCurrentPage.isValid()) { se->newQObject(svCurrentPage, m_renderPageItem); } else { svCurrentPage = se->newQObject(m_renderPageItem); se->globalObject().setProperty("currentPage", svCurrentPage); } #endif } } void ReportRender::initVariables() { m_datasources->setReportVariable("#PAGE", 1); m_datasources->setReportVariable("#PAGE_COUNT", 0); m_datasources->setReportVariable("#IS_LAST_PAGEFOOTER", false); m_datasources->setReportVariable("#IS_FIRST_PAGEFOOTER", false); } void ReportRender::clearPageMap() { m_renderedPages.clear(); } bool checkContentItem(ContentItemDesignIntf* item, DataSourceManager* datasources) { QString content = item->content(); foreach (QString functionName, datasources->groupFunctionNames()) { #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1) QRegularExpression rx = getGroupFunctionRegEx(functionName); if (content.indexOf(rx) >= 0) { return true; } #else QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName)); if (rx.indexIn(content) >= 0) { return true; } #endif } return false; } bool ReportRender::containsGroupFunctions(BaseDesignIntf* container) { if (container) { foreach (BaseDesignIntf* item, container->childBaseItems()) { ContentItemDesignIntf* contentItem = dynamic_cast(item); if (contentItem) { if (checkContentItem(contentItem, m_datasources)) return true; } else { if (containsGroupFunctions(item)) return true; } } } return false; } void ReportRender::extractGroupFuntionsFromItem(ContentItemDesignIntf* contentItem, BandDesignIntf* band) { #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1) if (contentItem && contentItem->content().contains(getScriptRegEx())) { foreach (const QString& functionName, m_datasources->groupFunctionNames()) { QRegularExpression rx = getGroupFunctionRegEx(functionName); QRegularExpression rxName = getGroupFunctionNameRegEx(functionName); QRegularExpressionMatch match = rx.match(contentItem->content()); if (match.hasMatch()) { QRegularExpressionMatchIterator iter = rx.globalMatch(contentItem->content()); while (iter.hasNext()) { match = iter.next(); QVector captures = normalizeCaptures(match); 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*))); connect(dataBand, SIGNAL(bandReRendered(BandDesignIntf*, BandDesignIntf*)), gf, SLOT(slotBandReRendered(BandDesignIntf*, 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))); } } } } else if (contentItem->content().indexOf(rxName) >= 0) { match = rxName.match(contentItem->content()); GroupFunction* gf = datasources()->addGroupFunction(functionName, match.captured(1), band->objectName(), ""); gf->setInvalid(tr("Wrong using function %1").arg(functionName)); } } } #else if (contentItem && contentItem->content().contains(QRegExp("\\$S\\s*\\{.*\\}"))) { foreach (const QString& functionName, m_datasources->groupFunctionNames()) { QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName)); rx.setMinimal(true); QRegExp rxName(QString(Const::GROUP_FUNCTION_NAME_RX).arg(functionName)); rxName.setMinimal(true); 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*))); connect(dataBand, SIGNAL(bandReRendered(BandDesignIntf*, BandDesignIntf*)), gf, SLOT(slotBandReRendered(BandDesignIntf*, 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)); } } } #endif } void ReportRender::extractGroupFunctionsFromContainer(BaseDesignIntf* baseItem, BandDesignIntf* band) { if (baseItem) { 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) { if (m_groupfunctionItems.contains(contentItem->patternName())) { QString content = contentItem->content(); foreach (QString functionName, m_groupfunctionItems.value(contentItem->patternName())) { #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1) QRegularExpression rx = getGroupFunctionRegEx(functionName); QRegularExpressionMatch match = rx.match(content); if (match.capturedStart() != -1) { int pos = 0; while ((pos = match.capturedStart()) != -1) { QVector captures = normalizeCaptures(match); if (captures.size() >= 3) { QString expressionIndex = datasources()->putGroupFunctionsExpressions( captures.at(Const::VALUE_INDEX)); if (captures.size() < 5) { content.replace(captures.at(0), QString("%1(%2,%3)") .arg(functionName) .arg('"' + expressionIndex + '"') .arg('"' + band->objectName() + '"')); } else { content.replace(captures.at(0), QString("%1(%2,%3,%4)") .arg(functionName, '"' + expressionIndex + '"', '"' + band->objectName() + '"', captures.at(4))); } } match = rx.match(content, pos + match.capturedLength()); } } #else QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName)); rx.setMinimal(true); 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)); if (captures.size() < 5) { content.replace(captures.at(0), QString("%1(%2,%3)") .arg(functionName) .arg('"' + expressionIndex + '"') .arg('"' + band->objectName() + '"')); } else { content.replace(captures.at(0), QString("%1(%2,%3,%4)") .arg(functionName, '"' + expressionIndex + '"', '"' + band->objectName() + '"', captures.at(4))); } } pos += rx.matchedLength(); } } #endif } contentItem->setContent(content); } } } void ReportRender::replaceGroupFunctionsInContainer(BaseDesignIntf* baseItem, BandDesignIntf* band) { if (baseItem) { 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); } QColor ReportRender::makeBackgroundColor(BandDesignIntf* band) { if (band->useAlternateBackgroundColor()) { return datasources() ->variable(QLatin1String("line_") + band->objectName().toLower()) .toInt() % 2 == 0 ? band->backgroundColor() : band->alternateBackgroundColor(); } return band->backgroundColor(); } BandDesignIntf* ReportRender::renderBand(BandDesignIntf* patternBand, BandDesignIntf* bandData, ReportRender::DataRenderMode mode, bool isLast) { QCoreApplication::processEvents(); bool bandIsSliced = false; if (patternBand) { if (patternBand->isHeader()) m_lastRenderedHeader = patternBand; BandDesignIntf* bandClone = 0; if (bandData) { bandClone = bandData; } else { bandClone = renderData(patternBand); } if (isLast) bandClone->setBottomSpace(1); if (mode == ForcedStartPage) { savePage(); startNewPage(); } if (patternBand->isFooter()) m_lastRenderedFooter = patternBand; bandClone->setBackgroundColor(makeBackgroundColor(bandClone)); patternBand->emitBandRendered(bandClone); m_scriptEngineContext->setCurrentBand(bandClone); 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 (patternBand && patternBand->isHeader() && patternBand->reprintOnEachPage()) m_reprintableBands.removeOne(patternBand); if (bandClone->canBeSplitted(m_maxHeightByColumn[m_currentColumn])) { bandClone = sliceBand(bandClone, patternBand, isLast); bandIsSliced = true; } else { qreal percent = (bandClone->height() - m_maxHeightByColumn[m_currentColumn]) / (bandClone->height() / 100); if (bandClone->maxScalePercent() >= percent) { if (percent < bandClone->maxScalePercent()) { 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(); if (patternBand->bandHeader() && patternBand->bandHeader()->columnsCount() > 1 && !m_lostHeadersMoved && patternBand->bandNestingLevel() == 0) { renderBand(patternBand->bandHeader(), 0, mode); } } else { savePage(); startNewPage(); if (!bandIsSliced) { BandDesignIntf* t = renderData(patternBand, false); t->copyBandAttributes(bandClone); patternBand->emitBandReRendered(bandClone, t); delete bandClone; bandClone = t; } } if (!registerBand(bandClone)) { BandDesignIntf* upperPart = dynamic_cast(bandClone->cloneUpperPart( m_maxHeightByColumn[m_currentColumn])); registerBand(upperPart); patternBand->emitBandReRendered(bandClone, 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()); } emit(patternBand->afterRender()); 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()) renderDataHeader(header); if (bandDatasource && !bandDatasource->eof() && !m_renderCanceled) { QString varName = QLatin1String("line_") + dataBand->objectName().toLower(); datasources()->setReportVariable(varName, 1); if (header && header->reprintOnEachPage()) m_reprintableBands.append(dataBand->bandHeader()); if (header && !header->printAlways()) renderDataHeader(header); renderGroupHeader(dataBand, bandDatasource, true); bool firstTime = true; while (!bandDatasource->eof() && !m_renderCanceled) { datasources()->updateChildrenData(dataBand->datasourceName()); 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); m_lastDataBand = dataBand; if (header && !firstTime && header->repeatOnEachRow()) renderBand(header, 0, StartNewPageAsNeeded); renderBand(dataBand, rawData, StartNewPageAsNeeded, !bandDatasource->hasNext()); m_newPageStarted = false; renderChildBands(dataBand); } bandDatasource->next(); datasources()->setReportVariable(varName, datasources()->variable(varName).toInt() + 1); QList bandList; QList childList; bandList = dataBand->childrenByType(BandDesignIntf::GroupHeader); while (bandList.size() > 0) { childList.clear(); foreach (BandDesignIntf* band, bandList) { childList.append(band->childrenByType(BandDesignIntf::GroupHeader)); QString groupLineVar = QLatin1String("line_") + band->objectName().toLower(); if (datasources()->containsVariable(groupLineVar)) datasources()->setReportVariable( groupLineVar, datasources()->variable(groupLineVar).toInt() + 1); } bandList = childList; } renderGroupHeader(dataBand, bandDatasource, false); if (dataBand->tryToKeepTogether()) closeDataGroup(dataBand); firstTime = false; } if (!dataBand->keepFooterTogether()) m_reprintableBands.removeOne(header); if (header) recalcIfNeeded(header); bool didGoBack = !bandDatasource->eof() && bandDatasource->prior(); renderGroupFooterByHeader(dataBand); if (didGoBack) { bandDatasource->next(); } if (footer && !footer->printAlways()) { renderBand(footer, 0, StartNewPageAsNeeded); if (dataBand->keepFooterTogether()) m_reprintableBands.removeOne(dataBand); } datasources()->deleteVariable(varName); } else if (bandDatasource == 0) { renderBand(dataBand, 0, StartNewPageAsNeeded); } if (footer && footer->printAlways()) { renderBand(footer, 0, StartNewPageAsNeeded); if (dataBand->keepFooterTogether()) m_reprintableBands.removeOne(dataBand); } } 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::renderReportHeader(PageItemDesignIntf* patternPage, PageRenderStage stage) { BandDesignIntf* band = patternPage->bandByType(BandDesignIntf::ReportHeader); BandDesignIntf* resBand = 0; if (band) { if (band->property("printBeforePageHeader").toBool() && stage == BeforePageHeader) resBand = renderBand(band, 0, StartNewPageAsNeeded); if (!band->property("printBeforePageHeader").toBool() && stage == AfterPageHeader) resBand = renderBand(band, 0, StartNewPageAsNeeded); if (resBand && containsGroupFunctions(band)) m_recalcBands.append(resBand); } } 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_renderPageItem->pageRect().x(), m_renderPageItem->pageRect().bottom() - bandClone->height()); bandClone->setHeight(m_pageFooterHeight); for (int i = 0; i < m_maxHeightByColumn.size(); ++i) m_maxHeightByColumn[i] += m_pageFooterHeight; m_renderPageItem->setPageFooter(bandClone); registerBand(bandClone); datasources()->clearGroupFunctionValues(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); } } m_renderPageItem->restoreLinks(); m_renderPageItem->updateSubItemsSize(FirstPass, m_datasources); foreach (BaseDesignIntf* item, pageItems) { if (!item->isWatermark()) item->setZValue(item->zValue() - 100000); else item->setZValue(item->zValue() + 100000); } } 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(); renderDataBand(band); closeFooterGroup(band); } } BandDesignIntf* ReportRender::findRecalcableBand(BandDesignIntf* patternBand) { QList::iterator it = m_recalcBands.begin(); for (; it != m_recalcBands.end(); ++it) { if ((*it)->patternItem() == patternBand) { BandDesignIntf* result = (*it); m_recalcBands.erase(it); return result; } } return 0; } void restoreItemsWithGroupFunctions(BaseDesignIntf* container, DataSourceManager* datasources) { foreach (BaseDesignIntf* bi, container->childBaseItems()) { ContentItemDesignIntf* pci = dynamic_cast(bi->patternItem()); if (pci && checkContentItem(pci, datasources)) { ContentItemDesignIntf* ci = dynamic_cast(bi); ci->setContent(pci->content()); } else restoreItemsWithGroupFunctions(bi, datasources); } } void ReportRender::recalcIfNeeded(BandDesignIntf* band) { BandDesignIntf* recalcBand = findRecalcableBand(band); if (recalcBand) { QString bandName = recalcBand->objectName(); restoreItemsWithGroupFunctions(recalcBand, m_datasources); recalcBand->setObjectName(recalcBand->patternItem()->objectName()); replaceGroupsFunction(recalcBand); recalcBand->updateItemSize(datasources()); recalcBand->setObjectName(bandName); datasources()->clearGroupFunctionValues(recalcBand->patternItem()->objectName()); } } void ReportRender::renderDataHeader(BandDesignIntf* header) { recalcIfNeeded(header); BandDesignIntf* renderedHeader = renderBand(header, 0, StartNewPageAsNeeded); if (containsGroupFunctions(header)) m_recalcBands.append(renderedHeader); } 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(datasources())) { if (band->childBands().count() > 0) { bool didGoBack = !dataSource->eof() && dataSource->prior(); renderGroupFooterByHeader(band); if (didGoBack) { dataSource->next(); } } closeDataGroup(band); } if (gb && !gb->isStarted()) { if (band->reprintOnEachPage()) { m_reprintableBands.append(band); } gb->startGroup(m_datasources); openDataGroup(band); BandDesignIntf* renderedHeader = 0; if (!firstTime && gb->startNewPage() && !m_newPageStarted) { if (gb->resetPageNumber()) resetPageNumber(BandReset); if (band->reprintOnEachPage()) { savePage(); startNewPage(); } else { renderedHeader = renderBand(band, 0, ForcedStartPage); } } else { renderedHeader = renderBand(band, 0, StartNewPageAsNeeded); } if (containsGroupFunctions(band)) m_recalcBands.append(renderedHeader); } renderGroupHeader(band, dataSource, firstTime); } } void ReportRender::renderGroupFooterByHeader(BandDesignIntf* groupHeader) { if (groupHeader->reprintOnEachPage()) m_reprintableBands.removeOne(groupHeader); foreach (BandDesignIntf* header, groupHeader->childrenByType(BandDesignIntf::GroupHeader)) { renderGroupFooterByHeader(header); } foreach (BandDesignIntf* footer, groupHeader->childrenByType(BandDesignIntf::GroupFooter)) { renderBand(footer, 0, StartNewPageAsNeeded); } closeDataGroup(groupHeader); } void ReportRender::renderGroupFooter(BandDesignIntf* parentBand) { foreach (BandDesignIntf* band, parentBand->childrenByType(BandDesignIntf::GroupHeader)) { IGroupBand* gb = dynamic_cast(band); if (gb && gb->isStarted()) { renderGroupFooterByHeader(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(); extractGroupFunctions(band); } } } 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::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); QList::Iterator it = m_reprintableBands.begin(); while (it != m_reprintableBands.end()) { if ((*it)->bandIndex() > band->bandIndex()) it = m_reprintableBands.erase(it); else ++it; } } recalcIfNeeded(band); closeGroup(band); } void ReportRender::closeFooterGroup(BandDesignIntf* band) { closeGroup(band); } qreal maxVectorValue(QVector vector) { qreal curValue = 0; foreach (qreal value, vector) { if (curValue < value) curValue = value; } return curValue; } qreal minVectorValue(QVector vector) { qreal curValue = vector[0]; foreach (qreal value, vector) { if (curValue > value) curValue = value; } return curValue; } void ReportRender::placeBandOnPage(BandDesignIntf* band, int columnIndex) { qreal bandPos = m_currentStartDataPos[columnIndex]; m_currentStartDataPos[columnIndex] += band->height(); m_maxHeightByColumn[columnIndex] -= band->height(); band->setPos(m_renderPageItem->pageRect().x() + band->width() * columnIndex, bandPos); band->setBandIndex(++m_currentIndex); band->setColumnIndex(columnIndex); m_renderPageItem->registerBand(band); m_currentColumn = columnIndex; } bool isMultiColumnHeader(BandDesignIntf* band) { return ((band->columnsCount() > 1) && (band->isHeader() && ((band->bandNestingLevel() == 0) || (band->columnsFillDirection() == BandDesignIntf::Horizontal)))); } 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() != m_maxHeightByColumn.size()) { for (int i = 1; i < band->columnsCount(); ++i) { m_maxHeightByColumn.append(m_maxHeightByColumn[0]); m_currentStartDataPos.append(m_currentStartDataPos[0]); } m_currentColumn = -1; } if ((band->columnsCount() > 1) && (!band->isHeader() || (band->bandNestingLevel() > 0 && band->columnsFillDirection() != BandDesignIntf::Horizontal))) { if (band->columnsFillDirection() == BandDesignIntf::Horizontal) { if (m_currentColumn < band->columnsCount() - 1) m_currentColumn = m_currentColumn + 1; else m_currentColumn = 0; } else { m_currentColumn = m_currentColumn == -1 ? 0 : m_currentColumn; if ((m_currentColumn != 0) && (m_maxHeightByColumn[0] == m_maxHeightByColumn[m_currentColumn]) && (m_maxHeightByColumn[0] >= band->height())) { m_currentColumn = 0; } } } m_currentColumn = m_currentColumn == -1 ? 0 : m_currentColumn; if ((band->height() <= m_maxHeightByColumn[m_currentColumn]) || m_patternPageItem->endlessHeight() || (isMultiColumnHeader(band) && (band->height() <= m_maxHeightByColumn[0]))) { if ((band->bandType() == BandDesignIntf::PageFooter)) { for (int i = 0; i < m_maxHeightByColumn.size(); ++i) m_maxHeightByColumn[i] += band->height(); } if (isMultiColumnHeader(band)) { if (!band->parent()) { for (int i = 0; i < band->columnsCount(); ++i) { m_currentColumn = i; if (i != 0) band = dynamic_cast(band->cloneItem(PreviewMode)); placeBandOnPage(band, i); } } else { placeBandOnPage(band, band->columnIndex()); } } else { if (band->bandType() != BandDesignIntf::PageFooter) { placeBandOnPage(band, m_currentColumn); } if (band->columnsCount() > 1) { m_columnedBandItems.append(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_currentNameIndex)); renameChildItems(band); if (m_lastDataBand) { #if QT_VERSION < 0x050000 m_lastDataBand->metaObject()->invokeMethod(m_lastDataBand, "bandRegistred"); #else emit m_lastDataBand->bandRegistred(); #endif } if (band->bandType() != BandDesignIntf::PageFooter) m_lastRenderedBand = 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() < m_maxHeightByColumn[m_currentColumn] && band->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::updateTOC(BaseDesignIntf* item, int pageNumber) { BookmarkContainerDesignIntf* bookmarkContainer = dynamic_cast(item); if (bookmarkContainer) { TableOfContents* toc = m_scriptEngineContext->tableOfContents(); foreach (QString key, bookmarkContainer->bookmarks()) { toc->setItem(key, bookmarkContainer->getBookMark(key).toString(), pageNumber); } } } void ReportRender::secondRenderPass(ReportPages renderedPages) { if (!m_scriptEngineContext->tableOfContents()->isEmpty()) { for (int i = 0; i < renderedPages.count(); ++i) { PageItemDesignIntf::Ptr page = renderedPages.at(i); updateTOC(page.data(), m_pagesRanges.findPageNumber(i)); foreach (BaseDesignIntf* item, page->childBaseItems()) { updateTOC(item, m_pagesRanges.findPageNumber(i)); } } } for (int i = 0; i < renderedPages.count(); ++i) { PageItemDesignIntf::Ptr page = renderedPages.at(i); m_datasources->setReportVariable("#PAGE", m_pagesRanges.findPageNumber(i)); m_datasources->setReportVariable("#PAGE_COUNT", m_pagesRanges.findLastPageNumber(i)); foreach (BaseDesignIntf* item, page->childBaseItems()) { if (item->isNeedUpdateSize(SecondPass)) item->updateItemSize(m_datasources, SecondPass); } } } void ReportRender::createTOCMarker(bool startNewRange) { m_pagesRanges.addTOCMarker(startNewRange); } BandDesignIntf* ReportRender::saveUppperPartReturnBottom(BandDesignIntf* band, int height, BandDesignIntf* patternBand) { // int sliceHeight = height; BandDesignIntf* upperBandPart = dynamic_cast(band->cloneUpperPart(height)); BandDesignIntf* bottomBandPart = dynamic_cast(band->cloneBottomPart(height)); if (!bottomBandPart->isEmpty()) { if (patternBand->keepFooterTogether()) closeFooterGroup(patternBand); if (upperBandPart->isEmpty()) bottomBandPart->copyBookmarks(band); } if (!upperBandPart->isEmpty()) { upperBandPart->setBottomSpace(0); upperBandPart->updateItemSize(m_datasources, FirstPass, height); registerBand(upperBandPart); upperBandPart->copyBookmarks(band); if (patternBand->isFooter()) closeFooterGroup(m_lastDataBand); } else delete upperBandPart; if (band->columnsCount() > 1 && (band->columnsFillDirection() == BandDesignIntf::Vertical || band->columnsFillDirection() == BandDesignIntf::VerticalUniform)) { startNewColumn(); if (patternBand->bandHeader() && patternBand->bandHeader()->columnsCount() > 1 && !m_lostHeadersMoved && patternBand->bandNestingLevel() == 0) { renderBand(patternBand->bandHeader(), 0, StartNewPageAsNeeded); } } else { savePage(); startNewPage(); } delete band; return bottomBandPart; } BandDesignIntf* ReportRender::renderData(BandDesignIntf* patternBand, bool emitBeforeRender) { BandDesignIntf* bandClone = dynamic_cast(patternBand->cloneItem(PreviewMode)); m_scriptEngineContext->baseDesignIntfToScript(patternBand->parent()->objectName(), bandClone); m_scriptEngineContext->setCurrentBand(bandClone); if (emitBeforeRender) emit(patternBand->beforeRender()); if (patternBand->isFooter()) { replaceGroupsFunction(bandClone); } if (patternBand->isHeader()) { replaceGroupsFunction(bandClone); } emit(patternBand->preparedForRender()); bandClone->setBottomSpace(patternBand->height() - patternBand->findMaxBottom()); bandClone->updateItemSize(m_datasources); // m_scriptEngineContext->baseDesignIntfToScript(bandClone); emit(patternBand->afterData()); return bandClone; } void ReportRender::startNewColumn() { if (m_currentColumn < m_maxHeightByColumn.size() - 1) { m_currentColumn++; checkLostHeadersInPrevColumn(); } else { savePage(); startNewPage(); } } void ReportRender::startNewPage(bool isFirst) { m_renderPageItem = 0; m_newPageStarted = true; initColumns(); initRenderPage(); m_scriptEngineContext->setCurrentPage(m_renderPageItem); m_scriptEngineContext->baseDesignIntfToScript(m_renderPageItem->patternName(), m_renderPageItem); emit m_patternPageItem->beforeRender(); 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; if (isFirst) { renderReportHeader(m_patternPageItem, BeforePageHeader); emit m_patternPageItem->beforeFirstPageRendered(); } renderPageHeader(m_patternPageItem); m_pageFooterHeight = calcPageFooterHeight(m_patternPageItem) + 2; 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) { m_pagesRanges.startNewRange(); if (resetType == PageReset) m_datasources->setReportVariable("#PAGE", 1); } void ReportRender::cutGroups() { m_popupedExpression.clear(); m_popupedValues.clear(); // foreach(BandDesignIntf* groupBand,m_childBands.keys()){ 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(); } bool bandLessThen(BandDesignIntf* b1, BandDesignIntf* b2) { return b1->bandIndex() < b2->bandIndex(); } void ReportRender::checkLostHeadersOnPrevPage() { QVector lostHeaders; if (m_renderedPages.isEmpty()) return; PageItemDesignIntf::Ptr page = m_renderedPages.last(); if (page->bands().isEmpty()) return; QMutableListIterator it(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 { lostHeaders.append(it.value()); } it.remove(); it.previous(); } else break; } if (lostHeaders.size() > 0) { m_lostHeadersMoved = true; // std::sort(lostHeaders.begin(), lostHeaders.end(), bandLessThen); std::sort(lostHeaders.begin(), lostHeaders.end(), bandLessThen); foreach (BandDesignIntf* header, lostHeaders) { registerBand(header); } } else { m_lostHeadersMoved = false; } } void ReportRender::checkLostHeadersInPrevColumn() { QVector lostHeaders; QMutableListIterator it(m_renderPageItem->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 { lostHeaders.append(it.value()); } it.remove(); it.previous(); } else break; } if (lostHeaders.size() > 0) { m_lostHeadersMoved = true; // std::sort(lostHeaders.begin(), lostHeaders.end(), bandLessThen); std::sort(lostHeaders.begin(), lostHeaders.end(), bandLessThen); foreach (BandDesignIntf* header, lostHeaders) { registerBand(header); } } else { m_lostHeadersMoved = false; } } 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() < groupIndex) || (groupIndex == -1))) { result = gb; groupIndex = result->bandIndex(); } } } return result; } void ReportRender::savePage(bool isLast) { m_datasources->setReportVariable("#IS_LAST_PAGEFOOTER", isLast); m_datasources->setReportVariable("#IS_FIRST_PAGEFOOTER", m_datasources->variable("#PAGE").toInt() == 1); renderPageItems(m_patternPageItem); if (m_renderPageItem->isEmpty() && m_renderPageItem->notPrintIfEmpty()) return; if (m_renderPageItem->isTOC()) m_pagesRanges.addTOCPage(); else m_pagesRanges.addPage(); 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_pagesRanges.currentRange(m_patternPageItem->isTOC()).firstPage == 0) { m_datasources->setReportVariable("#PAGE", 1); } else { m_datasources->setReportVariable("#PAGE", m_datasources->variable("#PAGE").toInt() + 1); } 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; } } if (m_renderPageItem->pageFooter()) { m_renderPageItem->pageFooter()->setBandIndex(++m_currentIndex); if (m_renderPageItem->pageFooter()->property("removeGap").toBool()) { m_renderPageItem->pageFooter()->setPos(m_lastRenderedBand->geometry().bottomLeft()); } } m_renderPageItem->placeTearOffBand(); // m_scriptEngineContext->setCurrentPage(m_renderPageItem); emit m_patternPageItem->afterRender(); if (isLast) emit m_patternPageItem->afterLastPageRendered(); if (isLast && m_patternPageItem->endlessHeight()) { qreal pageHeight = 0; foreach (BandDesignIntf* band, m_renderPageItem->bands()) { pageHeight += band->height(); } m_renderPageItem->setHeight( pageHeight + 10 + (m_patternPageItem->topMargin() + m_patternPageItem->bottomMargin()) * Const::mmFACTOR); } } 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; } int PagesRanges::findLastPageNumber(int index) { index++; foreach (PagesRange range, m_ranges) { if (range.firstPage <= (index) && range.lastPage >= (index)) return (range.lastPage - (range.firstPage)) + 1; } return 0; } int PagesRanges::findPageNumber(int index) { index++; foreach (PagesRange range, m_ranges) { if (range.firstPage <= (index) && range.lastPage >= (index)) return (index - range.firstPage) + 1; } return 0; } PagesRange& PagesRanges::currentRange(bool isTOC) { Q_ASSERT((isTOC && m_TOCRangeIndex != -1) || !isTOC); if (isTOC && m_TOCRangeIndex != -1) return m_ranges[m_TOCRangeIndex]; return m_ranges.last(); } void PagesRanges::startNewRange(bool isTOC) { PagesRange range; if (!m_ranges.isEmpty()) { range.firstPage = 0; range.lastPage = m_ranges.last().lastPage + 1; } else { range.firstPage = 0; range.lastPage = 0; } range.isTOC = isTOC; m_ranges.append(range); if (isTOC) m_TOCRangeIndex = m_ranges.size() - 1; } void PagesRanges::addTOCMarker(bool addNewRange) { if (addNewRange || m_ranges.isEmpty()) { startNewRange(true); } else { m_TOCRangeIndex = m_ranges.size() - 1; m_ranges.last().isTOC = true; } } void PagesRanges::addPage() { if (m_ranges.isEmpty()) startNewRange(); if (m_ranges.last().firstPage == 0) { m_ranges.last().firstPage = m_ranges.last().lastPage == 0 ? 1 : m_ranges.last().lastPage; m_ranges.last().lastPage = m_ranges.last().lastPage == 0 ? 1 : m_ranges.last().lastPage; } else { m_ranges.last().lastPage++; } } void PagesRanges::shiftRangesNextToTOC() { for (int i = m_TOCRangeIndex + 1; i < m_ranges.size(); ++i) { m_ranges[i].firstPage++; m_ranges[i].lastPage++; } } void PagesRanges::addTOCPage() { Q_ASSERT(m_TOCRangeIndex != -1); if (m_TOCRangeIndex != -1) { PagesRange& tocRange = m_ranges[m_TOCRangeIndex]; if (tocRange.firstPage == 0) { tocRange.firstPage = tocRange.lastPage == 0 ? 1 : tocRange.lastPage; tocRange.lastPage = tocRange.lastPage == 0 ? 1 : tocRange.lastPage; if (tocRange.firstPage == 1 && tocRange.lastPage == 1) shiftRangesNextToTOC(); } else { tocRange.lastPage++; shiftRangesNextToTOC(); } } } void PagesRanges::clear() { m_ranges.clear(); } } // namespace LimeReport