3 // Author: Frantisek Vacek <fanda.vacek@volny.cz>, (C) 2006
5 // Copyright: See COPYING file that comes with this distribution
8 #include "qfreportpainter.h"
9 #include "qfreportprocessor.h"
10 #include "qfreportitem.h"
12 #include <qffileutils.h>
15 #include <qfsqlquerytable.h>
18 #include <QCryptographicHash>
19 #include <QSvgRenderer>
21 #include <qflogcust.h>
23 //==========================================================
25 //==========================================================
27 QFReportItem::QFReportItem(QFReportItem *_parent, const QFDomElement &el)
28 : parent(_parent), element(el)
32 QFReportItem::~QFReportItem()
38 void QFReportItem::clearChildren()
40 foreach(QFReportItem *it, children) SAFE_DELETE(it);
43 //==========================================================
44 // QFReportProcessorItem
45 //==========================================================
46 const double QFReportProcessorItem::Epsilon
= 1e-10;
47 const QString
QFReportProcessorItem::INFO_IF_NOT_FOUND_DEFAULT_VALUE
= "$INFO";
49 QFReportProcessorItem::QFReportProcessorItem(QFReportProcessor
*proc
, QFReportProcessorItem
*_parent
, const QFDomElement
&el
)
50 : QFTreeItemBase(_parent
), processor(proc
), element(el
)//, recentPrintResult(PrintNotPrintedYet)
52 QF_ASSERT(processor
, "Processor can not be NULL.");
53 recentlyPrintNotFit
= false;
54 keepAll
= element
.attribute("keepall").toBool();
55 //if(keepAll) { qfInfo() << "KEEP ALL is true" << element.attribute("keepall"); }
58 QFReportProcessorItem::~QFReportProcessorItem()
60 qfTrash() << QF_FUNC_NAME
<< "##################" << element
.tagName();
63 bool QFReportProcessorItem::childrenSynced()
65 qfTrash() << QF_FUNC_NAME
<< element
.tagName() << "children count:" << children().count();
68 for(QFDomElement el
= element
.firstChildElement(); !!el
; el
= el
.nextSiblingElement()) {
69 qfTrash() << "\t checking:" << el
.tagName() << "i:" << i
;
70 if(!QFReportProcessor::isProcessible(el
)) continue; /// nezname elementy ignoruj
71 qfTrash() << "\t processible";
72 if(i
>= children().count()) {
73 /// vic znamych elementu nez deti => neco pribylo
75 qfTrash() << "\t more elements";
78 if(el
== childAt(i
)->element
) {
79 /// stejny element na stejne posici
83 /// doslo k nejaky zmene nebo deti nejsou dosud vytvoreny
84 qfTrash() << "\t other element";
88 if(i
!= children().count()) {
89 qfTrash() << "\t divny";
92 qfTrash() << "\treturn:" << synced
;
96 void QFReportProcessorItem::deleteChildren()
100 foreach(QObject *o, this->children()) {
101 //qfTrash() << "\twant delete object:" << o;
102 //qfTrash() << "\tdeleting object:" << o;
109 void QFReportProcessorItem::syncChildren()
111 qfTrash() << QF_FUNC_NAME
<< element
.tagName() << "id:" << element
.attribute("id");
113 QList
<QFTreeItemBase
*> lst
;
114 for(QFDomElement el
= element
.firstChildElement(); !!el
; el
= el
.nextSiblingElement()) {
115 if(!QFReportProcessor::isProcessible(el
)) continue;
117 for(i
=0; i
<children
.count(); i
++) {
118 if(childAt(i
)->element
== el
) break;
120 if(i
< children
.count()) {
121 /// presun vytvoreny item do noveho listu
123 //qfTrash() << "\tmoved:" << (lst.last()->element.isNull()? "NULL": lst.last()->element.tagName());
124 children
.removeAt(i
);
127 /// vytvor chybejici item
128 QFReportProcessorItem
*it
= processor
->createItem(el
, NULL
);
131 //qfTrash() << "\tcreated:" << (lst.last()->element.isNull()? "NULL": lst.last()->element.tagName());
134 /// vymaz neaktualni itemy
139 for(QFDomElement el
= element
.firstChildElement(); !!el
; el
= el
.nextSiblingElement()) {
140 if(el
.tagName() == "script") {
142 for(QDomNode nd
= el
.firstChild(); !nd
.isNull(); nd
= nd
.nextSibling()) {
143 if(nd
.isCDATASection()) {
144 code
= nd
.toCDATASection().data();
147 if(!code
.isEmpty()) processor
->scriptDriver()->evaluate(code
);
150 if(!QFReportProcessor::isProcessible(el
)) continue;
151 /// vytvor chybejici item
152 processor
->createProcessibleItem(el
, this);
155 //qfTrash() << QF_FUNC_NAME << "<<<<<<<<<<<<<<<< OUT";
158 QString
QFReportProcessorItem::elementAttribute(const QString
& attr_name
, const QString
&default_val
)
160 QFString ret
= element
.attribute(attr_name
, default_val
);
161 static QRegExp
rx("script:([A-Za-z]\\S*)\\((.*)\\)");
162 if(rx
.exactMatch(ret
)) {
163 QF_ASSERT(processor
, "Processor is NULL.");
164 QString fn
= rx
.cap(1);
166 QStringList sl
= ret
.splitAndTrim(',', '\'');
168 foreach(QString s
, sl
) vl
<< s
;
169 QScriptValue sv
= processor
->scriptDriver()->call(this, fn
, vl
);
175 QFReportItemBand
* QFReportProcessorItem::parentBand()
177 QFReportProcessorItem
*it
= this->parent();
179 if(it
->toBand()) return it
->toBand();
185 QFReportItemDetail
* QFReportProcessorItem::currentDetail()
187 QFReportProcessorItem
*it
= const_cast<QFReportProcessorItem
*>(this);
189 if(it
->toDetail()) return it
->toDetail();
195 QFXmlTable
QFReportProcessorItem::findDataTable(const QString
&name
)
199 const QFReportItemDetail
*d
= currentDetail();
200 qfTrash() << "\tparent:" << parent() << "parent detail:" << d
;
202 qfTrash() << "\tdata row is null:" << d
->dataRow().isNull();
203 if(d
->dataRow().isNull() && !processor
->isDesignMode()) qfWarning().noSpace() << "'" << name
<< "' parent detail datarow is NULL";
204 ret
= d
->dataRow().firstChildTable(name
);
205 /// pokud ji nenajde a name neni specifikovano, vezmi 1. tabulku
206 if(ret
.isNull() && name
.isEmpty()) ret
= d
->dataRow().firstChildTable();
207 qfTrash() << "\ttable name:" << name
<< "is null:" << ret
.isNull();
208 //qfInfo() << name << ret.element().toString();
213 QFReportProcessorItem::PrintResult
QFReportProcessorItem::checkPrintResult(QFReportProcessorItem::PrintResult res
)
215 PrintResult ret
= res
;
216 //if(res.value == PrintNotFit) {
217 //qfWarning().noSpace() << "PrintNotFit element: '" << element.tagName() << "' id: '" << element.attribute("id") << "' recentlyPrintNotFit: " << recentlyPrintNotFit << " keepall: " << keepAll;
219 if(keepAll
&& recentlyPrintNotFit
&& res
.value
== PrintNotFit
) {
220 //qfWarning().noSpace() << "PrintNeverFit element: '" << element.tagName() << "' id: '" << element.attribute("id") << "'";
221 ret
.flags
|= FlagPrintNeverFit
;
223 recentlyPrintNotFit
= (ret
.value
== PrintNotFit
);
227 QVariant
QFReportProcessorItem::concatenateNodeChildrenValues(const QDomNode
& nd
)
230 QDomElement el
= nd
.toElement();
231 for(QFDomNode nd1
= el
.firstChild(); !!nd1
; nd1
= nd1
.nextSibling()) {
232 QVariant v1
= nodeValue(nd1
);
234 QFDomElement eel
= nd1
.toElement();
235 qfInfo() << "node value:" << eel
.toString() << v1
.toString();
237 if(!ret
.isValid()) ret
= v1
;
238 else ret
= ret
.toString() + v1
.toString();
243 QString
QFReportProcessorItem::nodeText(const QDomNode
&nd
)
245 QVariant v
= nodeValue(nd
);
246 if(v
.canConvert
<QFXmlTableDocument
>()) {
247 /// jedna se o XML tabulku, ktera je vysledkem SQL dotazu, vezmi z ni pouze 1. hodnotu na 1. radku
248 QFXmlTableDocument doc
= v
.value
<QFXmlTableDocument
>();
249 QFXmlTable
xt(doc
, QString());
250 v
= xt
.firstRow().value(0);
255 QFDomElement el
= nd
.toElement();
256 bool hide_null
= el
.attribute("hidenull", "true").toBool();
257 if(!v
.isValid() && !hide_null
) {
261 bool hide_zero
= el
.attribute("hidezero").toBool();
263 if(v
.type() == QVariant::Int
&& v
.toInt() == 0) {
266 else if(v
.type() == QVariant::Double
&& v
.toDouble() == 0) {
270 QString format
= el
.attribute("format");
271 if(v
.type() == QVariant::Date
) {
272 //qfInfo() << "Date format:" << format;
273 if(format
.isNull()) ret
= v
.toDate().toString(Qf::defaultDateFormat());
274 else ret
= v
.toDate().toString(format
);
276 else if(v
.type() == QVariant::Time
) {
277 if(format
.isNull()) ret
= v
.toString();
278 else ret
= v
.toTime().toString(format
);
280 else if(v
.type() == QVariant::DateTime
) {
281 //qfInfo() << v.toString();
282 if(format
.isNull()) ret
= v
.toDateTime().toString(Qf::defaultDateTimeFormat());
283 else ret
= v
.toTime().toString(format
);
285 else if(v
.type() == QVariant::Double
) {
286 if(!format
.isNull()) ret
= QFString::number(v
.toDouble(), format
);
287 else ret
= v
.toString();
289 else if(v
.type() == QVariant::Int
) {
290 if(!format
.isNull()) ret
= QFString::number(v
.toInt(), format
);
291 else ret
= v
.toString();
294 if(format
== "check") {
296 QString s
= QFReportItemMetaPaint::checkReportSubstitution
;
297 s
.replace("${STATE}", (b
)? "1": "0");
300 else ret
= v
.toString();
304 else ret
= v
.toString();
308 QVariant
QFReportProcessorItem::nodeValue(const QDomNode
&nd
)
310 qfTrash().color(QFLog::Cyan
) << QF_FUNC_NAME
;
311 static const QString S_ATTR_DOMAIN
= "domain";
312 static const QString S_EL_DATA
= "data";
314 qfTrash() << "\tnode type:" << nd
.nodeType();
316 QString s
= nd
.toText().data();
317 qfTrash().noSpace() << "\t\ttext: '" << s
<< "'";
320 else if(nd
.isElement()) {
321 QFDomElement el
= nd
.toElement();
322 if(el
.tagName() == S_EL_DATA
) {
323 bool sql_match
= el
.attribute("sqlmatch", "true").toBool();
324 QString default_value
= el
.attribute("defaultValue", QFReportProcessorItem::INFO_IF_NOT_FOUND_DEFAULT_VALUE
);
325 QString cast
= el
.attribute("cast");
326 QString data_src
= el
.attribute("src").trimmed();
327 qfTrash().noSpace() << "\t\tdata: '" << data_src
<< "'";
328 QString domain
= el
.attribute(S_ATTR_DOMAIN
, "row");
330 if(domain
== "script") {
331 for(QFDomElement el_param
= el
.firstChildElement("param"); !!el_param
; el_param
= el_param
.nextSiblingElement("param")) {
332 //qfInfo() << concatenateNodeChildrenValues(el_param).toString();
333 params
<< concatenateNodeChildrenValues(el_param
);
336 else if(domain
== "sql" || domain
== "scriptcode") {
338 for(QDomNode nd
= el
.firstChildElement("code").firstChild(); !nd
.isNull(); nd
= nd
.nextSibling()) {
339 if(nd
.isCDATASection()) {
340 code
= nd
.toCDATASection().data();
344 if(!code
.isEmpty()) {
346 for(QFDomElement el_param
= el
.firstChildElement("param"); !!el_param
; el_param
= el_param
.nextSiblingElement("param")) {
347 QString param_name
= el_param
.attribute("name");
348 if(!param_name
.isEmpty()) {
349 params
[param_name
] = concatenateNodeChildrenValues(el_param
);
352 QMapIterator
<QString
, QVariant
> i(params
);
355 code
.replace("${" + i
.key() + '}', i
.value().toString());
360 QVariant data_value
= value(data_src
, domain
, params
, default_value
, sql_match
);
361 if(!cast
.isEmpty()) {
362 if(cast
== "double") {
363 data_value
= Qf::retypeVariant(data_value
, QVariant::Double
);
365 else if(cast
== "int") {
366 data_value
= Qf::retypeVariant(data_value
, QVariant::Int
);
368 else if(cast
== "date") {
369 //qfInfo() << "casting date" << data_value.toString();
370 data_value
= Qf::retypeVariant(data_value
, QVariant::Date
);
371 //qfInfo() << "to" << data_value.toString();
373 else if(cast
== "time") {
374 data_value
= Qf::retypeVariant(data_value
, QVariant::Time
);
380 qfWarning() << "unprocessible element:" << el
.tagName();
383 qfTrash().color(QFLog::Cyan
) << "\treturn:" << ret
.toString() << QVariant::typeToName(ret
.type());
387 QVariant
QFReportProcessorItem::value(const QString
&data_src
, const QString
& domain
, const QVariantList
¶ms
, const QVariant
&default_value
, bool sql_match
)
389 //qfInfo() << "data_src:" << data_src << "domain:" << domain;
390 qfTrash() << QF_FUNC_NAME
<< "data_src:" << data_src
<< "domain:" << domain
<< "sql_match:" << sql_match
;
391 static const QString S_DOMAIN_SYSTEM
= "system";
392 static const QString S_DOMAIN_REPORT
= "report";
393 static const QString S_DOMAIN_ROW
= "row";
394 static const QString S_DOMAIN_TABLE
= "table";
395 static const QString S_DOMAIN_SCRIPT
= "script";
396 static const QString S_DOMAIN_SCRIPT_CODE
= "scriptcode";
397 static const QString S_DOMAIN_SQL
= "sql";
398 static const QString S_SYSTEM_DATE
= "date";
399 static const QString S_SYSTEM_TIME
= "time";
400 static const QString S_TABLE_ROWNO
= "ROW_NO()";
401 QVariant data_value
= default_value
;
402 bool info_if_not_found
= (default_value
== QFReportProcessorItem::INFO_IF_NOT_FOUND_DEFAULT_VALUE
);
403 if(domain
== S_DOMAIN_SYSTEM
) {
404 if(data_src
== S_SYSTEM_DATE
) {
405 data_value
= QDate::currentDate();//.toString(date_format);
407 else if(data_src
== S_SYSTEM_TIME
) {
408 data_value
= QTime::currentTime();
410 else if(data_src
== "page") {
411 data_value
= QString::number(processor
->processedPageNo() + 1);
413 else if(data_src
== "pageCount") {
414 data_value
= QFReportItemMetaPaint::pageCountReportSubstitution
; /// takovyhle blby zkratky mam proto, aby to zabralo zhruba stejne mista jako cislo, za ktery se to vymeni
417 else if(domain
== S_DOMAIN_SCRIPT
) {
419 data_value
= QFScriptDriver::scriptValueToVariant(processor
->scriptDriver()->call(this, data_src
, params
));
421 catch(QFException
&e
) {
422 qfError() << "Report table data load error:" << e
.msg();
425 else if(domain
== S_DOMAIN_SCRIPT_CODE
) {
427 data_value
= QFScriptDriver::scriptValueToVariant(processor
->scriptDriver()->evaluate(data_src
));
429 catch(QFException
&e
) {
430 qfError() << "Report table data load error:" << e
.msg();
433 else if(domain
== S_DOMAIN_SQL
) {
434 //qfInfo() << "element:" << element.toString();
435 if(!processor
->isDesignMode()) {
436 QString qs
= data_src
;
437 //qfInfo() << "qs:" << qs;
438 if(!qs
.isEmpty()) try {
441 QFXmlTableDocument doc
;
442 QFXmlTable xt
= t
.toXmlTable(doc
);
443 doc
.appendChild(xt
.element());
444 //qfInfo() << doc.toString();
445 data_value
.setValue(doc
);
447 catch(QFException
&e
) {
448 qfError() << "Report table data load error:" << e
.msg();
452 else if(domain
== S_DOMAIN_REPORT
) {
453 QFString path
= QFFileUtils::path(data_src
);
454 QString key
= QFFileUtils::file(data_src
);
455 //qfTrash().noSpace() << "\t\tpath: '" << path << "'" << "\t\tname: '" << data << "'";
456 QFDomElement el
= element
.cd(path
+ "keyvals", !Qf::ThrowExc
);
459 data_value
= kv
.value(key
);
462 qfWarning() << QString("Report path '%1' does not exist. Domain: %2 Element path: '%3'").arg(path
+ "keyvals").arg(domain
).arg(element
.path());
465 else if(domain
== S_DOMAIN_TABLE
) {
466 QFReportItemBand
*band
= parentBand();
467 if(!band
) qfWarning().noSpace() << "'" << data_src
<< "' band is null";
469 QFXmlTable t
= band
->dataTable();
471 if(info_if_not_found
) data_value
= '{' + data_src
+ '}';//qfWarning().noSpace() << "'" << data_src << "' table is null";
473 else data_value
= t
.value(data_src
, (info_if_not_found
)? "$" + data_src
: default_value
, sql_match
);
476 else if(domain
== S_DOMAIN_ROW
) {
477 QFReportItemDetail
*det
= currentDetail();
479 QFXmlTableRow r
= det
->dataRow();
480 qfTrash() << "\t\tdata row is null:" << r
.isNull();
482 if(info_if_not_found
) data_value
= '[' + data_src
+ ']';
485 if(data_src
== S_TABLE_ROWNO
) {
486 data_value
= det
->currentRowNo() + 1;
489 data_value
= r
.value(data_src
, (info_if_not_found
)? "$" + data_src
: default_value
);
494 if(info_if_not_found
) data_value
= "$" + data_src
+ " no detail";
497 qfTrash() << "\treturn:" << data_value
.toString() << QVariant::typeToName(data_value
.type());
498 //qfInfo() << "\treturn:" << data_value.toString() << QVariant::typeToName(data_value.type());
502 QFReportItemMetaPaint
* QFReportProcessorItem::createMetaPaintItem(QFReportItemMetaPaint
* parent
)
504 QFReportItemMetaPaint
*ret
= NULL
;
505 ret
= new QFReportItemMetaPaintFrame(parent
, this);
509 QString
QFReportProcessorItem::toString(int indent
, int indent_offset
)
513 indent_str
.fill(' ', indent_offset
);
514 ret
+= indent_str
+ element
.tagName();
515 for(int i
=0; i
<children().count(); i
++) {
517 QFReportProcessorItem
*it
= childAt(i
);
518 ret
+= it
->toString(indent
, indent_offset
+= indent
);
523 //==========================================================
525 //==========================================================
526 QFReportItemBreak::QFReportItemBreak(QFReportProcessor
*proc
, QFReportProcessorItem
*parent
, const QFDomElement
&_el
)
527 : QFReportProcessorItem(proc
, parent
, _el
)
529 QF_ASSERT(proc
, "processor is NULL");
530 designedRect
.verticalUnit
= Rect::UnitInvalid
;
534 QFReportProcessorItem::PrintResult
QFReportItemBreak::printMetaPaint(QFReportItemMetaPaint
*out
, const QFReportProcessorItem::Rect
&bounding_rect
)
536 qfTrash() << QF_FUNC_NAME
<< element
.tagName();
537 Q_UNUSED(bounding_rect
);
539 PrintResult res
= PrintOk
;
540 if(!breaking
) res
= PrintNotFit
;
541 breaking
= !breaking
;
545 //==========================================================
547 //==========================================================
548 QFReportItemFrame::QFReportItemFrame(QFReportProcessor
*proc
, QFReportProcessorItem
*parent
, const QFDomElement
&el
)
549 : QFReportProcessorItem(proc
, parent
, el
)
552 qfTrash() << QF_FUNC_NAME
<< "*******************" << el
.tagName() << el
.attribute("id");
555 s
= element
.attribute("x1");
557 designedRect
.flags
|= Rect::LeftFixed
;
558 p
.rx() = s
.toDouble();
560 s
= element
.attribute("y1");
562 designedRect
.flags
|= Rect::TopFixed
;
563 p
.ry() = s
.toDouble();
565 designedRect
.setTopLeft(p
);
566 s
= element
.attribute("x2");
568 designedRect
.flags
|= Rect::RightFixed
;
569 p
.rx() = s
.toDouble();
571 s
= element
.attribute("y2");
573 designedRect
.flags
|= Rect::BottomFixed
;
574 p
.ry() = s
.toDouble();
576 designedRect
.setBottomRight(p
);
577 //qfTrash() << "\t" << __LINE__ << "designedRect:" << designedRect.toString();
578 //static const QString S_PERCENT = "%";
579 s
= element
.attribute("w").trimmed();
580 if(s
== "%%" && parentLayout() == QFGraphics::LayoutHorizontal
) { element
.setAttribute("filllayout", "1"); }
585 designedRect
.horizontalUnit
= Rect::UnitPercent
;
587 qreal d
= s
.toDouble();
589 if(designedRect
.flags
& Rect::RightFixed
) {
590 qreal r
= designedRect
.right();
591 designedRect
.setWidth(d
);
592 designedRect
.moveRight(r
);
594 else designedRect
.setWidth(d
);
598 s
= element
.attribute("h").trimmed();
599 if(s
== "%%" && parentLayout() == QFGraphics::LayoutVertical
) { element
.setAttribute("filllayout", "1"); }
603 designedRect
.verticalUnit
= Rect::UnitPercent
;
605 qreal d
= s
.toDouble();
607 if(designedRect
.flags
& Rect::BottomFixed
) {
608 qreal b
= designedRect
.bottom();
609 designedRect
.setWidth(d
);
610 designedRect
.moveBottom(b
);
612 else designedRect
.setHeight(d
);
616 s
= element
.attribute("filllayout").trimmed();
618 designedRect
.flags
|= Rect::FillLayout
;
619 if(parentLayout() == QFGraphics::LayoutHorizontal
) {designedRect
.horizontalUnit
= Rect::UnitMM
; designedRect
.setWidth(0);}
620 else if(parentLayout() == QFGraphics::LayoutVertical
) {designedRect
.verticalUnit
= Rect::UnitMM
; designedRect
.setHeight(0);}
623 s
= element
.attribute("expandChildrenFrames").trimmed();
625 //qfInfo() << "element:" << element.tagName();
626 designedRect
.flags
|= Rect::ExpandChildrenFrames
;
629 layout
= (element
.attribute("layout", "vertical") == "horizontal")? QFGraphics::LayoutHorizontal
: QFGraphics::LayoutVertical
;
630 if(layout
== QFGraphics::LayoutHorizontal
) designedRect
.flags
|= Rect::LayoutHorizontalFlag
;
631 else designedRect
.flags
|= Rect::LayoutVerticalFlag
;
634 s
= element
.attribute("inset");
635 if(!!s
) hinset
= vinset
= s
.toDouble();
636 s
= element
.attribute("hinset");
637 if(!!s
) hinset
= s
.toDouble();
638 s
= element
.attribute("vinset");
639 if(!!s
) vinset
= s
.toDouble();
642 s
= element
.attribute("halign", "left");
643 if(s
== "left") alignment
|= Qt::AlignLeft
;
644 else if(s
== "center") alignment
|= Qt::AlignHCenter
;
645 else if(s
== "right") alignment
|= Qt::AlignRight
;
646 s
= element
.attribute("valign", "top");
647 if(s
== "top") alignment
|= Qt::AlignTop
;
648 else if(s
== "center") alignment
|= Qt::AlignVCenter
;
649 else if(s
== "bottom") alignment
|= Qt::AlignBottom
;
651 //multipage = element.attribute("multipage", "0").toBool();
653 qfTrash() << "\tdesignedRect:" << designedRect
.toString();
654 //if(!isLeftTopFloating()) designedRect.moveTopLeft(p1);
655 //if(!isRightBottomFloating()) designedRect.moveBottomRight(p2);
656 //qfTrash() << "\tdesignedRect:" << designedRect.toString();
659 QFReportProcessorItem::ChildSize
QFReportItemFrame::childSize(QFGraphics::Layout parent_layout
)
661 if(parent_layout
== QFGraphics::LayoutHorizontal
) return ChildSize(designedRect
.width(), designedRect
.horizontalUnit
);
662 return ChildSize(designedRect
.height(), designedRect
.verticalUnit
);
665 QFReportProcessorItem::PrintResult
QFReportItemFrame::printMetaPaintChildren(QFReportItemMetaPaint
*out
, const QFReportProcessorItem::Rect
&bounding_rect
)
667 qfTrash().color(QFLog::Green
) << QF_FUNC_NAME
<< element
.tagName() << "id:" << element
.attribute("id") << "childrencount:" << children().count() << "indexToPrint:" << indexToPrint
;
668 qfTrash() << "\tbounding_rect:" << bounding_rect
.toString();
669 PrintResult res
= PrintOk
;
670 //dirtySize = Size();
671 Rect bbr
= bounding_rect
;
672 //Size children_dirty_size;
673 //Size children_bounding_size = bbr.size();
674 QList
<ChildSize
> sizes
;
675 QList
<ChildSize
> orthogonal_sizes
;
676 /// horizontalni layout se tiskne bud stejne, jako vertikalni (v pripade, ze lze tisknout deti v poradi, jak jsou v reportu)
677 /// nebo prehazene, pokud se nedaji procenta rozpocitat predem.
678 /// tato informace je ulozena v promenne can_print_children_in_natural_order
680 /// nastav detem mm rozmer ve smeru layoutu
681 //bool only_last_child_has_0_percent = false;
683 int cnt_0_percent
= 0;
685 for(int i
=indexToPrint
; i
<childrenCount(); i
++) {
686 QFReportProcessorItem
*it
= childAt(i
);
687 sizes
<< it
->childSize(layout
);
688 /// break funguje tak, ze pri 1., 3., 5. atd. tisku vraci PrintNotFit a pri sudych PrintOk
689 /// prvni break na strance znamena, ze jsem tu uz po zalomeni, takze se tiskne to za break.
690 /// v horizontalnim layoutu break ignoruj
691 if(it
->isBreak() && i
> indexToPrint
&& layout
== QFGraphics::LayoutVertical
) break;
693 int last_rubber_ix
= -1;
694 int first_percent_ix
= -1;
695 for(int i
=0; i
<sizes
.count(); i
++) {
696 const ChildSize
&sz
= sizes
[i
];
697 //only_last_child_has_0_percent = false;
698 if(sz
.unit
== Rect::UnitPercent
) {
699 if(first_percent_ix
< 0) first_percent_ix
= i
;
703 //only_last_child_has_0_percent = true;
706 else if(sz
.unit
== Rect::UnitMM
) {
713 //only_last_child_has_0_percent = (only_last_child_has_0_percent && cnt_percent == 1);
715 /// can_print_children_in_natural_order je true v pripade, ze procenta nejsou nebo 1. procenta jsou za poslednim rubber frame.
716 bool can_print_children_in_natural_order
= first_percent_ix
< 0 || last_rubber_ix
< 0 || last_rubber_ix
< first_percent_ix
;
718 if(layout
== QFGraphics::LayoutVertical
) {
719 /// ve vertikalnim layoutu nejdou michat % a rubber children frames, kvuli preteceni stranky (v takovem pripade se musi tisknout v prehazenem poradi) => rubbers predelej na %
720 /// predelej vsechny rubber children za prvnim vyskytem % na %
721 // pokud je parent frame rubber zpusobi % jeho raztazeni na cely bounding rect
722 if(!can_print_children_in_natural_order
) {
723 for(int i
=first_percent_ix
; i
<sizes
.count(); i
++) {
724 ChildSize
&sz
= sizes
[i
];
725 if(sz
.size
== 0 && sz
.unit
== Rect::UnitMM
) {
726 if(layout
== QFGraphics::LayoutVertical
) childAt(indexToPrint
+ i
)->designedRect
.verticalUnit
= Rect::UnitPercent
;
727 else if(layout
== QFGraphics::LayoutHorizontal
) childAt(indexToPrint
+ i
)->designedRect
.horizontalUnit
= Rect::UnitPercent
;
728 sz
.unit
= Rect::UnitPercent
;
734 if(layout
== QFGraphics::LayoutHorizontal
&& !can_print_children_in_natural_order
) {
735 /// pri tisku 2. metodou se tiskne vzdu od zacatku
738 /// zbyva vypocitat jeste ortogonalni rozmer
739 /// je to bud absolutni hodnota nebo % z bbr
740 for(int i
=indexToPrint
; i
<children().count(); i
++) {
741 QFReportProcessorItem
*it
= childAt(i
);
742 QFGraphics::Layout ol
= orthogonalLayout();
743 ChildSize sz
= it
->childSize(ol
);
744 if(sz
.unit
== Rect::UnitPercent
) {
745 if(sz
.size
== 0) sz
.size
= bbr
.sizeInLayout(ol
);
746 else sz
.size
= sz
.size
/ 100 * bbr
.sizeInLayout(ol
);
748 orthogonal_sizes
<< sz
;
749 //it->metaPaintOrthogonalLayoutLength = sz.size;
750 qfTrash() << "\tsetting orthogonal length:" << sz
.size
;
751 if(it
->isBreak() && i
> indexToPrint
&& layout
== QFGraphics::LayoutVertical
) break; /// v horizontalnim layoutu break ignoruj
754 if(layout
== QFGraphics::LayoutHorizontal
&& !can_print_children_in_natural_order
) {
757 /// to se muze stat jen v horizontalnim layoutu, kdyz nejde sirky napocitat dopredu.
758 /// v horizontalnim layoutu vytiskni nejdriv fixed itemy, pak rubber, ze zbytku rozpocitej % a vytiskni je taky
759 /// vytiskly itemy pak rozsoupej do spravnyho poradi
761 QList
<int> poradi_tisku
;
763 /// vytiskni rubber a fixed
764 for(int i
=0; i
<children().count(); i
++) {
765 QFReportProcessorItem
*it
= childAt(i
);
766 ChildSize sz
= it
->childSize(layout
);
767 //qfInfo() << "child:" << i << "size:" << sz.size << "unit:" << Rect::unitToString(sz.unit);
768 if(sz
.unit
== Rect::UnitMM
) {
770 //qfInfo() << "\t i:" << i << " fixed or rubber bbr";
771 if(sz
.size
> 0) ch_bbr
.setWidth(sz
.size
);
772 else ch_bbr
.setWidth(ch_bbr
.width() - sum_mm
);
773 if(orthogonal_sizes
[i
].size
> 0) {
774 ch_bbr
.setSizeInLayout(orthogonal_sizes
[i
].size
, orthogonalLayout());
776 //qfInfo() << "\t tisknu fixed:" << it->designedRect.toString();
777 PrintResult ch_res
= it
->printMetaPaint(out
, ch_bbr
);
778 if(ch_res
.value
== PrintOk
) {
779 //qfInfo() << "\t OK";
780 if(out
->children().count() > 0) {
782 sum_mm
+= out
->lastChild()->renderedRect
.width();
783 //qfInfo() << "\t poradi tisku <<" << i;
784 //qfInfo() << "\t renderedRect:" << out->lastChild()->renderedRect.width();
785 //qfInfo() << "\t sum_mm:" << sum_mm;
787 else { qfWarning() << "jak to, ze se dite nevytisklo v horizontalnim layoutu? ze by h=% v parentu, ktery nema h specifikovano?"; }
790 qfInfo() << "\t NOT OK";
796 qreal rest_mm
= bounding_rect
.width() - sum_mm
;
798 if(res
.value
== PrintOk
) {
799 /// rozpocitej procenta
800 qreal sum_percent
= 0;
801 int cnt_0_percent
= 0;
802 bool has_percent
= false;
803 for(int i
=0; i
<children().count(); i
++) {
804 QFReportProcessorItem
*it
= childAt(i
);
805 ChildSize sz
= it
->childSize(layout
);
806 if(sz
.unit
== Rect::UnitPercent
) {
808 if(sz
.size
== 0) cnt_0_percent
++;
809 else sum_percent
+= sz
.size
;
814 qfWarning() << "Percent exist but rest_mm is" << rest_mm
<< ". Ignoring rest of frames";
817 /// vytiskni procenta
819 if(cnt_0_percent
> 0) percent_0
= (100 - sum_percent
) / cnt_0_percent
;
820 for(int i
=0; i
<children().count(); i
++) {
821 QFReportProcessorItem
*it
= childAt(i
);
822 ChildSize sz
= it
->childSize(layout
);
823 if(sz
.unit
== Rect::UnitPercent
) {
825 if(sz
.size
== 0) d
= rest_mm
* percent_0
/ 100;
826 else d
= rest_mm
* sz
.size
/ 100;
829 if(orthogonal_sizes
[i
].size
> 0) {
830 ch_bbr
.setSizeInLayout(orthogonal_sizes
[i
].size
, orthogonalLayout());
832 //qfInfo() << "tisknu percent" << it->designedRect.toString();
833 PrintResult ch_res
= it
->printMetaPaint(out
, ch_bbr
);
834 if(ch_res
.value
== PrintOk
) {
837 else { res
= ch_res
; break; }
841 /// posprehazej vytisknuty deti
842 if(poradi_tisku
.count() == out
->children().count()) {
843 //QF_ASSERT(poradi_tisku.count() == out->children().count(), "nevytiskly se vsechny deti v horizontalnim layoutu");
844 QVector
<QFTreeItemBase
*> old_children(poradi_tisku
.count());
845 /// zkopiruj ukazatele na deti
846 for(int i
=0; i
<poradi_tisku
.count(); i
++) old_children
[i
] = out
->children()[i
];
847 /// dej je do spravnyho poradi
848 for(int i
=0; i
<poradi_tisku
.count(); i
++) out
->childrenRef()[poradi_tisku
[i
]] = old_children
[i
];
849 /// nastav jim spravne offsety
851 for(int i
=0; i
<poradi_tisku
.count(); i
++) {
852 QFReportItemMetaPaint
*it
= out
->childAt(i
);
853 /// tady je to potreba posunout vcetne deti :(
854 it
->shift(Point(offset_x
, 0));
855 offset_x
+= it
->renderedRect
.width();
861 if(res
.value
!= PrintOk
) {
862 resetIndexToPrintRecursively(!QFReportProcessorItem::IncludingParaTexts
);
866 /// can_print_children_in_natural_order
868 /// rozpocitej procenta
869 qreal sum_percent
= 0;
872 for(int i
=0; i
<sizes
.count(); i
++) {
873 ChildSize
&sz
= sizes
[i
];
874 if(sz
.unit
== Rect::UnitMM
) sum_mm
+= sz
.size
;
875 else if (sz
.unit
== Rect::UnitPercent
) {
876 if(sz
.size
== 0) cnt_0_percent
++;
877 else sum_percent
+= sz
.size
;
880 qreal rest_percent
= 100 - sum_percent
;
881 if(rest_percent
< 0) rest_percent
= 0;
883 if(cnt_0_percent
> 0) percent_0
= rest_percent
/ cnt_0_percent
;
885 qreal length_mm
= bbr
.sizeInLayout(layout
);
886 int index_to_print_0
= indexToPrint
;
887 for(; indexToPrint
<children().count(); indexToPrint
++) {
888 QFReportProcessorItem
*it
= childAt(indexToPrint
);
890 bool item_is_rubber_in_layout
= false;
891 qfTrash() << "\tch_bbr v1:" << ch_bbr
.toString();
893 /// vymysli rozmer ve smeru layoutu
894 qreal d
= ch_bbr
.sizeInLayout(layout
);
895 //qfInfo() << "indexToPrint:" << indexToPrint << "index_to_print_0:" << index_to_print_0 << "sizes.count():" << sizes.count();
896 ChildSize
&sz
= sizes
[indexToPrint
- index_to_print_0
];
897 if(sz
.unit
== Rect::UnitMM
) {
898 if(sz
.size
> 0) d
= sz
.size
;
899 else item_is_rubber_in_layout
= true;
901 else if(sz
.unit
== Rect::UnitPercent
) {
903 if(p
== 0) p
= percent_0
;
904 qreal rest_mm
= length_mm
- sum_mm
;
905 if(rest_mm
< 0) rest_mm
= 0;
906 d
= p
* rest_mm
/ 100.;
908 d
= qMin(ch_bbr
.sizeInLayout(layout
), d
);
909 ch_bbr
.setSizeInLayout(d
, layout
);
910 if(orthogonal_sizes
[indexToPrint
- index_to_print_0
].size
> 0) {
911 ch_bbr
.setSizeInLayout(orthogonal_sizes
[indexToPrint
- index_to_print_0
].size
, orthogonalLayout());
914 qfTrash() << "\tch_bbr v2:" << ch_bbr
.toString();
915 PrintResult ch_res
= it
->printMetaPaint(out
, ch_bbr
);
916 if(ch_res
.value
== PrintOk
) {
917 //qfTrash() << "\t" << __LINE__ << "children_dirty_size:" << children_dirty_size.toString();
918 //dirtyRect = dirtyRect.unite(it->dirtyRect);
919 //qfTrash() << "\t" << __LINE__ << "children_dirty_size:" << children_dirty_size.toString();
920 /// muze se stat, ze se dite nevytiskne, napriklad band nema zadna data
921 //QF_ASSERT(out->children().count() > 0, "jak to, ze se dite nevytisklo?");
922 if(out
->children().count() > 0) {
923 const Rect
&r
= out
->lastChild()->renderedRect
;
924 qfTrash() << "\tr:" << r
.toString() << "ch_res:" << ch_res
.toString();
925 bbr
.cutSizeInLayout(r
, layout
);
926 if(item_is_rubber_in_layout
) {
927 /// pricti vyrendrovany rozmer k sum_mm, az se zacnou rozpocitavat % bude to potreba.
928 /// je zaruceno, ze prvni % prijdou az po poslednim rubber frame.
929 sum_mm
+= r
.sizeInLayout(layout
);
931 if(ch_res
.flags
& FlagPrintAgain
) {
932 indexToPrint
--; /// vytiskni ho znovu
935 //bbr.cutSizeInLayout(it->dirtyRect, layout);
936 //qfTrash() << "\t" << __LINE__ << "children_dirty_size:" << children_dirty_size.toString();
939 /// pokud je vertikalni layout, a dite se nevejde vrat PrintNotFit
940 if(layout
== QFGraphics::LayoutHorizontal
) {
941 /// v horizontalnim, zadne pretikani neni
942 /// vytiskni to znovu s doteklymi texty
943 resetIndexToPrintRecursively(!QFReportProcessorItem::IncludingParaTexts
);
947 if(ch_res.flags & FlagNotFirstDetailNotFit) {
948 qfInfo() << "nevesel se detail";
949 /// nevesel se detail, ale nebyl to prvni detail, takze je to OK
950 indexToPrint--; /// vytiskni ho znovu
951 ch_res.flags |= FlagPrintAgain;
952 //ch_res.value = PrintOk;
959 if(it
->isBreak() && indexToPrint
> index_to_print_0
&& layout
== QFGraphics::LayoutVertical
) break;
962 //res = checkPrintResult(res);
963 qfTrash().color(QFLog::Green
) << "\t<<< CHILDREN return:" << res
.toString();
967 QFReportProcessorItem::PrintResult
QFReportItemFrame::printMetaPaint(QFReportItemMetaPaint
*out
, const QFReportProcessorItem::Rect
&bounding_rect
)
969 qfTrash().color(QFLog::Cyan
) << QF_FUNC_NAME
<< element
.tagName() << "id:" << element
.attribute("id");
970 //qfInfo() << element.tagName() << "id:" << element.attribute("id") << "designedRect:" << designedRect.toString();
971 qfTrash() << "\tbounding_rect:" << bounding_rect
.toString();
972 qfTrash() << "\tdesignedRect:" << designedRect
.toString();// << "isLeftTopFloating:" << isLeftTopFloating() << "isRightBottomFloating:" << isRightBottomFloating();
973 if(parentFrame()) qfTrash() << "\tparent layout:" << ((parentFrame()->layout
== QFGraphics::LayoutHorizontal
)? "horizontal": "vertical");
974 qfTrash() << "\tlayout:" << ((layout
== QFGraphics::LayoutHorizontal
)? "horizontal": "vertical") << ", is rubber:" << isRubber(layout
);
975 //qfTrash() << "\tmetaPaintLayoutLength:" << metaPaintLayoutLength << "metaPaintOrthogonalLayoutLength:" << metaPaintOrthogonalLayoutLength;
976 PrintResult res
= PrintOk
;
978 Rect bbr
= bounding_rect
;
979 qfTrash() << "\tbbr 0:" << bbr
.toString();
980 if(designedRect
.isAnchored()) {
981 /// pokud je designedRect anchored neni treba ho nekam cpat
982 /// pokud frame neni floating, vyprdni se na bounding_rect
984 if(bbr
.isRubber(QFGraphics::LayoutHorizontal
)) bbr
.setRight(bounding_rect
.right());
985 if(bbr
.isRubber(QFGraphics::LayoutVertical
)) bbr
.setBottom(bounding_rect
.bottom());
988 if(designedRect
.horizontalUnit
== Rect::UnitMM
&& designedRect
.width() - Epsilon
> bounding_rect
.width()) {
989 qfTrash() << "\t<<<< FRAME NOT FIT WIDTH";
990 return checkPrintResult(PrintNotFit
);
992 if(designedRect
.verticalUnit
== Rect::UnitMM
&& designedRect
.height() - Epsilon
> bounding_rect
.height()) {
993 qfTrash() << "\t<<<< FRAME NOT FIT HEIGHT";
994 //qfInfo() << "\tbounding_rect:" << bounding_rect.toString() << "height:" << bounding_rect.height();
995 //qfInfo() << "\tdesignedRect:" << designedRect.toString() << "height:" << designedRect.height();
996 //qfInfo() << "\tbounding_rect.height() < designedRect.height() (" << bounding_rect.height() << "<" << designedRect.height() << "):" << (bounding_rect.height() > designedRect.height());
997 return checkPrintResult(PrintNotFit
);
1001 Rect init_bbr
= bbr
;
1002 bbr
.adjust(hinset
, vinset
, -hinset
, -vinset
);
1003 qfTrash() << "\tbbr 1:" << bbr
.toString();
1005 QFReportItemMetaPaintFrame
*mp
= dynamic_cast<QFReportItemMetaPaintFrame
*>(createMetaPaintItem(NULL
));
1006 QF_ASSERT(mp
, "Meta paint item for element " + element
.tagName() + " not created.");
1007 mp
->setInset(hinset
, vinset
);
1008 mp
->setLayout(layout
);
1009 mp
->setAlignment(alignment
);
1010 res
= printMetaPaintChildren(mp
, bbr
);
1011 //qfTrash() << "\tbbr_init:" << bbr_init.toString();
1013 if(res
.value
== PrintNotFit
) {
1014 /// pokud je result neverfit, nech ho tam, at aspon vidime, co se nikdy nevejde
1015 //qfInfo() << "keepAll:" << keepAll;
1016 if(keepAll
&& !(res
.flags
& FlagPrintNeverFit
)) {
1017 resetIndexToPrintRecursively(QFReportProcessorItem::IncludingParaTexts
);
1018 //qfInfo() << "keepAll && !(res.flags & FlagPrintNeverFit)";
1020 return checkPrintResult(res
);
1025 if(!isRubber(layout
)) {
1026 /// pokud ma nektere dite flag filllayout, roztahni ho tak aby s ostatnimi detmi vyplnili layout
1027 int filllayout_child_ix
= -1;
1029 for(int i
=0; i
<mp
->childrenCount(); i
++) {
1030 QFReportItemMetaPaint
*it
= mp
->childAt(i
);
1031 sum_mm
+= it
->renderedRect
.sizeInLayout(layout
);
1032 if(it
->renderedRect
.flags
& Rect::FillLayout
) filllayout_child_ix
= i
;
1034 if(filllayout_child_ix
>= 0) {
1035 qreal offset
= bbr
.sizeInLayout(layout
) - sum_mm
;
1037 QFReportItemMetaPaint
*it
= mp
->childAt(filllayout_child_ix
);
1038 it
->renderedRect
.setSizeInLayout(it
->renderedRect
.sizeInLayout(layout
) + offset
, layout
);
1039 it
->alignChildren();
1041 if(layout
== QFGraphics::LayoutHorizontal
) p
.setX(offset
);
1042 else if(layout
== QFGraphics::LayoutVertical
) p
.setY(offset
);
1043 for(int i
=filllayout_child_ix
+ 1; i
<mp
->childrenCount(); i
++) {
1044 it
= mp
->childAt(i
);
1051 //if(element.tagName() == "row") qfInfo() << "expandchildren:" << element.attribute("expandchildren");
1052 if(isRubber(parentLayout()) && layout
!= orthogonalLayout(layout
) && element
.attribute("expandchildren").toBool()) {
1053 /// pokud ma item flag expandchildren, roztahni deti tak, aby mely vsechny rozmer ve smeru ortogonalniho layoutu
1054 /// jako to nejvetsi ve smeru ortogonalniho layoutu
1055 //qfInfo() << "expanding children elementid:" << element.attribute("id");
1056 //if(element.attribute("id") == "123") {
1057 // qfInfo() << "\t" << element.toString();
1061 for(int i
=0; i
<mp
->children
.count(); i
++) {
1062 QFReportItemMetaPaint
*it
= mp
->childAt(i
);
1063 //qfInfo() << "\t " << it->reportElement.toString();
1065 max_mm
= qMax(it
->renderedRect
.sizeInLayout(orthogonalLayout()), max_mm
);
1067 for(int i
=0; i
<mp
->children
.count(); i
++) {
1068 QFReportItemMetaPaint
*it
= mp
->childAt(i
);
1069 it
->renderedRect
.setSizeInLayout(max_mm
, orthogonalLayout());
1073 /// tak kolik jsem toho pokreslil?
1074 Rect dirty_rect
;//, rendered_rect = designedRect;
1075 dirty_rect
.flags
= designedRect
.flags
;
1076 if(isRubber(layout
) || isRubber(orthogonalLayout())) {
1077 /// pokud je v nejakym smeru natahovaci, musim to proste secist
1078 for(int i
=0; i
<mp
->childrenCount(); i
++) {
1079 QFReportItemMetaPaint
*it
= mp
->childAt(i
);
1080 //qfInfo() << "child" << i << "rendered rect:" << it->renderedRect.toString() << "is null:" << it->renderedRect.isNull();
1081 //qfInfo() << "\t 1 rubber dirty_rect:" << dirty_rect.toString();
1082 if(dirty_rect
.isNull()) dirty_rect
= it
->renderedRect
;
1083 else dirty_rect
= dirty_rect
.united(it
->renderedRect
);
1084 //dirty_rect.flags |= it->renderedRect.flags;
1085 //qfInfo() << "\t 2 rubber dirty_rect:" << dirty_rect.toString();
1087 qfTrash() << "\trubber dirty_rect:" << dirty_rect
.toString();
1089 qfTrash() << "\tdirty_rect 1:" << dirty_rect
.toString();
1090 /// pokud je v nekterem smeru definovany, je jedno, kolik se toho potisklo a nastav ten rozmer
1091 if(designedRect
.horizontalUnit
== Rect::UnitPercent
) dirty_rect
.setWidth(bbr
.width());
1092 else if(designedRect
.horizontalUnit
== Rect::UnitMM
&& designedRect
.width() > 0) dirty_rect
.setWidth(designedRect
.width() - 2*hinset
);
1093 qfTrash() << "\tdirty_rect 2:" << dirty_rect
.toString();
1094 if(designedRect
.verticalUnit
== Rect::UnitPercent
) dirty_rect
.setHeight(bbr
.height());
1095 else if(designedRect
.verticalUnit
== Rect::UnitMM
&& designedRect
.height() > 0) dirty_rect
.setHeight(designedRect
.height() - 2*vinset
);
1096 qfTrash() << "\tdirty_rect 3:" << dirty_rect
.toString();
1097 /// pri rendrovani se muze stat, ze dirtyRect nezacina na bbr, to ale alignment zase spravi
1098 dirty_rect
.moveTopLeft(bbr
.topLeft());
1099 qfTrash() << "\tdirty_rect:" << dirty_rect
.toString();
1100 //qfTrash() << "\tlayout:" << ((layout == LayoutHorizontal)? "horizontal": "vertical");
1101 //qfTrash() << "\tortho layout:" << ((orthogonalLayout() == LayoutHorizontal)? "horizontal": "vertical");
1102 //qfTrash() << "\trenderedRect:" << r.toString();
1103 //qfTrash() << "\trenderedRect:" << r.toString();
1106 qfTrash() << "\tALIGN:" << QString::number((int)alignment
, 16);
1107 //alignChildren(mp, dirty_rect);
1109 dirty_rect
.adjust(-hinset
, -vinset
, hinset
, vinset
);
1110 mp
->renderedRect
= dirty_rect
;
1111 mp
->alignChildren();
1112 //qfInfo() << "\t designedRect flags:" << designedRect.toString();
1113 mp
->renderedRect
.flags
= designedRect
.flags
;
1115 if(designedRect
.flags
& QFReportProcessorItem::Rect::ExpandChildrenFrames
) {
1116 mp
->expandChildrenFramesRecursively();
1119 //dirtyRect = r;//.adjusted(-hinset, -vinset, hinset, vinset);;
1120 qfTrash() << "\trenderedRect:" << mp
->renderedRect
.toString();
1121 res
= checkPrintResult(res
);
1122 qfTrash().color(QFLog::Cyan
) << "\t<<<< FRAME return:" << res
.toString() << element
.tagName() << "id:" << element
.attribute("id");
1126 void QFReportItemFrame::alignChildren(QFReportItemMetaPaintFrame *mp, const QFReportProcessorItem::Rect & dirty_rect)
1128 if(!dirty_rect.isNull()) {
1129 if(alignment & ~(Qt::AlignLeft | Qt::AlignTop)) {
1131 /// ve smeru layoutu posun cely blok
1134 /// vypocitej velikost potisknuteho bloku
1135 for(int i=0; i<mp->childrenCount(); i++) {
1136 QFReportItemMetaPaint *it = mp->childAt(i);
1137 r1 = r1.united(it->renderedRect);
1140 if(layout == QFGraphics::LayoutHorizontal) {
1141 if(alignment & Qt::AlignHCenter) al = 0.5;
1142 else if(alignment & Qt::AlignRight) al = 1;
1143 d = dirty_rect.width() - r1.width();
1144 if(al > 0 && d > 0) {
1145 offset.rx() = d * al - (r1.left() - dirty_rect.left());
1148 else if(layout == QFGraphics::LayoutVertical) {
1149 if(alignment & Qt::AlignVCenter) al = 0.5;
1150 else if(alignment & Qt::AlignBottom) al = 1;
1151 d = dirty_rect.height() - r1.height();
1152 if(al > 0 && d > 0) {
1153 offset.ry() = d * al - (r1.top() - dirty_rect.top());
1158 /// v orthogonalnim smeru kazdy item
1159 for(int i=0; i<mp->childrenCount(); i++) {
1160 QFReportItemMetaPaint *it = mp->childAt(i);
1161 const Rect &r1 = it->renderedRect;
1162 qfTrash() << "\t\titem renderedRect:" << r1.toString();
1165 if(orthogonalLayout() == QFGraphics::LayoutHorizontal) {
1167 if(alignment & Qt::AlignHCenter) al = 0.5;
1168 else if(alignment & Qt::AlignRight) al = 1;
1169 d = dirty_rect.width() - r1.width();
1170 if(al > 0 && d > 0) {
1171 qfTrash() << "\t\thorizontal alignment:" << al;
1172 offset.rx() = d * al - (r1.left() - dirty_rect.left());
1175 else if(orthogonalLayout() == QFGraphics::LayoutVertical) {
1178 if(alignment & Qt::AlignVCenter) al = 0.5;
1179 else if(alignment & Qt::AlignBottom) al = 1;
1180 d = dirty_rect.height() - r1.height();
1181 if(al > 0 && d > 0) {
1182 qfTrash() << "\t\tvertical alignment:" << al;
1183 offset.ry() = d * al - (r1.top() - dirty_rect.top());
1186 qfTrash() << "\t\talign offset:" << offset.toString();
1187 if(!offset.isNull()) it->shift(offset);
1194 QFReportItemFrame::Layout QFReportItemFrame::parentLayout() const
1196 QFReportItemFrame *frm = parentFrame();
1197 if(!frm) return LayoutInvalid;
1201 void QFReportItemFrame::resetIndexToPrintRecursively(bool including_para_texts
)
1203 //qfInfo() << "resetIndexToPrintRecursively()";
1205 for(int i
=0; i
<childrenCount(); i
++) {
1206 QFReportProcessorItem
*it
= childAt(i
);
1207 it
->resetIndexToPrintRecursively(including_para_texts
);
1210 foreach(QObject *o, children()) {
1211 QFReportProcessorItem *it = qobject_cast<QFReportProcessorItem*>(o);
1212 it->resetIndexToPrintRecursively();
1217 //==========================================================
1218 // QFReportItemReport
1219 //==========================================================
1220 QFReportItemReport::QFReportItemReport(QFReportProcessor
*proc
, const QFDomElement
&_el
)
1221 : QFReportItemBand(proc
, NULL
, _el
)
1223 QF_ASSERT(proc
, "processor is NULL");
1224 //Rect r = designedRect;
1225 //QFDomElement el = element.cloneNode(false).toElement();
1226 //qfTrash() << "\toriginal:" << element.tagName() << "is null:" << element.isNull() << "has children:" << element.hasChildNodes() << "parent node is null:" << element.parentNode().isNull();
1227 //qfTrash() << "\tclone:" << el.tagName() << "is null:" << el.isNull() << "has children:" << el.hasChildNodes() << "parent node is null:" << el.parentNode().isNull();
1228 if(element
.attribute("orientation") == "landscape") {
1229 Size sz
= designedRect
.size();
1231 designedRect
.setSize(sz
);
1233 designedRect
.flags
= (Rect::LeftFixed
| Rect::TopFixed
| Rect::RightFixed
| Rect::BottomFixed
);
1234 //element.setAttribute("brd", "color: teal");
1235 //element.setAttribute("fill", "color: white");
1236 f_dataTable
= proc
->data();
1237 //qfInfo() << f_dataTable.toString();
1238 dataTableLoaded
= true;
1241 QFReportProcessorItem::PrintResult
QFReportItemReport::printMetaPaint(QFReportItemMetaPaint
*out
, const QFReportProcessorItem::Rect
&bounding_rect
)
1243 qfTrash() << QF_FUNC_NAME
<< "\x1B[1;31;40m***ROOT***ROOT***ROOT***ROOT***\x1B[0;37;40m" << element
.tagName();
1244 Q_UNUSED(bounding_rect
);
1245 PrintResult res
= PrintOk
;
1247 //QFReportItemMetaPaintPage *pg = new QFReportItemMetaPaintPage(out, element, processor->context());
1248 //pg->renderedRect = designedRect;
1249 //indexToPrint = 0; /// vzdy vytiskni header a footer. (footer je absolutni header, umisteny pred detailem)
1250 res
= QFReportItemBand::printMetaPaint(out
, designedRect
);
1251 //res = printMetaPaintChildren(pg, pg->renderedRect);
1252 qfTrash() << "\t\x1B[1;31;40m<<< ***ROOT***ROOT***ROOT***ROOT***\x1B[0;37;40m";
1253 //res = checkPrintResult(res);
1257 QFXmlTable
& QFReportItemReport::dataTable()
1262 //==========================================================
1264 //==========================================================
1266 QFReportProcessorItem::PrintResult QFReportItemBody::printMetaPaint(QFReportItemMetaPaint *out, const QFReportProcessorItem::Rect &bounding_rect )
1268 qfTrash() << QF_FUNC_NAME;
1269 PrintResult res = QFReportItemDetail::printMetaPaint(out, bounding_rect);
1270 /// body jediny ma tu vysadu, ze se muze vickrat za sebou nevytisknout a neznamena to print forever.
1271 if(res == PrintNeverFit) res = PrintNotFit;
1276 //==========================================================
1277 // QFReportItemHeaderFrame
1278 //==========================================================
1279 QFReportProcessorItem::PrintResult
QFReportItemHeaderFrame::printMetaPaint(QFReportItemMetaPaint
*out
, const QFReportProcessorItem::Rect
&bounding_rect
)
1281 qfTrash() << QF_FUNC_NAME
;
1282 return QFReportItemFrame::printMetaPaint(out
, bounding_rect
);
1285 //==========================================================
1287 //==========================================================
1288 QFReportProcessorItem::PrintResult
QFReportItemRow::printMetaPaint(QFReportItemMetaPaint
*out
, const Rect
&bounding_rect
)
1290 qfTrash() << QF_FUNC_NAME
;
1291 return QFReportItemFrame::printMetaPaint(out
, bounding_rect
);
1294 //==========================================================
1296 //==========================================================
1297 QFReportProcessorItem::PrintResult
QFReportItemCell::printMetaPaint(QFReportItemMetaPaint
*out
, const Rect
&bounding_rect
)
1299 qfTrash() << QF_FUNC_NAME
;
1300 return QFReportItemFrame::printMetaPaint(out
, bounding_rect
);
1303 //==========================================================
1305 //==========================================================
1306 QFReportItemPara::QFReportItemPara(QFReportProcessor
* proc
, QFReportProcessorItem
* parent
, const QFDomElement
& el
)
1307 : QFReportItemFrame(proc
, parent
, el
)
1310 //qfInfo() << el.text();
1313 void QFReportItemPara::resetIndexToPrintRecursively(bool including_para_texts
)
1315 if(including_para_texts
) indexToPrint
= 0;
1318 QFReportProcessorItem::PrintResult
QFReportItemPara::printMetaPaint(QFReportItemMetaPaint
*out
, const Rect
&bounding_rect
)
1321 return QFReportItemFrame::printMetaPaint(out
, bounding_rect
);
1324 QFReportProcessorItem::PrintResult
QFReportItemPara::printMetaPaintChildren(QFReportItemMetaPaint
*out
, const QFReportProcessorItem::Rect
&bounding_rect
)
1326 qfTrash().color(QFLog::Yellow
) << QF_FUNC_NAME
<< element
.tagName() << "id:" << element
.attribute("id");
1327 PrintResult res
= PrintOk
;
1328 if(indexToPrint
== 0) {
1329 printedText
= paraText();
1331 QString text
= printedText
.mid(indexToPrint
);
1333 QFGraphicsStyleCache::Style style
= processor
->context().styleCache().style(elementAttribute("style"));
1336 s
= elementAttribute("font");
1337 if(!!s
) style
.font
= processor
->context().styleCache().font(s
);
1338 s
= elementAttribute("pen");
1339 if(!!s
) style
.pen
= processor
->context().styleCache().pen(s
);
1340 //QBrush brush = processor->context().brushFromString(element.attribute("brush"));
1341 qfTrash() << "\tfont:" << style
.font
.toString();
1342 //qfTrash() << "\tpen color:" << pen.color().name();
1343 //qfTrash() << "\tbrush color:" << brush.color().name();
1345 QFontMetricsF font_metrics
= processor
->fontMetrics(style
.font
);
1348 if(QFString(elementAttribute("wrap", "1")).toBool()) flags
|= Qt::TextWordWrap
;
1350 s
= elementAttribute("halign", "left");
1351 if(s
== "center") flags
|= Qt::AlignHCenter
;
1352 else if(s
== "right") flags
|= Qt::AlignRight
;
1353 else if(s
== "justify") flags
|= Qt::AlignJustify
; /// ma smysl jen pro para
1354 s
= element
.attribute("valign", "top");
1355 if(s
== "center") flags
|= Qt::AlignVCenter
;
1356 else if(s
== "bottom") flags
|= Qt::AlignBottom
;
1360 /// velikost boundingRect je v mm, tak to prepocitej na body vystupniho zarizeni
1361 br
= QFGraphics::mm2device(bounding_rect
, processor
->paintDevice());
1363 bool render_check_mark
= false;
1364 bool text_item_should_be_created
= true;
1365 QRegExp rx
= QFReportItemMetaPaint::checkReportSubstitutionRegExp
;
1366 if(rx
.exactMatch(text
)) {
1367 //bool check_on = rx.capturedTexts().value(1) == "1";
1368 br
= font_metrics
.boundingRect('X');
1369 render_check_mark
= true;
1373 //text.replace(QFReportItemMetaPaint::checkOnReportSubstitution, "X");
1374 //text.replace(QFReportItemMetaPaint::checkOffReportSubstitution, "X");
1375 //qfInfo().noSpace().color(QFLog::Green) << "index to print: " << indexToPrint << " text: '" << text << "'";
1376 //qfInfo() << "bounding rect:" << bounding_rect.toString();
1377 //qfWarning() << "device physical DPI:" << processor->paintDevice()->physicalDpiX() << processor->paintDevice()->physicalDpiY();
1378 //qfWarning().noSpace() << "'" << text << "' font metrics: " << br.toString();
1380 //QString text = element.text().simplified().replace("\\n", "\n");
1381 //qfInfo() << "br:" << br.toString();
1382 //Rect br_debug = br;
1383 //bool splitted = false;
1386 qreal leading
= font_metrics
.leading();
1389 textLayout
.setFont(style
.font
);
1390 Qt::Alignment alignment
= (~Qt::Alignment()) & flags
;
1391 QTextOption
opt(alignment
);
1392 opt
.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere
);
1393 textLayout
.setTextOption(opt
);
1394 textLayout
.setText(text
);
1395 textLayout
.beginLayout();
1396 //bool rubber_frame = designedRect.isRubber(LayoutVertical);
1398 //QString tx1 = text;
1399 //qfInfo() << "text to layout:" << text;
1401 QTextLine line
= textLayout
.createLine();
1402 if(!line
.isValid()) {
1403 //qfInfo() << "veslo se VSECHNO";
1404 indexToPrint
= printedText
.length();
1407 //old_pos = line.textStart();
1408 line
.setLineWidth(br
.width()); /// setWidth() nastavi spravne line.height(), proto musi byt pred merenim popsane vysky.
1409 qreal interline_space
= (height
> 0)? leading
: 0;
1410 if(height
+ interline_space
+ line
.height() > br
.height()) {
1411 //qfInfo() << "NEEEEEEEE veslo se";
1414 /// nevejde se ani jeden radek
1415 text_item_should_be_created
= false;
1419 /// neco se preci jenom veslo
1421 //qfInfo() << "\tbounding_rect rect:" << bounding_rect.toString();
1422 //qfInfo() << "\tbr:" << br.toString();
1423 //qfInfo() << "\theight:" << height;
1424 int pos
= line
.textStart();
1425 //qfInfo() << "POS:" << pos << text.mid(pos).left(50);
1426 indexToPrint
+= pos
;
1427 text
= text
.left(pos
);
1430 //line.setLineWidth(123456789); /// vytiskni to az do konce
1432 height
+= interline_space
;
1433 //qfInfo() << "LINE ##:" << line.textStart() << text.mid(line.textStart(), line.textLength());
1434 line
.setPosition(QPointF(0., height
));
1435 height
+= line
.height();
1436 width
= qMax(width
, line
.naturalTextWidth());
1438 textLayout
.endLayout();
1440 br
.setHeight(height
);
1441 // musim to takhle premerit, jina
1442 //br = font_metrics.boundingRect(br, flags, text);
1443 //br = font_metrics.boundingRect(br_debug, 0, text);
1444 //qfInfo() << "\tbr2:" << br.toString();
1448 int x_dpi = processor->paintDevice()->logicalDpiX();
1449 int y_dpi = processor->paintDevice()->logicalDpiY();
1450 br.setWidth(br.width() * 25.4 / x_dpi);
1451 br.setHeight(br.height() * 25.4 / y_dpi);
1453 /// velikost boundingRect je v bodech vystupniho zarizeni, tak to prepocitej na mm
1454 br
= QFGraphics::device2mm(br
, processor
->paintDevice());
1455 //if(splitted) qfInfo() << "\tbr [mm]:" << br.toString();
1456 //qfWarning().noSpace() << "'" << text << "' font metrics: " << br.toString();
1457 /// posun to na zacatek, alignment ramecku to zase vrati
1458 br
.moveTopLeft(bounding_rect
.topLeft());
1459 // odecti mezeru mezi radky za poslednim radkem
1460 //br.setHeight(br.height() - processor->fontMetrics(style.font).leading());
1461 //qfInfo().noSpace() << "text: '" << text << "'";
1462 //qfInfo() << "\tbr:" << br.toString() << "text_item_should_be_created:" << text_item_should_be_created;
1463 if(br
.width() == 0) {
1464 /// tiskne se prazdny text
1465 if(QFString(elementAttribute("omitEmptyString")).toBool()) text_item_should_be_created
= false;
1467 if(text_item_should_be_created
) {
1468 QFReportItemMetaPaintText
*mt
;
1469 if(render_check_mark
) mt
= new QFReportItemMetaPaintCheck(out
, this);
1470 else mt
= new QFReportItemMetaPaintText(out
, this);
1471 mt
->pen
= style
.pen
;
1472 //mt->brush = brush;
1473 mt
->font
= style
.font
;
1476 //mt->renderCheck = render_check;
1477 //if(flags & (Qt::AlignHCenter | Qt::AlignRight)) br.setLeft(bounding_rect.left());
1478 //if(flags & (Qt::AlignVCenter | Qt::AlignBottom)) br.setWidth(bounding_rect.height());
1479 mt
->renderedRect
= br
;
1480 mt
->renderedRect
.flags
= designedRect
.flags
;
1482 //qfTrash().color(QFLog::Green, QFLog::Red) << "\tleading:" << processor->fontMetrics(style.font).leading() << "\theight:" << processor->fontMetrics(style.font).height();
1483 qfTrash() << "\tchild rendered rect:" << br
.toString();
1484 qfTrash() << "\t<<< CHILDREN paraText return:" << res
.toString();
1485 //res = checkPrintResult(res);
1489 QString
QFReportItemPara::paraText()
1491 qfTrash().color(QFLog::Cyan
) << QF_FUNC_NAME
;
1493 QString to_localize
;
1494 QStringList data_texts
;
1496 for(QFDomNode nd
= element
.firstChild(); !!nd
; nd
= nd
.nextSibling()) {
1498 to_localize
+= nodeText(nd
);
1501 to_localize
+= '%' + QString::number(++data_cnt
);
1502 data_texts
<< nodeText(nd
);
1506 QByteArray ba
= to_localize
.toUtf8();
1507 ret
= QCoreApplication::translate("report", ba
.constData(), 0, QCoreApplication::UnicodeUTF8
);
1508 //ret = QCoreApplication::trUtf8(ba.constData(), "report");
1509 //qfInfo() << to_localize << "->" << ret;
1510 for(int i
=0; i
<data_texts
.count(); i
++) ret
= ret
.arg(data_texts
.value(i
));
1512 //qfTrash().color(QFLog::Cyan) << "\treturn:" << ret;
1514 static QString new_line
;
1515 if(new_line
.isEmpty()) new_line
+= QChar::LineSeparator
;
1516 ret
.replace("\\n", new_line
);
1517 ret
.replace("\n", new_line
);
1519 /// jinak nedokazu zadat mezeru mezi dvema <data> elementy nez <data>\s<data>
1520 ret
.replace("\\s", " ");
1522 //qfInfo().noSpace() << "'" << ret << "'";
1527 //==========================================================
1529 //==========================================================
1530 QFReportItemBand::QFReportItemBand(QFReportProcessor
*proc
, QFReportProcessorItem
*parent
, const QFDomElement
&_el
)
1531 : QFReportItemFrame(proc
, parent
, _el
), dataTableLoaded(false)
1535 void QFReportItemBand::resetIndexToPrintRecursively(bool including_para_texts
)
1537 QFReportItemFrame::resetIndexToPrintRecursively(including_para_texts
);
1538 //qfInfo() << "dataTableLoaded = false" << element.attribute("id");
1539 dataTableLoaded
= false;
1542 QFXmlTable
& QFReportItemBand::dataTable()
1544 //qfLogFuncFrame() << "dataTableLoaded:" << dataTableLoaded;
1545 if(!dataTableLoaded
) {
1546 QFDomElement el_data_src
= element
.firstChildElement("datasrc");
1547 QFDomElement el_data
= el_data_src
.firstChildElement("data");
1548 QString data_src_name
= el_data_src
.attribute("name");
1549 //QString data_domain = el_data_src.attribute("domain", "table");
1550 if(data_src_name
.isEmpty()) {
1551 /// drive nebyly podporovany domeny pro data, zkus starsi zpusob
1552 /// v kazdem pripade, pokud neni definovano datasrc, je datadomain vzdy "table"
1553 data_src_name
= element
.attribute("datatablename");
1554 //data_domain = "table";
1556 //qfInfo() << "\t data_src_name:" << data_src_name;
1557 if(el_data
.isNull()) {
1558 //qfInfo() << "loading datatablename:" << data_src_name;
1559 f_dataTable
= findDataTable(data_src_name
);
1562 //qfInfo() << "\t loading data to f_dataTable";
1563 QVariant v
= nodeValue(el_data
);
1564 f_dataTableOwnerDocument
= v
.value
<QFXmlTableDocument
>();
1565 //qfInfo() << "\t" << f_dataTableOwnerDocument.toString();
1566 f_dataTable
= f_dataTableOwnerDocument
.toTable();
1568 dataTableLoaded
= true;
1573 QFReportProcessorItem::PrintResult
QFReportItemBand::printMetaPaint(QFReportItemMetaPaint
*out
, const Rect
&bounding_rect
)
1575 //qfInfo() << __LINE__;
1576 qfTrash().color(QFLog::White
) << QF_FUNC_NAME
;
1577 //qfInfo() << "src:" << element.attribute("datatablename") << "table is null:" << dataTable().isNull();
1578 //qfInfo() << dataTable().toString();
1579 if(dataTable().isNull() && !processor
->isDesignMode()) { /// pokud neni table (treba bez radku), band se vubec netiskne
1581 res
.value
= PrintOk
;
1584 if(QFString(element
.attribute("headeronbreak")).toBool()) {
1585 /// vsechno krome detailu se bude tisknout znovu
1586 for(int i
=0; i
<children().count(); i
++) {
1587 QFReportProcessorItem
*it
= childAt(i
);
1588 if(it
->toDetail() == NULL
) it
->resetIndexToPrintRecursively(QFReportProcessorItem::IncludingParaTexts
);
1592 PrintResult res
= QFReportItemFrame::printMetaPaint(out
, bounding_rect
);
1593 //res = checkPrintResult(res);
1594 qfTrash().color(QFLog::Green
) << "\tRETURN:" << res
.toString();
1598 //==========================================================
1599 // QFReportItemDetail
1600 //==========================================================
1601 QFReportItemDetail::QFReportItemDetail(QFReportProcessor
*proc
, QFReportProcessorItem
*parent
, const QFDomElement
&_el
)
1602 : QFReportItemFrame(proc
, parent
, _el
)
1604 //qfInfo() << QF_FUNC_NAME;
1608 QFReportProcessorItem::PrintResult
QFReportItemDetail::printMetaPaint(QFReportItemMetaPaint
*out
, const Rect
&bounding_rect
)
1610 qfTrash().color(QFLog::Blue
) << QF_FUNC_NAME
<< element
.tagName() << "id:" << element
.attribute("id");
1611 //qfInfo() << QF_FUNC_NAME;
1612 bool design_mode
= processor
->isDesignMode(); /// true znamena, zobraz prvni radek, i kdyz tam nejsou data.
1613 //qfInfo() << "design mode:" << design_mode;
1614 QFReportItemBand
*b
= parentBand();
1616 qfTrash() << "\t band:" << b
<< "table is null:" << b
->dataTable().isNull();
1617 if(!b
->dataTable().isNull()) {
1618 //design_view = false;
1619 if(f_dataRow
.isNull()) {
1620 /// kdyz neni f_dataRow, vezmi prvni radek dat
1621 f_dataRow
= b
->dataTable().firstRow();
1622 //qfInfo() << "\ttaking first row, is null:" << f_dataRow.isNull();
1628 if(!design_mode
&& f_dataRow
.isNull()) {
1629 /// prazdnej detail vubec netiskni
1630 res
.value
= PrintOk
;
1633 res
= QFReportItemFrame::printMetaPaint(out
, bounding_rect
);
1634 if(res
.value
== PrintOk
) {
1636 /// vezmi dalsi radek dat
1637 f_dataRow
= b
->dataTable().nextRow(f_dataRow
);
1639 //qfInfo() << "\ttaking next row" << f_currentRowNo << "is null:" << f_dataRow.isNull();
1640 if(!f_dataRow
.isNull()) {
1641 resetIndexToPrintRecursively(QFReportProcessorItem::IncludingParaTexts
);
1642 res
.flags
|= FlagPrintAgain
;
1646 //res = checkPrintResult(res);
1647 qfTrash().color(QFLog::Blue
) << "\treturn:" << res
.toString();
1651 //==========================================================
1652 // QFReportItemTable
1653 //==========================================================
1654 QFReportItemTable::QFReportItemTable(QFReportProcessor
*proc
, QFReportProcessorItem
*_parent
, const QFDomElement
&_el
)
1655 : QFReportItemBand(proc
, _parent
, _el
)
1657 //qfTrash() << QF_FUNC_NAME << "parent:" << parent();
1658 //QF_ASSERT(!!_el, "element is null.");
1661 void QFReportItemTable::syncChildren()
1663 qfTrash() << QF_FUNC_NAME
<< element
.tagName() << "id:" << element
.attribute("id");
1665 for(QFDomElement el
= fakeBand
.firstChildElement(); !!el
; el
= el
.nextSiblingElement()) {
1666 if(!QFReportProcessor::isProcessible(el
)) continue;
1667 /// vytvor chybejici item
1668 processor
->createProcessibleItem(el
, this);
1670 qfTrash() << QF_FUNC_NAME
<< "<<<<<<<<<<<<<<<< OUT";
1673 void QFReportItemTable::createFakeBand()
1676 if(!!fakeBand
) return;
1678 bool from_data
= element
.attribute("createfromdata").toBool();
1679 QString decoration
= element
.attribute("decoration");
1680 bool grid
= (decoration
== "grid");
1681 bool horizontal_lines
= (decoration
== "horizontallines");
1682 bool line
= !decoration
.isEmpty();
1683 QString line_pen
= (grid
)? "black1": "black1";
1684 bool shadow
= element
.attribute("shadow", "1").toBool();
1686 fakeBand
= fakeBandDocument
.createElement("band");
1687 fakeBandDocument
.appendChild(fakeBand
);
1688 fakeBand
.setAttribute("__fake", 1); /// napomaha pri selekci v report editoru
1690 QFDomElement el_header
, el_detail
, el_footer
;
1692 QFDomElement el
, el1
;
1694 el1
= fakeBand
.ownerDocument().createElement("row");
1695 el
= element
.firstChildElement("headerframe");
1696 el1
.copyAttributesFrom(el
);
1697 /// v tabulce ma smysl mit deti zarovnany
1698 if(grid
&& el1
.attribute("expandChildrenFrames").isEmpty()) el1
.setAttribute("expandChildrenFrames", "1");
1699 if(line
&& el1
.attribute("bbrd").isEmpty()) el1
.setAttribute("bbrd", line_pen
);
1700 else if(horizontal_lines
) el1
.setAttribute("bbrd", line_pen
);
1701 if(shadow
&& el1
.attribute("fill").isEmpty()) el1
.setAttribute("fill", "tblshadow");
1703 el_header
.setAttribute("__fakeBandHeaderRow", 1); /// napomaha exportu do HTML
1705 el1
= fakeBand
.ownerDocument().createElement("detail");
1706 el
= element
.firstChildElement("detailframe");
1707 el1
.copyAttributesFrom(el
);
1708 if(grid
&& el1
.attribute("expandChildrenFrames").isEmpty()) el1
.setAttribute("expandChildrenFrames", "1");
1709 if(el1
.attribute("keepall").isEmpty()) el1
.setAttribute("keepall", "1");
1710 if(horizontal_lines
) el1
.setAttribute("bbrd", line_pen
);
1712 el_detail
.setAttribute("__fakeBandDetail", 1); /// napomaha exportu do HTML
1714 el1
= fakeBand
.ownerDocument().createElement("row");
1715 el
= element
.firstChildElement("footerframe");
1716 el1
.copyAttributesFrom(el
);
1717 if(grid
&& el1
.attribute("expandChildrenFrames").isEmpty()) el1
.setAttribute("expandChildrenFrames", "1");
1718 if(line
) el1
.setAttribute("tbrd", line_pen
);
1719 else if(horizontal_lines
) el1
.setAttribute("bbrd", line_pen
);
1720 if(shadow
) el1
.setAttribute("fill", "tblshadow");
1722 el_footer
.setAttribute("__fakeBandFooterRow", 1); /// napomaha exportu do HTML
1725 bool has_footer
= false;
1727 qfTrash() << "\tcreating from data";
1728 QFXmlTable t
= dataTable();
1729 //foreach(const QFXmlTableColumnDef cd, t.columns()) if(!t.columnFooter(cd.name).isEmpty()) {has_footer = true; break;}
1730 QFXmlTableColumnList cols
= t
.columns();
1731 foreach(const QFXmlTableColumnDef cd
, t
.columns()) {
1733 QFDomElement el
= fakeBand
.ownerDocument().createElement("para");
1734 el
.setAttribute("w", "%");
1735 el
.setAttribute("hinset", "1");
1736 el
.setAttribute("style", "tblheading");
1737 el
.setAttribute("halign", "center");
1738 if(grid
) el
.setAttribute("brd", "black1");
1739 QDomText txt
= fakeBand
.ownerDocument().createTextNode(t
.columnHeader(cd
.name
));
1740 el
.appendChild(txt
);
1741 el_header
.appendChild(el
);
1744 QFDomElement el
= fakeBand
.ownerDocument().createElement("para");
1745 el
.setAttribute("w", "%");
1746 el
.setAttribute("hinset", "1");
1747 el
.setAttribute("style", "tbltext");
1748 el
.setAttribute("halign", t
.columnHAlignment(cd
.name
));
1749 if(grid
) el
.setAttribute("brd", "black1");
1750 QFDomElement el1
= fakeBand
.ownerDocument().createElement("data");
1751 el1
.setAttribute("src", cd
.name
);
1752 el
.appendChild(el1
);
1753 el_detail
.appendChild(el
);
1756 QString footer
= t
.columnFooter(cd
.name
);
1757 if(!footer
.isEmpty()) has_footer
= true;
1758 QFDomElement el
= fakeBand
.ownerDocument().createElement("para");
1759 el
.setAttribute("w", "%");
1760 el
.setAttribute("hinset", "1");
1761 el
.setAttribute("style", "tbltextB");
1762 el
.setAttribute("halign", t
.columnHAlignment(cd
.name
));
1763 if(grid
) el
.setAttribute("brd", "black1");
1764 QDomText txt
= fakeBand
.ownerDocument().createTextNode(footer
);
1765 el
.appendChild(txt
);
1766 el_footer
.appendChild(el
);
1771 QFDomElement el
= element
.firstChildElement("cols");
1772 for(el
=el
.firstChildElement("col"); !!el
; el
=el
.nextSiblingElement("col")) {
1773 //QString w = el.attribute("w");
1775 el1
= el
.firstChildElement("colheader");
1777 el1
= el1
.cloneNode().toElement();
1778 el1
.setTagName("cell");
1780 else el1
= fakeBand
.ownerDocument().createElement("cell");
1781 el1
.copyAttributesFrom(el
);
1782 if(grid
) el1
.setAttribute("brd", "black1");
1783 el_header
.appendChild(el1
);
1784 //if(!w.isEmpty()) el1.setAttribute("w", w);
1786 el1
= el
.firstChildElement("coldetail");
1788 el1
= el1
.cloneNode().toElement();
1789 el1
.setTagName("cell");
1790 if(grid
) el1
.setAttribute("brd", "black1");
1792 else el1
= fakeBand
.ownerDocument().createElement("cell");
1793 el1
.copyAttributesFrom(el
);
1794 el_detail
.appendChild(el1
);
1795 //if(!w.isEmpty()) el1.setAttribute("w", w);
1797 el1
= el
.firstChildElement("colfooter");
1800 el1
= el1
.cloneNode().toElement();
1801 el1
.setTagName("cell");
1802 if(grid
) el1
.setAttribute("brd", "black1");
1804 else el1
= fakeBand
.ownerDocument().createElement("cell");
1805 el1
.copyAttributesFrom(el
);
1806 el_footer
.appendChild(el1
);
1807 //if(!w.isEmpty()) el1.setAttribute("w", w);
1811 fakeBand
.appendChild(el_header
);
1812 fakeBand
.appendChild(el_detail
);
1813 if(has_footer
) fakeBand
.appendChild(el_footer
);
1814 //qfInfo() << fakeBand.toString();
1817 QFReportProcessorItem::PrintResult
QFReportItemTable::printMetaPaint(QFReportItemMetaPaint
*out
, const QFReportProcessorItem::Rect
&bounding_rect
)
1820 return QFReportItemBand::printMetaPaint(out
, bounding_rect
);
1823 //===============================================================
1825 //===============================================================
1826 QFReportProcessorItem::PrintResult QFReportItemIf::printMetaPaintChildren(QFReportItemMetaPaint *out, const QFReportProcessorItem::Rect &bounding_rect)
1828 qfTrash().color(QFLog::Magenta) << QF_FUNC_NAME << element.tagName() << "id:" << element.attribute("id");
1829 qfTrash() << "\tbounding_rect:" << bounding_rect.toString();
1830 PrintResult res = PrintOk;
1831 Rect bbr = bounding_rect;
1833 QFDomElement el = element.firstChildElement();
1835 bool bool_res = nodeValue(el).toBool();
1836 QFReportProcessorItem *it_res = NULL;
1837 for(int i=indexToPrint; i<children().count(); i++) {
1838 QFReportProcessorItem *it = childAt(i);
1840 if(dynamic_cast<QFReportItemIfTrue*>(it)) {
1846 if(dynamic_cast<QFReportItemIfFalse*>(it)) {
1853 res = it_res->printMetaPaint(out, bbr);
1859 //===============================================================
1860 // QFReportItemImage
1861 //===============================================================
1862 bool QFReportItemImage::childrenSynced()
1864 return childrenSyncedFlag
;
1867 void QFReportItemImage::syncChildren()
1869 qfTrash() << QF_FUNC_NAME
<< element
.tagName() << "id:" << element
.attribute("id");
1870 QString orig_src
= element
.attribute("src");
1871 QString processor_img_key
;
1873 QFReportProcessorItem::Image im
;
1874 if(orig_src
.startsWith("key:/")) {
1875 /// obrazek je ocekavan v processor->images(), takze neni treba delat nic
1878 else if(orig_src
.isEmpty()) {
1879 /// obrazek bude v datech
1882 if(!src
.isEmpty()) {
1883 src
= QFReportProcessor::searchDirs().findFile(src
);
1885 qfWarning().noSpace() << "file '" << orig_src
<< "' does not exists in " << QFReportProcessor::searchDirs().dirs().join(", ");
1886 /// pridej fake para element, aby se jmeno chybejiciho souboru zobrazilo v reportu
1887 if(fakeLoadErrorPara
.isNull()) {
1888 //qfInfo() << "creating fakeLoadErrorPara:" << orig_src;
1889 fakeLoadErrorPara
= fakeLoadErrorParaDocument
.createElement("para");
1890 fakeLoadErrorParaDocument
.appendChild(fakeLoadErrorPara
);
1891 fakeLoadErrorPara
.setAttribute("__fake", 1);
1892 fakeLoadErrorPara
.appendChild(fakeLoadErrorPara
.ownerDocument().createTextNode(orig_src
));
1893 processor
->createProcessibleItem(fakeLoadErrorPara
, this);
1894 //qfInfo() << "children cnt:" << this->children().count();
1895 //qfInfo() << "this:" << this << "childrencount" << children().count() << "\n" << toString();
1900 qfTrash() << "orig_src:" << orig_src
;
1901 qfTrash() << "src:" << src
;
1902 if(!src
.isEmpty()) {
1903 if(src
.endsWith(".svg", Qt::CaseInsensitive
)) {
1905 if(!ren
.load(src
)) qfWarning() << "SVG data read error src:" << src
;
1907 //qfInfo() << "default size::" << ren.defaultSize().width() << ren.defaultSize().height();
1909 QPainter
painter(&pic
);
1910 ren
.render(&painter
);
1913 //qfInfo() << "bounding rect:" << Rect(pic.boundingRect()).toString();
1917 im
.image
= QImage(src
);
1919 if(!im
.isNull()) processor_img_key
= orig_src
;
1921 if(im
.isNull() && !orig_src
.isEmpty()) {
1922 /// pridej fake para element, aby se jmeno chybejiciho souboru zobrazilo v reportu
1923 qfWarning().noSpace() << "QImage('" << src
<< "') constructor error.";
1924 if(fakeLoadErrorPara
.isNull()) {
1925 fakeLoadErrorPara
= fakeLoadErrorParaDocument
.createElement("para");
1926 fakeLoadErrorParaDocument
.appendChild(fakeLoadErrorPara
);
1927 fakeLoadErrorPara
.setAttribute("__fake", 1);
1928 fakeLoadErrorPara
.appendChild(fakeLoadErrorPara
.ownerDocument().createTextNode("QImage('" + src
+ "') constructor error."));
1929 processor
->createProcessibleItem(fakeLoadErrorPara
, this);
1934 processor
->addImage(processor_img_key
, QFReportProcessorItem::Image(im
));
1935 src
= processor_img_key
;
1937 qfTrash() << "src:" << src
;
1938 //QFReportProcessorItem::syncChildren();
1939 childrenSyncedFlag
= true;
1942 QFReportItemImage::PrintResult
QFReportItemImage::printMetaPaintChildren(QFReportItemMetaPaint
*out
, const QFReportProcessorItem::Rect
&bounding_rect
)
1944 qfTrash().color(QFLog::Magenta
) << QF_FUNC_NAME
<< element
.tagName() << "id:" << element
.attribute("id");
1945 qfTrash() << "\tbounding_rect:" << bounding_rect
.toString();
1946 PrintResult res
= PrintOk
;
1947 Rect br
= bounding_rect
;
1948 //QFLog::setDomainTresholds(QStringList() << "qfreportitem");
1949 if(!fakeLoadErrorPara
.isNull()) {
1950 /// src nebyl nalezen, child je para, kde je uvedeno, jak se jmenoval nenalezeny obrazek
1951 //qfInfo() << "this:" << this << "childrencount" << children().count() << "\n" << toString();
1952 QFReportItemFrame::printMetaPaintChildren(out
, bounding_rect
);
1953 //QString orig_src = element.attribute("src");
1954 //QFReportItemMetaPaintText *txt = new QFReportItemMetaPaintText(out, this);
1957 QFReportProcessorItem::Image im
= processor
->images().value(src
);
1959 /// muze byt jeste v datech, zkus ho nahrat pro aktualni radek
1960 QFDomElement el
= element
.firstChildElement("data");
1961 QString data_s
= nodeText(el
);
1962 //qfError() << data_s;
1964 QString format
= element
.attribute("dataformat");
1966 QString encoding
= element
.attribute("dataencoding");
1967 if(encoding
== "base64") {
1968 data
= QByteArray::fromBase64(data_s
.toAscii());
1970 else if(encoding
== "hex") {
1971 data
= QByteArray::fromHex(data_s
.toAscii());
1975 QString s
= element
.attribute("datacompression");
1976 if(s
== "qCompress") {
1977 data
= qUncompress(data
);
1980 if(!data
.isEmpty()) {
1981 if(format
== "svg") {
1983 if(!ren
.load(data
)) qfWarning() << "SVG data read error, format:" << format
;
1986 QPainter
painter(&pic
);
1987 ren
.render(&painter
);
1993 if(!im
.image
.load(data
, format
.toAscii())) qfWarning() << "Image data read error, format:" << format
;
1997 if(im
.isNull()) qfWarning() << "Printing an empty image";
1998 QFReportItemMetaPaintImage
*img
= new QFReportItemMetaPaintImage(out
, this);
1999 if(element
.attribute("suppressPrintOut").toBool()) {
2000 //qfInfo() << "\t suppressPrintOut";
2001 img
->layoutSettings()->suppressPrintOut
= true;
2003 //qfInfo() << "\t src:" << src;
2004 //qfInfo() << "\t processor->images().contains(" << src << "):" << processor->images().contains(src);
2005 QString aspect
= element
.attribute("aspectratio", "ignored");
2006 if(aspect
== "keep") {
2007 img
->aspectRatioMode
= Qt::KeepAspectRatio
;
2009 else if(aspect
== "keepexpanding") {
2010 img
->aspectRatioMode
= Qt::KeepAspectRatioByExpanding
;
2012 if(designedRect
.width() == 0 && designedRect
.horizontalUnit
== Rect::UnitMM
&& designedRect
.height() == 0 && designedRect
.verticalUnit
== Rect::UnitMM
) {
2016 w
= im
.image
.width() / (im
.image
.dotsPerMeterX() / 1000.);
2017 h
= im
.image
.height() / (im
.image
.dotsPerMeterY() / 1000.);
2018 if(w
> 0 && w
< br
.width()) br
.setWidth(w
);
2019 if(h
> 0 && h
< br
.height()) br
.setHeight(w
);
2021 else if(im
.isPicture()) {
2022 w
=im
.picture
.boundingRect().width();
2023 h
= im
.picture
.boundingRect().height();
2026 else if(designedRect
.width() == 0 && designedRect
.horizontalUnit
== Rect::UnitMM
) {
2027 /// rubber ve smeru x
2028 Size sz
= im
.size();
2029 double d
= br
.height() * sz
.width() / sz
.height();
2032 else if(designedRect
.height() == 0 && designedRect
.verticalUnit
== Rect::UnitMM
) {
2033 /// rubber ve smeru y
2034 //qfInfo() << "br:" << br.toString();
2035 Size sz
= im
.size();
2036 double d
= br
.width() * sz
.height() / sz
.width();
2040 /// oba smery zadany
2041 if(img
->aspectRatioMode
== Qt::KeepAspectRatioByExpanding
) {
2042 Size sz
= im
.size();
2043 /// pretece to designedrect ve smeru x?
2044 double d
= br
.height() * sz
.width() / sz
.height();
2045 if(d
> designedRect
.width()) {
2049 /// pretece to designedrect ve smeru y?
2050 d
= br
.width() * sz
.height() / sz
.width();
2051 if(d
> designedRect
.height()) {
2058 img
->renderedRect
= br
;
2059 img
->renderedRect
.flags
= designedRect
.flags
;
2061 //QFLog::setDomainTresholds(QStringList());
2066 //===============================================================
2067 // QFReportItemGraph
2068 //===============================================================
2069 void QFReportItemGraph::syncChildren()
2071 qfTrash() << QF_FUNC_NAME
<< element
.tagName() << "id:" << element
.attribute("id");
2072 static int graph_no
= 0;
2073 src
= QString("key:/graph-%1").arg(++graph_no
);
2075 childrenSyncedFlag
= true;
2076 QFReportProcessorItem::syncChildren();
2079 QFReportItemImage::PrintResult
QFReportItemGraph::printMetaPaintChildren(QFReportItemMetaPaint
*out
, const QFReportProcessorItem::Rect
&bounding_rect
)
2081 qfTrash().color(QFLog::Magenta
) << QF_FUNC_NAME
<< element
.tagName() << "id:" << element
.attribute("id");
2082 PrintResult res
= PrintOk
;
2083 Rect br
= bounding_rect
;
2085 /// vykresli graf a pridej ho do processor->images()
2087 QFGraph
*graph
= QFGraph::createGraph(element
, findDataTable(element
.attribute("datatablename")));
2089 graph
->setStyleCache(processor
->context().styleCache());
2091 painter
.begin(&pict
);
2092 graph
->draw(&painter
, br
.size());
2094 processor
->addImage(src
, QFReportProcessorItem::Image(pict
));
2097 //qfInfo() << "physicalDpiX:" << pict.physicalDpiX();
2098 //qfInfo() << "logicalDpiX:" << pict.logicalDpiX();
2099 //qfInfo() << "pict bounding_rect:" << Rect(pict.boundingRect()).toString();
2101 res
= QFReportItemImage::printMetaPaintChildren(out
, br
);