1 /***************************************************************************
2  *   This file is part of the Lime Report project                          *
3  *   Copyright (C) 2015 by Alexander Arin                                  *
4  *   arin_a@bk.ru                                                          *
5  *                                                                         *
6  **                   GNU General Public License Usage                    **
7  *                                                                         *
8  *   This library is free software: you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation, either version 3 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *   You should have received a copy of the GNU General Public License     *
13  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
14  *                                                                         *
15  **                  GNU Lesser General Public License                    **
16  *                                                                         *
17  *   This library is free software: you can redistribute it and/or modify  *
18  *   it under the terms of the GNU Lesser General Public License as        *
19  *   published by the Free Software Foundation, either version 3 of the    *
20  *   License, or (at your option) any later version.                       *
21  *   You should have received a copy of the GNU Lesser General Public      *
22  *   License along with this library.                                      *
23  *   If not, see <http://www.gnu.org/licenses/>.                           *
24  *                                                                         *
25  *   This library is distributed in the hope that it will be useful,       *
26  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
27  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
28  *   GNU General Public License for more details.                          *
29  ****************************************************************************/
30 #include <stdexcept>
31 #include <QMessageBox>
32 
33 #include "lrglobal.h"
34 #include "lrreportrender.h"
35 #include "lrpagedesignintf.h"
36 #include "lrbanddesignintf.h"
37 #include "lritemdesignintf.h"
38 #include "lrscriptenginemanager.h"
39 
40 #include "serializators/lrxmlreader.h"
41 #include "serializators/lrxmlwriter.h"
42 
43 namespace LimeReport{
44 
initColumns()45 void ReportRender::initColumns(){
46     m_maxHeightByColumn.clear();
47     m_currentStartDataPos.clear();
48     m_maxHeightByColumn.append(0);
49     m_currentStartDataPos.append(0);
50     m_currentColumn = 0;
51 }
52 
isNeedToRearrangeColumnsItems()53 bool ReportRender::isNeedToRearrangeColumnsItems()
54 {
55     if (m_columnedBandItems.size()<=1) return false;
56     if (m_columnedBandItems[0]->columnsFillDirection()!=BandDesignIntf::VerticalUniform)
57         return false;
58 
59     int avg = m_columnedBandItems.size()/m_columnedBandItems[0]->columnsCount();
60 
61     for (int i=0;i<m_maxHeightByColumn.size();++i){
62         qreal maxHeight = 0;
63         int maxHeightColumn = 0;
64         if (m_maxHeightByColumn[i]>maxHeight){
65             maxHeight = m_maxHeightByColumn[i];
66             maxHeightColumn = i;
67         }
68         if (maxHeightColumn>0 && columnItemsCount(maxHeightColumn)<avg &&
69                 maxHeight> lastColumnItem(maxHeightColumn-1)->height()
70         ){
71           return true;
72         }
73     }
74     return false;
75 }
76 
lastColumnItem(int columnIndex)77 BandDesignIntf *ReportRender::lastColumnItem(int columnIndex)
78 {
79     if (columnIndex<0) return 0;
80     for(int i=0;i<m_columnedBandItems.size();++i){
81        if (m_columnedBandItems[i]->columnIndex()>columnIndex)
82            return m_columnedBandItems[i-1];
83     }
84     return m_columnedBandItems.last();
85 }
86 
rearrangeColumnsItems()87 void ReportRender::rearrangeColumnsItems()
88 {
89     if (isNeedToRearrangeColumnsItems()){
90         qreal startHeight = columnHeigth(0);
91         int avg = m_columnedBandItems.size() / m_columnedBandItems[0]->columnsCount();
92         for (int i = 1; i < m_columnedBandItems[0]->columnsCount(); ++i){
93            if (columnItemsCount(i) < avg){
94                int getCount = avg * (m_columnedBandItems[0]->columnsCount()-i) - columnItemsCount(i);
95                for (int j = 0; j < getCount; ++j){
96                    BandDesignIntf* band = lastColumnItem(i-1);
97                    band->setPos(band->pos().x()+band->width(),m_columnedBandItems[0]->pos().y());
98                    band->setColumnIndex(i);
99                }
100 
101            }
102         }
103         m_renderPageItem->relocateBands();
104         m_maxHeightByColumn[0]+=startHeight-maxColumnHeight();
105         m_currentStartDataPos[0]-=startHeight-maxColumnHeight();
106         m_columnedBandItems.clear();
107     }
108 }
109 
columnItemsCount(int columnIndex)110 int ReportRender::columnItemsCount(int columnIndex)
111 {
112     int result = 0;
113     foreach(BandDesignIntf* band, m_columnedBandItems){
114         if (band->columnIndex()==columnIndex)
115             ++result;
116         if (band->columnIndex()>columnIndex) break;
117     }
118     return result;
119 }
120 
columnHeigth(int columnIndex)121 qreal ReportRender::columnHeigth(int columnIndex)
122 {
123     qreal result = 0;
124     for(int i=0;i<m_columnedBandItems.size();++i){
125        if (m_columnedBandItems[i]->columnIndex()==columnIndex)
126            result += m_columnedBandItems[i]->height();
127        if (m_columnedBandItems[i]->columnIndex()>columnIndex) break;
128     }
129     return result;
130 }
131 
maxColumnHeight()132 qreal ReportRender::maxColumnHeight()
133 {
134     qreal result = 0;
135     for (int i=0;i<m_columnedBandItems[0]->columnsCount();++i){
136         qreal curColumnHeight = columnHeigth(i);
137         if (curColumnHeight>result) result = curColumnHeight;
138     }
139     return result;
140 }
141 
renameChildItems(BaseDesignIntf * item)142 void ReportRender::renameChildItems(BaseDesignIntf *item){
143     foreach(BaseDesignIntf* child, item->childBaseItems()){
144         if (!child->childBaseItems().isEmpty()) renameChildItems(child);
145         child->setObjectName(child->metaObject()->className()+QString::number(++m_currentNameIndex));
146     }
147 }
148 
ReportRender(QObject * parent)149 ReportRender::ReportRender(QObject *parent)
150     :QObject(parent), m_renderPageItem(0), m_pageCount(0),
151     m_lastRenderedHeader(0), m_lastDataBand(0), m_lastRenderedFooter(0),
152     m_currentColumn(0), m_newPageStarted(false), m_lostHeadersMoved(false)
153 {
154     initColumns();
155 }
156 
setDatasources(DataSourceManager * value)157 void ReportRender::setDatasources(DataSourceManager *value)
158 {
159     m_datasources=value;
160     initVariables();
161     resetPageNumber(BandReset);
162 }
163 
setScriptContext(ScriptEngineContext * scriptContext)164 void ReportRender::setScriptContext(ScriptEngineContext* scriptContext)
165 {
166     m_scriptEngineContext=scriptContext;
167 }
168 
initDatasources()169 void ReportRender::initDatasources(){
170     try{
171         datasources()->setAllDatasourcesToFirst();
172     } catch(ReportError &exception){
173         //TODO possible should thow exeption
174         QMessageBox::critical(0,tr("Error"),exception.what());
175         return;
176     }
177 }
178 
initDatasource(const QString & name)179 void ReportRender::initDatasource(const QString& name){
180     try{
181         if (datasources()->containsDatasource(name)){
182             IDataSource* ds = datasources()->dataSource(name);
183             if (ds)
184                 ds->first();
185         }
186     } catch(ReportError &exception){
187         QMessageBox::critical(0,tr("Error"),exception.what());
188         return;
189     }
190 }
191 
analizeItem(ContentItemDesignIntf * contentItem,BandDesignIntf * band)192 void ReportRender::analizeItem(ContentItemDesignIntf* contentItem, BandDesignIntf* band){
193     if (contentItem){
194         QString content = contentItem->content();
195         QVector<QString> functions;
196         foreach(const QString &functionName, m_datasources->groupFunctionNames()){
197             QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName));
198             rx.setMinimal(true);
199             if (rx.indexIn(content)>=0){
200                 functions.append(functionName);
201             }
202         }
203         if (functions.size()>0)
204             m_groupfunctionItems.insert(contentItem->patternName(), functions);
205     }
206 }
207 
analizeContainer(BaseDesignIntf * item,BandDesignIntf * band)208 void ReportRender::analizeContainer(BaseDesignIntf* item, BandDesignIntf* band){
209     foreach(BaseDesignIntf* child, item->childBaseItems()){
210         ContentItemDesignIntf* contentItem = dynamic_cast<ContentItemDesignIntf*>(child);
211         if (contentItem) analizeItem(contentItem, band);
212         else analizeContainer(child, band);
213     }
214 }
215 
analizePage(PageItemDesignIntf * patternPage)216 void ReportRender::analizePage(PageItemDesignIntf* patternPage){
217     m_groupfunctionItems.clear();
218     foreach(BandDesignIntf* band, patternPage->bands()){
219         if (band->isFooter() || band->isHeader()){
220             analizeContainer(band,band);
221         }
222     }
223 }
224 
renderPage(PageItemDesignIntf * patternPage,bool isTOC,bool,bool)225 void ReportRender::renderPage(PageItemDesignIntf* patternPage, bool isTOC, bool /*isFirst*/, bool /*resetPageNumbers*/)
226 {
227     m_currentNameIndex = 0;
228     m_patternPageItem = patternPage;
229 
230     analizePage(patternPage);
231 
232     if (m_patternPageItem->resetPageNumber() && m_pageCount>0 && !isTOC) {
233         resetPageNumber(PageReset);
234     }
235 
236     if (m_patternPageItem->resetPageNumber() && !isTOC && m_pageCount == 0){
237         m_pagesRanges.startNewRange();
238     }
239 
240     m_renderCanceled = false;
241     BandDesignIntf* reportFooter = m_patternPageItem->bandByType(BandDesignIntf::ReportFooter);
242     m_reportFooterHeight = 0;
243     if (reportFooter)
244         m_reportFooterHeight = reportFooter->height();
245 
246     initGroups();
247     clearPageMap();
248 
249     try{
250         datasources()->setAllDatasourcesToFirst();
251         datasources()->clearGroupFuntionsExpressions();
252     } catch(ReportError &exception){
253         //TODO possible should thow exeption
254         QMessageBox::critical(0,tr("Error"),exception.what());
255         return;
256     }
257 
258     clearPageMap();
259     startNewPage(true);
260 
261     renderReportHeader(m_patternPageItem, AfterPageHeader);
262 
263     BandDesignIntf* lastRenderedBand = 0;
264     for (int i=0;i<m_patternPageItem->dataBandCount() && !m_renderCanceled; i++){
265         lastRenderedBand = m_patternPageItem->dataBandAt(i);
266         initDatasource(lastRenderedBand->datasourceName());
267         renderDataBand(lastRenderedBand);
268         if (i < m_patternPageItem->dataBandCount()-1) closeFooterGroup(lastRenderedBand);
269     }
270 
271     if (reportFooter)
272         renderBand(reportFooter, 0, StartNewPageAsNeeded);
273     if (lastRenderedBand && lastRenderedBand->keepFooterTogether())
274         closeFooterGroup(lastRenderedBand);
275 
276     BandDesignIntf* tearOffBand = m_patternPageItem->bandByType(BandDesignIntf::TearOffBand);
277     if (tearOffBand)
278         renderBand(tearOffBand, 0, StartNewPageAsNeeded);
279 
280     savePage(true);
281 
282 }
283 
pageCount()284 int ReportRender::pageCount()
285 {
286     return m_renderedPages.count();
287 }
288 
pageAt(int index)289 PageItemDesignIntf::Ptr ReportRender::pageAt(int index)
290 {
291     if ((index>m_renderedPages.count()-1)||(index<0)) throw ReportError(tr("page index out of range"));
292     else return m_renderedPages.at(index);
293 }
294 
renderPageToString(PageItemDesignIntf * patternPage)295 QString ReportRender::renderPageToString(PageItemDesignIntf *patternPage)
296 {
297     renderPage(patternPage);
298     return toString();
299 }
300 
renderPageToPages(PageItemDesignIntf * patternPage)301 ReportPages ReportRender::renderPageToPages(PageItemDesignIntf *patternPage)
302 {
303     renderPage(patternPage);
304     return m_renderedPages;
305 }
306 
renderTOC(PageItemDesignIntf * patternPage,bool first,bool resetPages)307 ReportPages ReportRender::renderTOC(PageItemDesignIntf* patternPage, bool first, bool resetPages){
308     renderPage(patternPage, true, first, resetPages);
309     return m_renderedPages;
310 }
311 
initRenderPage()312 void ReportRender::initRenderPage()
313 {
314     if (!m_renderPageItem) {
315         m_renderPageItem = new PageItemDesignIntf(m_patternPageItem->pageSize(), m_patternPageItem->pageRect());
316         m_renderPageItem->initFromItem(m_patternPageItem);
317         m_renderPageItem->setItemMode(PreviewMode);
318         m_renderPageItem->setPatternName(m_patternPageItem->objectName());
319         m_renderPageItem->setPatternItem(m_patternPageItem);
320 
321         ScriptValueType svCurrentPage;
322         ScriptEngineType* se = ScriptEngineManager::instance().scriptEngine();
323 
324 #ifdef USE_QJSENGINE
325         svCurrentPage = getJSValue(*se, m_renderPageItem);
326         se->globalObject().setProperty("currentPage", svCurrentPage);
327 #else
328         svCurrentPage = se->globalObject().property("currentPage");
329         if (svCurrentPage.isValid()){
330             se->newQObject(svCurrentPage, m_renderPageItem);
331         } else {
332             svCurrentPage = se->newQObject(m_renderPageItem);
333             se->globalObject().setProperty("currentPage", svCurrentPage);
334         }
335 #endif
336 
337 
338     }
339 }
340 
initVariables()341 void ReportRender::initVariables()
342 {
343     m_datasources->setReportVariable("#PAGE",1);
344     m_datasources->setReportVariable("#PAGE_COUNT",0);
345     m_datasources->setReportVariable("#IS_LAST_PAGEFOOTER",false);
346     m_datasources->setReportVariable("#IS_FIRST_PAGEFOOTER",false);
347 }
348 
clearPageMap()349 void ReportRender::clearPageMap()
350 {
351     m_renderedPages.clear();
352 }
353 
containsGroupFunctions(BandDesignIntf * band)354 bool ReportRender::containsGroupFunctions(BandDesignIntf *band){
355     foreach(BaseDesignIntf* item,band->childBaseItems()){
356         ContentItemDesignIntf* contentItem = dynamic_cast<ContentItemDesignIntf*>(item);
357         if (contentItem){
358             QString content = contentItem->content();
359             foreach(QString functionName, m_datasources->groupFunctionNames()){
360                 QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName));
361                 if (rx.indexIn(content)>=0){
362                     return true;
363                 }
364             }
365         }
366     }
367     return false;
368 }
369 
extractGroupFuntionsFromItem(ContentItemDesignIntf * contentItem,BandDesignIntf * band)370 void ReportRender::extractGroupFuntionsFromItem(ContentItemDesignIntf* contentItem, BandDesignIntf* band){
371     if ( contentItem && contentItem->content().contains(QRegExp("\\$S\\s*\\{.*\\}"))){
372         foreach(const QString &functionName, m_datasources->groupFunctionNames()){
373             QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName));
374             rx.setMinimal(true);
375             QRegExp rxName(QString(Const::GROUP_FUNCTION_NAME_RX).arg(functionName));
376             rxName.setMinimal(true);
377             if (rx.indexIn(contentItem->content())>=0){
378                 int pos = 0;
379                 while ( (pos = rx.indexIn(contentItem->content(),pos)) != -1){
380                     QVector<QString> captures = normalizeCaptures(rx);
381                     if (captures.size()>=3){
382                         int dsIndex = captures.size() == 3 ? Const::DATASOURCE_INDEX - 1 : Const::DATASOURCE_INDEX;
383                         BandDesignIntf* dataBand = m_patternPageItem->bandByName(captures.at(dsIndex));
384                         if (dataBand){
385                             GroupFunction* gf = datasources()->addGroupFunction(functionName,captures.at(Const::VALUE_INDEX),band->objectName(),dataBand->objectName());
386                             if (gf){
387                                 connect(dataBand,SIGNAL(bandRendered(BandDesignIntf*)),gf,SLOT(slotBandRendered(BandDesignIntf*)));
388                             }
389                         } else {
390                             GroupFunction* gf = datasources()->addGroupFunction(functionName,captures.at(Const::VALUE_INDEX),band->objectName(),captures.at(dsIndex));
391                             gf->setInvalid(tr("Databand \"%1\" not found").arg(captures.at(dsIndex)));
392                         }
393                     }
394                     pos += rx.matchedLength();
395                 }
396             } else if (rxName.indexIn(contentItem->content())>=0){
397                 GroupFunction* gf = datasources()->addGroupFunction(functionName,rxName.cap(1),band->objectName(),"");
398                 gf->setInvalid(tr("Wrong using function %1").arg(functionName));
399             }
400         }
401     }
402 }
403 
extractGroupFunctionsFromContainer(BaseDesignIntf * baseItem,BandDesignIntf * band)404 void ReportRender::extractGroupFunctionsFromContainer(BaseDesignIntf* baseItem, BandDesignIntf* band){
405     foreach (BaseDesignIntf* item, baseItem->childBaseItems()) {
406         ContentItemDesignIntf* contentItem = dynamic_cast<ContentItemDesignIntf*>(item);
407         if (contentItem) extractGroupFuntionsFromItem(contentItem, band);
408         else extractGroupFunctionsFromContainer(item, band);
409     }
410 
411 }
412 
extractGroupFunctions(BandDesignIntf * band)413 void ReportRender::extractGroupFunctions(BandDesignIntf *band)
414 {
415     extractGroupFunctionsFromContainer(band, band);
416 }
417 
replaceGroupFunctionsInItem(ContentItemDesignIntf * contentItem,BandDesignIntf * band)418 void ReportRender::replaceGroupFunctionsInItem(ContentItemDesignIntf* contentItem, BandDesignIntf* band){
419     if (contentItem){
420         if (m_groupfunctionItems.contains(contentItem->patternName())){
421             QString content = contentItem->content();
422             foreach(QString functionName, m_groupfunctionItems.value(contentItem->patternName())){
423                 QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName));
424                 rx.setMinimal(true);
425                 if (rx.indexIn(content)>=0){
426                     int pos = 0;
427                     while ( (pos = rx.indexIn(content,pos))!= -1 ){
428                         QVector<QString> captures = normalizeCaptures(rx);
429                         if (captures.size() >= 3){
430                             QString expressionIndex = datasources()->putGroupFunctionsExpressions(captures.at(Const::VALUE_INDEX));
431                             if (captures.size()<5){
432                                 content.replace(captures.at(0),QString("%1(%2,%3)").arg(functionName).arg('"'+expressionIndex+'"').arg('"'+band->objectName()+'"'));
433                             } else {
434                                 content.replace(captures.at(0),QString("%1(%2,%3,%4)")
435                                                 .arg(functionName)
436                                                 .arg('"'+expressionIndex+'"')
437                                                 .arg('"'+band->objectName()+'"')
438                                                 .arg(captures.at(4)));
439                             }
440                         }
441                         pos += rx.matchedLength();
442                     }
443                 }
444             }
445             contentItem->setContent(content);
446         }
447     }
448 }
449 
replaceGroupFunctionsInContainer(BaseDesignIntf * baseItem,BandDesignIntf * band)450 void ReportRender::replaceGroupFunctionsInContainer(BaseDesignIntf* baseItem, BandDesignIntf* band)
451 {
452     foreach(BaseDesignIntf* item, baseItem->childBaseItems()){
453         ContentItemDesignIntf* contentItem = dynamic_cast<ContentItemDesignIntf*>(item);
454         if (contentItem) replaceGroupFunctionsInItem(contentItem, band);
455         else replaceGroupFunctionsInContainer(item, band);
456     }
457 }
458 
replaceGroupsFunction(BandDesignIntf * band)459 void ReportRender::replaceGroupsFunction(BandDesignIntf *band)
460 {
461     replaceGroupFunctionsInContainer(band, band);
462 }
463 
renderBand(BandDesignIntf * patternBand,BandDesignIntf * bandData,ReportRender::DataRenderMode mode,bool isLast)464 BandDesignIntf* ReportRender::renderBand(BandDesignIntf *patternBand, BandDesignIntf* bandData, ReportRender::DataRenderMode mode, bool isLast)
465 {
466     QCoreApplication::processEvents();
467     bool bandIsSliced = false;
468     if (patternBand){
469 
470         if (patternBand->isHeader())
471             m_lastRenderedHeader = patternBand;
472 
473         BandDesignIntf* bandClone = 0;
474 
475         if (bandData){
476            bandClone = bandData;
477         } else {
478             bandClone = renderData(patternBand);
479         }
480 
481         if (isLast) bandClone->setBootomSpace(1);
482 
483         if (mode == ForcedStartPage){
484             savePage();
485             startNewPage();
486         }
487 
488         if (patternBand->isFooter())
489             m_lastRenderedFooter = patternBand;
490 
491         if (bandClone->useAlternateBackgroundColor()){
492             bandClone->setBackgroundColor(
493                         (datasources()->variable(QLatin1String("line_")+patternBand->objectName().toLower()).toInt() %2 == 0 ?
494                              bandClone->backgroundColor() :
495                              bandClone->alternateBackgroundColor()
496                         )
497             );
498         }
499 
500         patternBand->emitBandRendered(bandClone);
501         m_scriptEngineContext->setCurrentBand(bandClone);
502         emit(patternBand->afterRender());
503 
504         if ( isLast && bandClone->keepFooterTogether() && bandClone->sliceLastRow() ){
505             if (m_maxHeightByColumn[m_currentColumn] < (bandClone->height()+m_reportFooterHeight))
506                 m_maxHeightByColumn[m_currentColumn] -= ((m_maxHeightByColumn[m_currentColumn]-bandClone->height())+(bandClone->height()*calcSlicePercent(bandClone->height())));
507          }
508 
509         if (!bandClone->isEmpty() || patternBand->printIfEmpty()){
510             if (!registerBand(bandClone)){
511                 if (patternBand && patternBand->isHeader() && patternBand->reprintOnEachPage())
512                     m_reprintableBands.removeOne(patternBand);
513                 if (bandClone->canBeSplitted(m_maxHeightByColumn[m_currentColumn])){
514                     bandClone = sliceBand(bandClone, patternBand, isLast);
515                     bandIsSliced = true;
516                 } else {
517                     qreal percent = (bandClone->height()-m_maxHeightByColumn[m_currentColumn])/(bandClone->height()/100);
518                     if (bandClone->maxScalePercent()>=percent){
519                         if (percent<bandClone->maxScalePercent()){
520                             percent += 2;
521                             bandClone->setScale((100-percent)/100);
522                             BandDesignIntf* upperPart = dynamic_cast<BandDesignIntf*>(bandClone->cloneUpperPart(m_maxHeightByColumn[m_currentColumn]));
523                             registerBand(upperPart);
524                             delete bandClone;
525                             bandClone = NULL;
526                         }
527                     } else {
528 
529                         if (mode==StartNewPageAsNeeded){
530                             if (bandClone->columnsCount()>1 &&
531                                 (bandClone->columnsFillDirection()==BandDesignIntf::Vertical ||
532                                  bandClone->columnsFillDirection()==BandDesignIntf::VerticalUniform))
533                             {
534                                 startNewColumn();
535                                 if (patternBand->bandHeader() &&
536                                     patternBand->bandHeader()->columnsCount()>1 &&
537                                     !m_lostHeadersMoved &&
538                                     patternBand->bandNestingLevel() == 0
539                                 ){
540                                     renderBand(patternBand->bandHeader(), 0, mode);
541                                 }
542                             } else {
543                                 savePage();
544                                 startNewPage();
545                                 if (!bandIsSliced){
546                                     BandDesignIntf* t = renderData(patternBand);
547                                     t->copyBookmarks(bandClone);
548                                     delete bandClone;
549                                     bandClone = t;
550                                 }
551                             }
552                             if (!registerBand(bandClone)) {
553                                 BandDesignIntf* upperPart = dynamic_cast<BandDesignIntf*>(bandClone->cloneUpperPart(m_maxHeightByColumn[m_currentColumn]));
554                                 registerBand(upperPart);
555                                 delete bandClone;
556                                 bandClone = NULL;
557                             };
558                         } else {
559                             bandClone->setHeight(m_maxHeightByColumn[m_currentColumn]);
560                             registerBand(bandClone);
561                         }
562                     }
563                 }
564             }
565         } else {
566             delete bandClone;
567             return 0;
568         }
569 
570         if (patternBand->isFooter())
571             datasources()->clearGroupFunctionValues(patternBand->objectName());
572         return bandClone;
573     }
574     return 0;
575 }
576 
renderDataBand(BandDesignIntf * dataBand)577 void ReportRender::renderDataBand(BandDesignIntf *dataBand)
578 {
579     if (dataBand == NULL )
580         return;
581 
582     IDataSource* bandDatasource = 0;
583     m_lastRenderedFooter = 0;
584 
585     if (!dataBand->datasourceName().isEmpty())
586        bandDatasource = datasources()->dataSource(dataBand->datasourceName());
587 
588     BandDesignIntf* header = dataBand->bandHeader();
589     BandDesignIntf* footer = dataBand->bandFooter();
590 
591     if (header && header->printAlways()) renderDataHeader(header);
592 
593     if(bandDatasource && !bandDatasource->eof() && !m_renderCanceled){
594 
595         QString varName = QLatin1String("line_")+dataBand->objectName().toLower();
596         datasources()->setReportVariable(varName,1);
597 
598         if (header && header->reprintOnEachPage())
599             m_reprintableBands.append(dataBand->bandHeader());
600 
601         if (header && !header->printAlways())
602             renderDataHeader(header);
603 
604         renderGroupHeader(dataBand, bandDatasource, true);
605 
606         bool firstTime = true;
607 
608 
609         while(!bandDatasource->eof() && !m_renderCanceled){
610 
611             BandDesignIntf* rawData = renderData(dataBand);
612 
613             if (!rawData->isEmpty() || dataBand->printIfEmpty()){
614 
615                 if ((firstTime && dataBand->startFromNewPage()) ||
616                     (!firstTime && dataBand->startNewPage())) {
617                     savePage();
618                     startNewPage();
619                 }
620 
621                 if (dataBand->tryToKeepTogether()) openDataGroup(dataBand);
622 
623                 if (dataBand->keepFooterTogether() && !bandDatasource->hasNext())
624                     openFooterGroup(dataBand);
625 
626                 datasources()->updateChildrenData(dataBand->datasourceName());
627                 m_lastDataBand = dataBand;
628 
629                 if (header && !firstTime && header->repeatOnEachRow())
630                     renderBand(header, 0, StartNewPageAsNeeded);
631 
632                 renderBand(dataBand, rawData, StartNewPageAsNeeded, !bandDatasource->hasNext());
633                 m_newPageStarted = false;
634                 renderChildBands(dataBand);
635 
636             }
637 
638             bandDatasource->next();
639 
640             datasources()->setReportVariable(varName,datasources()->variable(varName).toInt()+1);
641 
642             QList<BandDesignIntf *> bandList;
643             QList<BandDesignIntf *> childList;
644 
645             bandList = dataBand->childrenByType(BandDesignIntf::GroupHeader);
646             while (bandList.size() > 0)
647             {
648                 childList.clear();
649                 foreach (BandDesignIntf* band, bandList)
650                 {
651                     childList.append(band->childrenByType(BandDesignIntf::GroupHeader));
652 
653                     QString groupLineVar = QLatin1String("line_")+band->objectName().toLower();
654                     if (datasources()->containsVariable(groupLineVar))
655                         datasources()->setReportVariable(groupLineVar,datasources()->variable(groupLineVar).toInt()+1);
656                 }
657                 bandList = childList;
658             }
659 
660             renderGroupHeader(dataBand, bandDatasource, false);
661             if (dataBand->tryToKeepTogether()) closeDataGroup(dataBand);
662             firstTime = false;
663         }
664 
665         if (!dataBand->keepFooterTogether())
666         	m_reprintableBands.removeOne(header);
667         if (header) recalcIfNeeded(header);
668 
669         if (bandDatasource->prior()){
670             renderGroupFooter(dataBand);
671             bandDatasource->next();
672         }
673 
674         if (footer && !footer->printAlways()){
675             renderBand(footer, 0, StartNewPageAsNeeded);
676             if (dataBand->keepFooterTogether())
677                 m_reprintableBands.removeOne(dataBand);
678         }
679 
680         datasources()->deleteVariable(varName);
681 
682     } else if (bandDatasource==0) {
683         renderBand(dataBand, 0, StartNewPageAsNeeded);
684     }
685 
686     if (footer && footer->printAlways()){
687         renderBand(footer, 0, StartNewPageAsNeeded);
688         if (dataBand->keepFooterTogether())
689             m_reprintableBands.removeOne(dataBand);
690     }
691 }
692 
renderPageHeader(PageItemDesignIntf * patternPage)693 void ReportRender::renderPageHeader(PageItemDesignIntf *patternPage)
694 {
695     BandDesignIntf* band = patternPage->bandByType(BandDesignIntf::PageHeader);
696     if (band){
697         if (m_datasources->variable("#PAGE").toInt()!=1 ||
698             band->property("printOnFirstPage").toBool()
699         )
700             renderBand(band, 0);
701     }
702 }
703 
renderReportHeader(PageItemDesignIntf * patternPage,PageRenderStage stage)704 void ReportRender::renderReportHeader(PageItemDesignIntf *patternPage, PageRenderStage stage)
705 {
706     BandDesignIntf* band = patternPage->bandByType(BandDesignIntf::ReportHeader);
707     if (band){
708         if (band->property("printBeforePageHeader").toBool() && stage == BeforePageHeader )
709             renderBand(band, 0, StartNewPageAsNeeded);
710         if (!band->property("printBeforePageHeader").toBool() && stage == AfterPageHeader )
711             renderBand(band, 0, StartNewPageAsNeeded);
712     }
713 }
714 
renderPageFooter(PageItemDesignIntf * patternPage)715 void ReportRender::renderPageFooter(PageItemDesignIntf *patternPage)
716 {
717     BandDesignIntf* band = patternPage->bandByType(BandDesignIntf::PageFooter);
718     if (band){
719         BandDesignIntf* bandClone = dynamic_cast<BandDesignIntf*>(band->cloneItem(PreviewMode, m_renderPageItem, m_renderPageItem));
720         replaceGroupsFunction(bandClone);
721         bandClone->updateItemSize(m_datasources);
722         bandClone->setItemPos(m_renderPageItem->pageRect().x(),m_renderPageItem->pageRect().bottom()-bandClone->height());
723         bandClone->setHeight(m_pageFooterHeight);
724         for(int i=0;i<m_maxHeightByColumn.size();++i)
725             m_maxHeightByColumn[i]+=m_pageFooterHeight;
726         m_renderPageItem->setPageFooter(bandClone);
727         registerBand(bandClone);
728         datasources()->clearGroupFunctionValues(band->objectName());
729     }
730 }
731 
renderPageItems(PageItemDesignIntf * patternPage)732 void ReportRender::renderPageItems(PageItemDesignIntf* patternPage)
733 {
734     QList<BaseDesignIntf*> pageItems;
735     foreach (BaseDesignIntf* item, patternPage->childBaseItems()) {
736         ItemDesignIntf* id = dynamic_cast<ItemDesignIntf*>(item);
737         if (id&&id->itemLocation()==ItemDesignIntf::Page){
738             BaseDesignIntf* cloneItem = item->cloneItem(m_renderPageItem->itemMode(),
739                                                         m_renderPageItem,
740                                                         m_renderPageItem);
741             pageItems.append(cloneItem);
742         }
743     }
744     m_renderPageItem->restoreLinks();
745     m_renderPageItem->updateSubItemsSize(FirstPass,m_datasources);
746     foreach(BaseDesignIntf* item, pageItems){
747         if (!item->isWatermark())
748             item->setZValue(item->zValue()-100000);
749         else
750             item->setZValue(item->zValue()+100000);
751     }
752 }
753 
calcPageFooterHeight(PageItemDesignIntf * patternPage)754 qreal ReportRender::calcPageFooterHeight(PageItemDesignIntf *patternPage)
755 {
756     BandDesignIntf* band = patternPage->bandByType(BandDesignIntf::PageFooter);
757     if (band){
758         if (m_datasources->variable("#PAGE")!=1)
759             return band->height();
760         else if (band->property("printOnFirstPage").toBool())
761             return band->height();
762     }
763     return 0;
764 }
765 
renderChildHeader(BandDesignIntf * parent,BandPrintMode printMode)766 void ReportRender::renderChildHeader(BandDesignIntf *parent, BandPrintMode printMode)
767 {
768     foreach(BandDesignIntf* band,parent->childrenByType(BandDesignIntf::SubDetailHeader)){
769         bool printAlways=false;
770         if (band->metaObject()->indexOfProperty("printAlways")>0){
771             printAlways=band->property("printAlways").toBool();
772         }
773         if (printAlways == (printMode == PrintAlwaysPrintable))
774             renderBand(band, 0, StartNewPageAsNeeded);
775     }
776 }
777 
renderChildFooter(BandDesignIntf * parent,BandPrintMode printMode)778 void ReportRender::renderChildFooter(BandDesignIntf *parent, BandPrintMode printMode)
779 {
780     foreach(BandDesignIntf* band,parent->childrenByType(BandDesignIntf::SubDetailFooter)){
781         bool printAlways=false;
782         if (band->metaObject()->indexOfProperty("printAlways")>0){
783             printAlways=band->property("printAlways").toBool();
784         }
785 
786         if ( (band != m_lastRenderedFooter) && (printAlways == (printMode == PrintAlwaysPrintable)) )
787             renderBand(band, 0, StartNewPageAsNeeded);
788     }
789 }
790 
renderChildBands(BandDesignIntf * parentBand)791 void ReportRender::renderChildBands(BandDesignIntf *parentBand)
792 {
793     foreach(BandDesignIntf* band,parentBand->childrenByType(BandDesignIntf::SubDetailBand)){
794         IDataSource* ds = 0;
795         if (!band->datasourceName().isEmpty())
796             ds = m_datasources->dataSource(band->datasourceName());
797         if (ds) ds->first();
798         renderDataBand(band);
799         closeFooterGroup(band);
800     }
801 }
802 
findRecalcableBand(BandDesignIntf * patternBand)803 BandDesignIntf* ReportRender::findRecalcableBand(BandDesignIntf* patternBand){
804 
805     QList<BandDesignIntf*>::iterator it = m_recalcBands.begin();
806     for (;it !=m_recalcBands.end() ;++it){
807         if ((*it)->patternItem() == patternBand){
808             BandDesignIntf* result = (*it);
809             m_recalcBands.erase(it);
810             return result;
811         }
812     }
813     return 0;
814 }
815 
recalcIfNeeded(BandDesignIntf * band)816 void ReportRender::recalcIfNeeded(BandDesignIntf* band){
817     BandDesignIntf* recalcBand = findRecalcableBand(band);
818     if (recalcBand){
819         QString bandName = recalcBand->objectName();
820         recalcBand->restoreItems();
821         recalcBand->setObjectName(recalcBand->patternItem()->objectName());
822         replaceGroupsFunction(recalcBand);
823         recalcBand->updateItemSize(datasources());
824         recalcBand->setObjectName(bandName);
825         datasources()->clearGroupFunctionValues(recalcBand->patternItem()->objectName());
826     }
827 }
828 
renderDataHeader(BandDesignIntf * header)829 void ReportRender::renderDataHeader(BandDesignIntf *header)
830 {
831     recalcIfNeeded(header);
832     BandDesignIntf* renderedHeader = renderBand(header, 0);
833     if (containsGroupFunctions(header))
834         m_recalcBands.append(renderedHeader);
835 }
836 
renderGroupHeader(BandDesignIntf * parentBand,IDataSource * dataSource,bool firstTime)837 void ReportRender::renderGroupHeader(BandDesignIntf *parentBand, IDataSource* dataSource, bool firstTime)
838 {
839     foreach(BandDesignIntf* band,parentBand->childrenByType(BandDesignIntf::GroupHeader)){
840         IGroupBand* gb = dynamic_cast<IGroupBand*>(band);
841         if (gb&&gb->isNeedToClose(datasources())){
842             if (band->childBands().count()>0){
843                 bool didGoBack = dataSource->prior();
844                 renderGroupFooterByHeader(band);
845                 if (didGoBack){
846                     dataSource->next();
847                 }
848             }
849             closeDataGroup(band);
850         }
851 
852         if (gb && !gb->isStarted()){
853             if (band->reprintOnEachPage()){
854                 m_reprintableBands.append(band);
855             }
856             gb->startGroup(m_datasources);
857             openDataGroup(band);
858             BandDesignIntf* renderedHeader = 0;
859             if (!firstTime && gb->startNewPage() && !m_newPageStarted){
860                 if (gb->resetPageNumber()) resetPageNumber(BandReset);
861                 if (band->reprintOnEachPage()){
862                     savePage();
863                     startNewPage();
864                 } else {
865                     renderedHeader = renderBand(band, 0, ForcedStartPage);
866                 }
867             } else {
868                 renderedHeader = renderBand(band, 0, StartNewPageAsNeeded);
869             }
870             if (containsGroupFunctions(band))
871                 m_recalcBands.append(renderedHeader);
872         }
873 
874         renderGroupHeader(band, dataSource, firstTime);
875     }
876 }
877 
renderGroupFooterByHeader(BandDesignIntf * groupHeader)878 void ReportRender::renderGroupFooterByHeader(BandDesignIntf* groupHeader){
879     if (groupHeader->reprintOnEachPage()) m_reprintableBands.removeOne(groupHeader);
880     foreach (BandDesignIntf* header, groupHeader->childrenByType(BandDesignIntf::GroupHeader)){
881         renderGroupFooterByHeader(header);
882     }
883     foreach (BandDesignIntf* footer, groupHeader->childrenByType(BandDesignIntf::GroupFooter)){
884         renderBand(footer, 0, StartNewPageAsNeeded);
885     }
886     closeDataGroup(groupHeader);
887 }
888 
renderGroupFooter(BandDesignIntf * parentBand)889 void ReportRender::renderGroupFooter(BandDesignIntf *parentBand)
890 {
891     foreach(BandDesignIntf* band,parentBand->childrenByType(BandDesignIntf::GroupHeader)){
892         IGroupBand* gb = dynamic_cast<IGroupBand*>(band);
893         if (gb && gb->isStarted()){
894             renderGroupFooterByHeader(band);
895         }
896     }
897 }
898 
initGroups()899 void ReportRender::initGroups()
900 {
901     m_datasources->clearGroupFunction();
902     foreach(BandDesignIntf* band, m_patternPageItem->childBands()){
903         if (band->isFooter()) extractGroupFunctions(band);
904         if (band->isHeader()){
905             IGroupBand* gb = dynamic_cast<IGroupBand*>(band);
906             if (gb) gb->closeGroup();
907             extractGroupFunctions(band);
908         }
909     }
910 }
911 
popPageFooterGroupValues(BandDesignIntf * dataBand)912 void ReportRender::popPageFooterGroupValues(BandDesignIntf *dataBand)
913 {
914     BandDesignIntf* pageFooter = m_patternPageItem->bandByType(BandDesignIntf::PageFooter);
915     if (pageFooter){
916         foreach(GroupFunction* gf, datasources()->groupFunctionsByBand(pageFooter->objectName())){
917             if ((gf->dataBandName()==dataBand->objectName())){
918                 // FIXME Probably coincidence Field and Variables
919                 if ((!m_popupedExpression.contains(dataBand))||(!m_popupedExpression.values(dataBand).contains(gf->data()))){
920                     m_popupedExpression.insert(dataBand,gf->data());
921                     m_popupedValues.insert(QString("%1").arg((quintptr)dataBand)+'|'+gf->data(), gf->values()[gf->values().count()-1]);
922                     gf->values().pop_back();
923                 }
924             }
925         }
926     }
927 }
928 
pushPageFooterGroupValues(BandDesignIntf * dataBand)929 void ReportRender::pushPageFooterGroupValues(BandDesignIntf *dataBand)
930 {
931     BandDesignIntf* pageFooter = m_patternPageItem->bandByType(BandDesignIntf::PageFooter);
932     if (pageFooter){
933         foreach(GroupFunction* gf, datasources()->groupFunctionsByBand(pageFooter->objectName())){
934             if ((gf->dataBandName()==dataBand->objectName())){
935                 // FIXME Probably coincidence Field and Variables
936                 if ((m_popupedExpression.contains(dataBand))&&(m_popupedExpression.values(dataBand).contains(gf->data()))){
937                     gf->values().push_back(m_popupedValues.value(QString("%1").arg((quintptr)dataBand)+'|'+gf->data()));
938                 }
939             }
940         }
941     }
942 }
943 
closeGroup(BandDesignIntf * band)944 void ReportRender::closeGroup(BandDesignIntf *band)
945 {
946     QMultiMap< BandDesignIntf*, GroupBandsHolder* >::iterator it;
947     it = m_childBands.find(band);
948 
949     while (it!=m_childBands.end()&&it.key()==band){
950         GroupBandsHolder* bl = it.value();
951         if (bl){
952             bl->clear();
953             delete bl;
954         }
955         ++it;
956     }
957 
958     m_childBands.remove(band);
959 }
960 
openDataGroup(BandDesignIntf * band)961 void ReportRender::openDataGroup(BandDesignIntf *band)
962 {
963     m_childBands.insert(band,new GroupBandsHolder(band->tryToKeepTogether()));
964 }
965 
openFooterGroup(BandDesignIntf * band)966 void ReportRender::openFooterGroup(BandDesignIntf *band)
967 {
968     GroupBandsHolder* holder = new GroupBandsHolder(true);
969     holder->setIsFooterGroup();
970     m_childBands.insert(band,holder);
971 }
972 
closeDataGroup(BandDesignIntf * band)973 void ReportRender::closeDataGroup(BandDesignIntf *band)
974 {
975     IGroupBand* groupBand = dynamic_cast<IGroupBand*>(band);
976     if (groupBand){
977         groupBand->closeGroup();
978         if (band->reprintOnEachPage()) m_reprintableBands.removeOne(band);
979 
980         QList<BandDesignIntf*>::Iterator it = m_reprintableBands.begin();
981         while (it != m_reprintableBands.end()){
982             if ((*it)->bandIndex()>band->bandIndex())
983                 it = m_reprintableBands.erase(it);
984             else
985                 ++it;
986         }
987     }
988     recalcIfNeeded(band);
989     closeGroup(band);
990 }
991 
closeFooterGroup(BandDesignIntf * band)992 void ReportRender::closeFooterGroup(BandDesignIntf *band){
993     closeGroup(band);
994 }
995 
maxVectorValue(QVector<qreal> vector)996 qreal maxVectorValue(QVector<qreal> vector){
997     qreal curValue = 0;
998     foreach (qreal value, vector) {
999         if (curValue<value) curValue=value;
1000     }
1001     return curValue;
1002 }
1003 
minVectorValue(QVector<qreal> vector)1004 qreal minVectorValue(QVector<qreal> vector){
1005     qreal curValue = vector[0];
1006     foreach (qreal value, vector) {
1007         if (curValue>value) curValue=value;
1008     }
1009     return curValue;
1010 }
1011 
placeBandOnPage(BandDesignIntf * band,int columnIndex)1012 void ReportRender::placeBandOnPage(BandDesignIntf* band, int columnIndex){
1013 
1014     qreal bandPos = m_currentStartDataPos[columnIndex];
1015 
1016     m_currentStartDataPos[columnIndex] += band->height();
1017     m_maxHeightByColumn[columnIndex] -= band->height();
1018     band->setPos(m_renderPageItem->pageRect().x()+band->width()*columnIndex, bandPos);
1019     band->setBandIndex(++m_currentIndex);
1020     band->setColumnIndex(columnIndex);
1021 
1022     m_renderPageItem->registerBand(band);
1023     m_currentColumn = columnIndex;
1024 }
1025 
isMultiColumnHeader(BandDesignIntf * band)1026 bool isMultiColumnHeader(BandDesignIntf* band){
1027     return ( (band->columnsCount() > 1 ) &&
1028              (band->isHeader() &&
1029              ((band->bandNestingLevel() == 0) || (band->columnsFillDirection() == BandDesignIntf::Horizontal))));
1030 }
1031 
registerBand(BandDesignIntf * band,bool registerInChildren)1032 bool ReportRender::registerBand(BandDesignIntf *band, bool registerInChildren)
1033 {
1034 
1035     if (band->columnsCount() == 1 && m_maxHeightByColumn.size() > 1 ){
1036         if (band->bandType() != BandDesignIntf::PageFooter){
1037             rearrangeColumnsItems();
1038             m_currentColumn = 0;
1039             qreal minValue = minVectorValue(m_maxHeightByColumn);
1040             m_maxHeightByColumn.clear();
1041             m_maxHeightByColumn.append(minValue);
1042             qreal maxValue = maxVectorValue(m_currentStartDataPos);
1043             m_currentStartDataPos.clear();
1044             m_currentStartDataPos.append(maxValue);
1045         }
1046     }
1047 
1048     if (band->columnsCount() != m_maxHeightByColumn.size()){
1049         for(int i=1;i<band->columnsCount();++i){
1050             m_maxHeightByColumn.append(m_maxHeightByColumn[0]);
1051             m_currentStartDataPos.append(m_currentStartDataPos[0]);
1052         }
1053         m_currentColumn = -1;
1054     }
1055 
1056     if ( (band->columnsCount() > 1) &&
1057          (!band->isHeader() || (band->bandNestingLevel() > 0 && band->columnsFillDirection() != BandDesignIntf::Horizontal ))){
1058 
1059         if (band->columnsFillDirection() == BandDesignIntf::Horizontal){
1060             if (m_currentColumn < band->columnsCount()-1)
1061                 m_currentColumn = m_currentColumn+1;
1062             else
1063                 m_currentColumn = 0;
1064         } else {
1065             m_currentColumn = m_currentColumn == -1 ? 0: m_currentColumn;
1066             if ((m_currentColumn !=0) &&
1067                 (m_maxHeightByColumn[0] == m_maxHeightByColumn[m_currentColumn]) &&
1068                 (m_maxHeightByColumn[0] >= band->height())
1069             ){
1070                 m_currentColumn = 0;
1071             }
1072         }
1073     }
1074 
1075     m_currentColumn = m_currentColumn == -1 ? 0: m_currentColumn;
1076 
1077     if (  (band->height() <= m_maxHeightByColumn[m_currentColumn]) ||
1078           m_patternPageItem->endlessHeight() ||
1079           (isMultiColumnHeader(band) && (band->height() <= m_maxHeightByColumn[0]))
1080     ){
1081 
1082         if ( (band->bandType() == BandDesignIntf::PageFooter) ){
1083            for (int i=0; i < m_maxHeightByColumn.size(); ++i)
1084                m_maxHeightByColumn[i]+=band->height();
1085         }
1086 
1087         if ( isMultiColumnHeader(band)){
1088 
1089             if (!band->parent()){
1090                 for (int i = 0; i < band->columnsCount(); ++i){
1091                     m_currentColumn = i;
1092                     if (i != 0) band = dynamic_cast<BandDesignIntf*>(band->cloneItem(PreviewMode));
1093                     placeBandOnPage(band, i);
1094                 }
1095             } else {
1096                 placeBandOnPage(band, band->columnIndex());
1097             }
1098 
1099 
1100         } else {
1101 
1102             if (band->bandType() != BandDesignIntf::PageFooter){
1103                 placeBandOnPage(band, m_currentColumn);
1104             }
1105 
1106             if (band->columnsCount() > 1){
1107                 m_columnedBandItems.append(band);
1108             }
1109 
1110         }
1111 
1112         foreach(QList<BandDesignIntf*>* list, m_childBands.values()){
1113             if (registerInChildren &&
1114                 band->bandType()!=BandDesignIntf::PageHeader &&
1115                 band->bandType()!=BandDesignIntf::PageFooter &&
1116                 band->bandType()!=BandDesignIntf::ReportHeader &&
1117                 band->bandType()!=BandDesignIntf::ReportFooter &&
1118                 !list->contains(band) &&
1119                 !band->reprintOnEachPage()
1120             )
1121                 list->append(band);
1122         }
1123 
1124         if (band->isData()) m_renderedDataBandCount++;
1125         band->setObjectName(band->objectName()+QString::number(++m_currentNameIndex));
1126         renameChildItems(band);
1127         if (m_lastDataBand){
1128 #ifdef HAVE_QT4
1129             m_lastDataBand->metaObject()->invokeMethod(m_lastDataBand,"bandRegistred");
1130 #endif
1131 #ifdef HAVE_QT5
1132             emit m_lastDataBand->bandRegistred();
1133 #endif
1134         }
1135         return true;
1136     } else return false;
1137 }
1138 
calcSlicePercent(qreal height)1139 qreal ReportRender::calcSlicePercent(qreal height){
1140     return (height*3/(m_dataAreaSize))/100;
1141 }
1142 
sliceBand(BandDesignIntf * band,BandDesignIntf * patternBand,bool isLast)1143 BandDesignIntf* ReportRender::sliceBand(BandDesignIntf *band, BandDesignIntf* patternBand, bool isLast)
1144 {
1145     while (band->height()>m_maxHeightByColumn[m_currentColumn]) {
1146         band = saveUppperPartReturnBottom(band,m_maxHeightByColumn[m_currentColumn],patternBand);
1147         if (!band->isEmpty()) {
1148             if (band->autoHeight()){
1149                 if (band->isNeedUpdateSize(FirstPass)){
1150                     band->setHeight(0);
1151                 }
1152                 band->updateItemSize(m_datasources);
1153             }
1154             DataBandDesignIntf* data = dynamic_cast<DataBandDesignIntf*>(band);
1155             if (isLast && data && data->keepFooterTogether() &&
1156                 band->height()<m_maxHeightByColumn[m_currentColumn] && band->sliceLastRow()
1157             ){
1158                 if (band->height()>(m_maxHeightByColumn[m_currentColumn]-m_reportFooterHeight)){
1159                     m_maxHeightByColumn[m_currentColumn] -= ((m_maxHeightByColumn[m_currentColumn]-band->height())+(band->height()*calcSlicePercent(band->height())));
1160                 }
1161             }
1162             if (registerBand(band)) break;
1163         } else break;
1164     }
1165 
1166     if (band->isEmpty()) {
1167         delete band;
1168         band = 0;
1169     }
1170 
1171     return band;
1172 
1173 }
1174 
updateTOC(BaseDesignIntf * item,int pageNumber)1175 void ReportRender::updateTOC(BaseDesignIntf* item, int pageNumber){
1176     BookmarkContainerDesignIntf* bookmarkContainer = dynamic_cast<BookmarkContainerDesignIntf*>(item);
1177     if (bookmarkContainer){
1178         TableOfContents* toc = m_scriptEngineContext->tableOfContents();
1179         foreach (QString key, bookmarkContainer->bookmarks()){
1180             toc->setItem(key, bookmarkContainer->getBookMark(key).toString(), pageNumber);
1181         }
1182     }
1183 }
1184 
secondRenderPass(ReportPages renderedPages)1185 void ReportRender::secondRenderPass(ReportPages renderedPages)
1186 {
1187     if (!m_scriptEngineContext->tableOfContents()->isEmpty()){
1188         for(int i = 0; i < renderedPages.count(); ++i){
1189             PageItemDesignIntf::Ptr page = renderedPages.at(i);
1190             updateTOC(page.data(), m_pagesRanges.findPageNumber(i));
1191             foreach(BaseDesignIntf* item, page->childBaseItems()){
1192                 updateTOC(item, m_pagesRanges.findPageNumber(i));
1193             }
1194         }
1195     }
1196 
1197     for(int i = 0; i < renderedPages.count(); ++i){
1198         PageItemDesignIntf::Ptr page = renderedPages.at(i);
1199         m_datasources->setReportVariable("#PAGE",m_pagesRanges.findPageNumber(i));
1200         m_datasources->setReportVariable("#PAGE_COUNT",m_pagesRanges.findLastPageNumber(i));
1201         foreach(BaseDesignIntf* item, page->childBaseItems()){
1202             if (item->isNeedUpdateSize(SecondPass))
1203                 item->updateItemSize(m_datasources, SecondPass);
1204         }
1205     }
1206 }
1207 
createTOCMarker(bool startNewRange)1208 void ReportRender::createTOCMarker(bool startNewRange)
1209 {
1210     m_pagesRanges.addTOCMarker(startNewRange);
1211 }
1212 
saveUppperPartReturnBottom(BandDesignIntf * band,int height,BandDesignIntf * patternBand)1213 BandDesignIntf *ReportRender::saveUppperPartReturnBottom(BandDesignIntf *band, int height, BandDesignIntf* patternBand)
1214 {
1215     int sliceHeight = height;
1216     BandDesignIntf* upperBandPart = dynamic_cast<BandDesignIntf*>(band->cloneUpperPart(sliceHeight));
1217     BandDesignIntf* bottomBandPart = dynamic_cast<BandDesignIntf*>(band->cloneBottomPart(sliceHeight));
1218     if (!bottomBandPart->isEmpty()){
1219         if (patternBand->keepFooterTogether())
1220             closeFooterGroup(patternBand);
1221         if (upperBandPart->isEmpty())
1222             bottomBandPart->copyBookmarks(band);
1223     }
1224     if (!upperBandPart->isEmpty()){
1225         upperBandPart->updateItemSize(m_datasources, FirstPass, height);
1226         registerBand(upperBandPart);
1227         upperBandPart->copyBookmarks(band);
1228     } else delete upperBandPart;
1229 
1230     if (band->columnsCount()>1 &&
1231         (band->columnsFillDirection()==BandDesignIntf::Vertical ||
1232          band->columnsFillDirection()==BandDesignIntf::VerticalUniform)){
1233         startNewColumn();
1234         if (patternBand->bandHeader() &&
1235             patternBand->bandHeader()->columnsCount()>1 &&
1236             !m_lostHeadersMoved &&
1237             patternBand->bandNestingLevel() == 0
1238         ){
1239             renderBand(patternBand->bandHeader(), 0, StartNewPageAsNeeded);
1240         }
1241 
1242     } else {
1243         savePage();
1244         startNewPage();
1245     }
1246 
1247     delete band;
1248     return bottomBandPart;
1249 }
1250 
renderData(BandDesignIntf * patternBand)1251 BandDesignIntf *ReportRender::renderData(BandDesignIntf *patternBand)
1252 {
1253     BandDesignIntf* bandClone = dynamic_cast<BandDesignIntf*>(patternBand->cloneItem(PreviewMode));
1254 
1255     m_scriptEngineContext->baseDesignIntfToScript(patternBand->parent()->objectName(), bandClone);
1256     m_scriptEngineContext->setCurrentBand(bandClone);
1257     emit(patternBand->beforeRender());
1258 
1259     if (patternBand->isFooter()){
1260         replaceGroupsFunction(bandClone);
1261     }
1262 
1263     if (patternBand->isHeader()){
1264         replaceGroupsFunction(bandClone);
1265     }
1266 
1267     bandClone->updateItemSize(m_datasources);
1268 
1269     //m_scriptEngineContext->baseDesignIntfToScript(bandClone);
1270     emit(patternBand->afterData());
1271 
1272     return bandClone;
1273 }
1274 
startNewColumn()1275 void ReportRender::startNewColumn(){
1276     if (m_currentColumn < m_maxHeightByColumn.size()-1){
1277         m_currentColumn++;
1278         checkLostHeadersInPrevColumn();
1279     } else {
1280         savePage();
1281         startNewPage();
1282     }
1283 }
1284 
startNewPage(bool isFirst)1285 void ReportRender::startNewPage(bool isFirst)
1286 {
1287     m_renderPageItem = 0;
1288     m_newPageStarted = true;
1289     initColumns();
1290     initRenderPage();
1291 
1292     m_scriptEngineContext->baseDesignIntfToScript(m_renderPageItem->patternName(), m_renderPageItem);
1293     emit m_patternPageItem->beforeRender();
1294 
1295     m_renderPageItem->setObjectName(QLatin1String("ReportPage")+QString::number(m_pageCount));
1296     m_maxHeightByColumn[m_currentColumn] = m_renderPageItem->pageRect().height();
1297     m_currentStartDataPos[m_currentColumn] = m_patternPageItem->topMargin() * Const::mmFACTOR;
1298     m_currentIndex = 0;
1299 
1300     if (isFirst) {
1301         renderReportHeader(m_patternPageItem, BeforePageHeader);
1302         emit m_patternPageItem->beforeFirstPageRendered();
1303     }
1304 
1305     renderPageHeader(m_patternPageItem);
1306 
1307     m_pageFooterHeight = calcPageFooterHeight(m_patternPageItem)+2;
1308     m_maxHeightByColumn[m_currentColumn] -= m_pageFooterHeight;
1309     m_currentIndex = 10;
1310     m_dataAreaSize = m_maxHeightByColumn[m_currentColumn];
1311     m_renderedDataBandCount = 0;
1312 
1313     foreach (BandDesignIntf* band, m_reprintableBands) {
1314         renderBand(band, 0);
1315     }
1316 
1317     checkLostHeadersOnPrevPage();
1318     pasteGroups();
1319 
1320 }
1321 
resetPageNumber(ResetPageNuberType resetType)1322 void ReportRender::resetPageNumber(ResetPageNuberType resetType)
1323 {
1324     m_pagesRanges.startNewRange();
1325     if (resetType == PageReset)
1326         m_datasources->setReportVariable("#PAGE",1);
1327 }
1328 
cutGroups()1329 void ReportRender::cutGroups()
1330 {
1331     m_popupedExpression.clear();
1332     m_popupedValues.clear();
1333     foreach(BandDesignIntf* groupBand,m_childBands.keys()){
1334         if (m_childBands.value(groupBand)->tryToKeepTogether()){
1335             foreach(BandDesignIntf* band, *m_childBands.value(groupBand)){
1336                 m_renderPageItem->removeBand(band);
1337                 popPageFooterGroupValues(band);
1338                 band->setParent(0);
1339                 band->setParentItem(0);
1340             }
1341         }
1342     }
1343 
1344 }
1345 
checkFooterGroup(BandDesignIntf * groupBand)1346 void ReportRender::checkFooterGroup(BandDesignIntf *groupBand)
1347 {
1348     if (m_childBands.contains(groupBand)){
1349         GroupBandsHolder* holder = m_childBands.value(groupBand);
1350         foreach(BandDesignIntf* band, *holder){
1351             qreal percent = band->height()*100 / m_dataAreaSize;
1352             if (m_renderedDataBandCount<=1 || percent>20 ){
1353                  holder->removeAll(band);
1354             }
1355         }
1356     }
1357 }
1358 
pasteGroups()1359 void ReportRender::pasteGroups()
1360 {
1361     BandDesignIntf* groupBand = findEnclosingGroup();
1362     if (groupBand){
1363         foreach(BandDesignIntf* band, *m_childBands.value(groupBand)){
1364             registerBand(band,false);
1365             if (band->isData()) m_renderedDataBandCount++;
1366             pushPageFooterGroupValues(band);
1367         }
1368         foreach(GroupBandsHolder* holder, m_childBands.values())
1369             holder->setTryToKeepTogether(false);
1370     }
1371     m_popupedExpression.clear();
1372     m_popupedValues.clear();
1373 }
1374 
bandLessThen(BandDesignIntf * b1,BandDesignIntf * b2)1375 bool bandLessThen(BandDesignIntf* b1, BandDesignIntf* b2){
1376     return b1->bandIndex() < b2->bandIndex();
1377 }
1378 
checkLostHeadersOnPrevPage()1379 void ReportRender::checkLostHeadersOnPrevPage()
1380 {
1381     QVector<BandDesignIntf*> lostHeaders;
1382 
1383     if (m_renderedPages.isEmpty()) return;
1384     PageItemDesignIntf::Ptr page = m_renderedPages.last();
1385     if (page->bands().isEmpty()) return;
1386 
1387     QMutableListIterator<BandDesignIntf*>it(page->bands());
1388 
1389     it.toBack();
1390     if (it.hasPrevious()){
1391         if (it.previous()->isFooter()){
1392                 if (it.hasPrevious()) it.previous();
1393                 else return;
1394         }
1395     }
1396 
1397     while (it.hasPrevious()){
1398         if (it.value()->isHeader()){
1399             if (it.value()->reprintOnEachPage()){
1400                 delete it.value();
1401             } else { lostHeaders.append(it.value());}
1402             it.remove();
1403             it.previous();
1404         } else break;
1405     }
1406 
1407     if (lostHeaders.size() > 0){
1408         m_lostHeadersMoved = true;
1409         qSort(lostHeaders.begin(), lostHeaders.end(), bandLessThen);
1410         foreach(BandDesignIntf* header, lostHeaders){
1411             registerBand(header);
1412         }
1413     } else {
1414         m_lostHeadersMoved = false;
1415     }
1416 
1417 
1418 }
1419 
checkLostHeadersInPrevColumn()1420 void ReportRender::checkLostHeadersInPrevColumn()
1421 {
1422     QVector<BandDesignIntf*> lostHeaders;
1423 
1424     QMutableListIterator<BandDesignIntf*>it(m_renderPageItem->bands());
1425 
1426     it.toBack();
1427     if (it.hasPrevious()){
1428         if (it.previous()->isFooter()){
1429                 if (it.hasPrevious()) it.previous();
1430                 else return;
1431         }
1432     }
1433 
1434     while (it.hasPrevious()){
1435         if (it.value()->isHeader()){
1436             if (it.value()->reprintOnEachPage()){
1437                 delete it.value();
1438             } else { lostHeaders.append(it.value());}
1439             it.remove();
1440             it.previous();
1441         } else break;
1442     }
1443 
1444     if (lostHeaders.size() > 0){
1445         m_lostHeadersMoved = true;
1446         qSort(lostHeaders.begin(), lostHeaders.end(), bandLessThen);
1447         foreach(BandDesignIntf* header, lostHeaders){
1448             registerBand(header);
1449         }
1450     } else {
1451         m_lostHeadersMoved = false;
1452     }
1453 }
1454 
findEnclosingGroup()1455 BandDesignIntf* ReportRender::findEnclosingGroup()
1456 {
1457     BandDesignIntf* result=0;
1458     int groupIndex = -1;
1459     if (!m_childBands.isEmpty()){
1460         foreach(BandDesignIntf* gb, m_childBands.keys()){
1461             if (m_childBands.value(gb)->tryToKeepTogether()&&
1462                 ((gb->bandIndex()<groupIndex)||(groupIndex==-1))
1463             ){
1464                 result=gb;
1465                 groupIndex=result->bandIndex();
1466             }
1467         }
1468     }
1469     return result;
1470 }
1471 
savePage(bool isLast)1472 void ReportRender::savePage(bool isLast)
1473 {
1474     if (m_renderPageItem->isTOC())
1475         m_pagesRanges.addTOCPage();
1476     else
1477         m_pagesRanges.addPage();
1478 
1479     m_datasources->setReportVariable("#IS_LAST_PAGEFOOTER",isLast);
1480     m_datasources->setReportVariable("#IS_FIRST_PAGEFOOTER",m_datasources->variable("#PAGE").toInt()==1);
1481 
1482     renderPageItems(m_patternPageItem);
1483     checkFooterGroup(m_lastDataBand);
1484     cutGroups();
1485     rearrangeColumnsItems();
1486     m_columnedBandItems.clear();
1487 
1488     BandDesignIntf* pf = m_patternPageItem->bandByType(BandDesignIntf::PageFooter);
1489     if (pf && m_datasources->variable("#PAGE").toInt()!=1 && !isLast){
1490         renderPageFooter(m_patternPageItem);
1491     } else {
1492         if (pf && pf->property("printOnFirstPage").toBool() && m_datasources->variable("#PAGE").toInt()==1){
1493             renderPageFooter(m_patternPageItem);
1494         } else if(pf && pf->property("printOnLastPage").toBool() && isLast){
1495             renderPageFooter(m_patternPageItem);
1496         }
1497     }
1498 
1499     if (m_pagesRanges.currentRange(m_patternPageItem->isTOC()).firstPage == 0) {
1500         m_datasources->setReportVariable("#PAGE",1);
1501     } else {
1502         m_datasources->setReportVariable("#PAGE",m_datasources->variable("#PAGE").toInt()+1);
1503     }
1504 
1505     BandDesignIntf* pageFooter = m_renderPageItem->bandByType(BandDesignIntf::PageFooter);
1506     if (pageFooter) pageFooter->setBandIndex(++m_currentIndex);
1507     m_renderedPages.append(PageItemDesignIntf::Ptr(m_renderPageItem));
1508     m_pageCount++;
1509     emit pageRendered(m_pageCount);
1510 
1511     if (isLast){
1512         BandDesignIntf* ph = m_renderPageItem->bandByType(BandDesignIntf::PageHeader);
1513         if (ph && !ph->property("printOnLastPage").toBool()){
1514             delete ph;
1515         }
1516     }
1517 
1518     m_renderPageItem->placeTearOffBand();
1519     m_scriptEngineContext->setCurrentPage(m_renderPageItem);
1520     emit m_patternPageItem->afterRender();
1521     if (isLast)
1522         emit m_patternPageItem->afterLastPageRendered();
1523     if (isLast && m_patternPageItem->endlessHeight()){
1524         qreal pageHeight = 0;
1525         foreach (BandDesignIntf* band, m_renderPageItem->bands()) {
1526             pageHeight += band->height();
1527         }
1528         m_renderPageItem->setHeight(pageHeight + 10 +
1529            (m_patternPageItem->topMargin() + m_patternPageItem->bottomMargin()) * Const::mmFACTOR);
1530     }
1531 }
1532 
toString()1533 QString ReportRender::toString()
1534 {
1535     QScopedPointer<ItemsWriterIntf> writer(new XMLWriter());
1536     foreach(PageItemDesignIntf::Ptr page,m_renderedPages){
1537         writer->putItem(page.data());
1538     }
1539     return writer->saveToString();
1540 }
1541 
~ReportRender()1542 ReportRender::~ReportRender(){
1543     m_renderedPages.clear();
1544 }
1545 
cancelRender()1546 void ReportRender::cancelRender(){
1547     m_renderCanceled = true;
1548 }
1549 
findLastPageNumber(int index)1550 int PagesRanges::findLastPageNumber(int index)
1551 {
1552     index++;
1553     foreach (PagesRange range, m_ranges) {
1554         if ( range.firstPage <= (index) && range.lastPage>= (index) )
1555             return (range.lastPage-(range.firstPage))+1;
1556     }
1557     return 0;
1558 }
1559 
findPageNumber(int index)1560 int PagesRanges::findPageNumber(int index)
1561 {
1562     index++;
1563     foreach (PagesRange range, m_ranges) {
1564         if ( range.firstPage <= (index) && range.lastPage >= (index) )
1565             return (index - range.firstPage)+1;
1566     }
1567     return 0;
1568 }
1569 
currentRange(bool isTOC)1570 PagesRange&PagesRanges::currentRange(bool isTOC)
1571 {
1572     Q_ASSERT( (isTOC && m_TOCRangeIndex!=-1) || !isTOC);
1573     if (isTOC && m_TOCRangeIndex !=-1) return m_ranges[m_TOCRangeIndex];
1574     return m_ranges.last();
1575 }
1576 
startNewRange(bool isTOC)1577 void PagesRanges::startNewRange(bool isTOC)
1578 {
1579     PagesRange range;
1580     if (!m_ranges.isEmpty()){
1581         range.firstPage = 0;
1582         range.lastPage = m_ranges.last().lastPage + 1;
1583     } else {
1584         range.firstPage = 0;
1585         range.lastPage = 0;
1586     }
1587     range.isTOC = isTOC;
1588     m_ranges.append(range);
1589     if (isTOC) m_TOCRangeIndex = m_ranges.size()-1;
1590 }
1591 
addTOCMarker(bool addNewRange)1592 void PagesRanges::addTOCMarker(bool addNewRange)
1593 {
1594     if ( addNewRange || m_ranges.isEmpty()){
1595         startNewRange(true);
1596     } else {
1597         m_TOCRangeIndex =  m_ranges.size()-1;
1598         m_ranges.last().isTOC = true;
1599     }
1600 }
1601 
addPage()1602 void PagesRanges::addPage()
1603 {
1604     if (m_ranges.isEmpty()) startNewRange();
1605     if (m_ranges.last().firstPage == 0){
1606         m_ranges.last().firstPage = m_ranges.last().lastPage == 0 ? 1 : m_ranges.last().lastPage;
1607         m_ranges.last().lastPage = m_ranges.last().lastPage == 0 ? 1 : m_ranges.last().lastPage;
1608     } else {
1609         m_ranges.last().lastPage++;
1610     }
1611 }
1612 
shiftRangesNextToTOC()1613 void PagesRanges::shiftRangesNextToTOC(){
1614     for(int i = m_TOCRangeIndex+1; i < m_ranges.size(); ++i){
1615         m_ranges[i].firstPage++;
1616         m_ranges[i].lastPage++;
1617     }
1618 }
1619 
addTOCPage()1620 void PagesRanges::addTOCPage()
1621 {
1622     Q_ASSERT(m_TOCRangeIndex != -1);
1623     if (m_TOCRangeIndex != -1){
1624         PagesRange& tocRange = m_ranges[m_TOCRangeIndex];
1625         if (tocRange.firstPage == 0) {
1626             tocRange.firstPage = tocRange.lastPage == 0 ? 1 :  tocRange.lastPage;
1627             tocRange.lastPage = tocRange.lastPage == 0 ? 1 :  tocRange.lastPage;
1628             if (tocRange.firstPage == 1 && tocRange.lastPage == 1)
1629                 shiftRangesNextToTOC();
1630         } else {
1631             tocRange.lastPage++;
1632             shiftRangesNextToTOC();
1633         }
1634     }
1635 }
1636 
clear()1637 void PagesRanges::clear()
1638 {
1639     m_ranges.clear();
1640 }
1641 
1642 } // namespace LimeReport
1643