fixed some build related problems
[qsqlmon.git] / libqf / libqfgui / reports / processor / qfreportitem.cpp
blob203e5d4497fbc3aef85d663d3428b697e51dd0e6
2 //
3 // Author: Frantisek Vacek <fanda.vacek@volny.cz>, (C) 2006
4 //
5 // Copyright: See COPYING file that comes with this distribution
6 //
8 #include "qfreportpainter.h"
9 #include "qfreportprocessor.h"
10 #include "qfreportitem.h"
12 #include <qffileutils.h>
13 #include <qfsql.h>
14 #include <qfgraph.h>
15 #include <qfsqlquerytable.h>
17 #include <QDate>
18 #include <QCryptographicHash>
19 #include <QSvgRenderer>
21 #include <qflogcust.h>
23 //==========================================================
24 // QFReportItem
25 //==========================================================
27 QFReportItem::QFReportItem(QFReportItem *_parent, const QFDomElement &el)
28 : parent(_parent), element(el)
32 QFReportItem::~QFReportItem()
34 //clearChildren();
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();
66 bool synced = true;
67 int i = 0;
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
74 synced = false;
75 qfTrash() << "\t more elements";
76 break;
78 if(el == childAt(i)->element) {
79 /// stejny element na stejne posici
80 i++;
81 continue;
83 /// doslo k nejaky zmene nebo deti nejsou dosud vytvoreny
84 qfTrash() << "\t other element";
85 synced = false;
86 break;
88 if(i != children().count()) {
89 qfTrash() << "\t divny";
90 synced = false;
92 qfTrash() << "\treturn:" << synced;
93 return synced;
96 void QFReportProcessorItem::deleteChildren()
98 clearChildren();
100 foreach(QObject *o, this->children()) {
101 //qfTrash() << "\twant delete object:" << o;
102 //qfTrash() << "\tdeleting object:" << o;
103 //objectMap.take(o);
104 SAFE_DELETE(o);
109 void QFReportProcessorItem::syncChildren()
111 qfTrash() << QF_FUNC_NAME << element.tagName() << "id:" << element.attribute("id");
112 #if 0
113 QList<QFTreeItemBase*> lst;
114 for(QFDomElement el = element.firstChildElement(); !!el; el = el.nextSiblingElement()) {
115 if(!QFReportProcessor::isProcessible(el)) continue;
116 int i;
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
122 lst << childAt(i);
123 //qfTrash() << "\tmoved:" << (lst.last()->element.isNull()? "NULL": lst.last()->element.tagName());
124 children.removeAt(i);
126 else {
127 /// vytvor chybejici item
128 QFReportProcessorItem *it = processor->createItem(el, NULL);
129 it->f_parent = this;
130 lst << it;
131 //qfTrash() << "\tcreated:" << (lst.last()->element.isNull()? "NULL": lst.last()->element.tagName());
134 /// vymaz neaktualni itemy
135 clearChildren();
136 children = lst;
137 #else
138 deleteChildren();
139 for(QFDomElement el = element.firstChildElement(); !!el; el = el.nextSiblingElement()) {
140 if(el.tagName() == "script") {
141 QString code;
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);
148 continue;
150 if(!QFReportProcessor::isProcessible(el)) continue;
151 /// vytvor chybejici item
152 processor->createProcessibleItem(el, this);
154 #endif
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);
165 ret = rx.cap(2);
166 QStringList sl = ret.splitAndTrim(',', '\'');
167 QVariantList vl;
168 foreach(QString s, sl) vl << s;
169 QScriptValue sv = processor->scriptDriver()->call(this, fn, vl);
170 ret = sv.toString();
172 return ret;
175 QFReportItemBand* QFReportProcessorItem::parentBand()
177 QFReportProcessorItem *it = this->parent();
178 while(it) {
179 if(it->toBand()) return it->toBand();
180 it = it->parent();
182 return NULL;
185 QFReportItemDetail* QFReportProcessorItem::currentDetail()
187 QFReportProcessorItem *it = const_cast<QFReportProcessorItem *>(this);
188 while(it) {
189 if(it->toDetail()) return it->toDetail();
190 it = it->parent();
192 return NULL;
195 QFXmlTable QFReportProcessorItem::findDataTable(const QString &name)
197 qfLogFuncFrame();
198 QFXmlTable ret;
199 const QFReportItemDetail *d = currentDetail();
200 qfTrash() << "\tparent:" << parent() << "parent detail:" << d;
201 if(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();
210 return ret;
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);
224 return ret;
227 QVariant QFReportProcessorItem::concatenateNodeChildrenValues(const QDomNode & nd)
229 QVariant ret;
230 QDomElement el = nd.toElement();
231 for(QFDomNode nd1 = el.firstChild(); !!nd1; nd1 = nd1.nextSibling()) {
232 QVariant v1 = nodeValue(nd1);
233 if(0) {
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();
240 return ret;
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);
252 QString ret;
253 if(nd.isElement()) {
254 do {
255 QFDomElement el = nd.toElement();
256 bool hide_null = el.attribute("hidenull", "true").toBool();
257 if(!v.isValid() && !hide_null) {
258 ret = "{null}";
259 break;
261 bool hide_zero = el.attribute("hidezero").toBool();
262 if(hide_zero) {
263 if(v.type() == QVariant::Int && v.toInt() == 0) {
264 break;
266 else if(v.type() == QVariant::Double && v.toDouble() == 0) {
267 break;
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();
293 else {
294 if(format == "check") {
295 bool b = v.toBool();
296 QString s = QFReportItemMetaPaint::checkReportSubstitution;
297 s.replace("${STATE}", (b)? "1": "0");
298 ret = s;
300 else ret = v.toString();
302 } while(false);
304 else ret = v.toString();
305 return ret;
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";
313 QVariant ret;
314 qfTrash() << "\tnode type:" << nd.nodeType();
315 if(nd.isText()) {
316 QString s = nd.toText().data();
317 qfTrash().noSpace() << "\t\ttext: '" << s << "'";
318 ret = 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");
329 QVariantList params;
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") {
337 QString code;
338 for(QDomNode nd = el.firstChildElement("code").firstChild(); !nd.isNull(); nd = nd.nextSibling()) {
339 if(nd.isCDATASection()) {
340 code = nd.toCDATASection().data();
341 break;
344 if(!code.isEmpty()) {
345 QVariantMap params;
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);
353 while(i.hasNext()) {
354 i.next();
355 code.replace("${" + i.key() + '}', i.value().toString());
357 data_src = code;
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);
377 ret = data_value;
379 else {
380 qfWarning() << "unprocessible element:" << el.tagName();
383 qfTrash().color(QFLog::Cyan) << "\treturn:" << ret.toString() << QVariant::typeToName(ret.type());
384 return ret;
387 QVariant QFReportProcessorItem::value(const QString &data_src, const QString & domain, const QVariantList &params, 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) {
418 try {
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) {
426 try {
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 {
439 QFSqlQueryTable t;
440 t.reload(qs);
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);
457 if(!!el) {
458 QFXmlKeyVals kv(el);
459 data_value = kv.value(key);
461 else {
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";
468 if(band) {
469 QFXmlTable t = band->dataTable();
470 if(t.isNull()) {
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();
478 if(det) {
479 QFXmlTableRow r = det->dataRow();
480 qfTrash() << "\t\tdata row is null:" << r.isNull();
481 if(r.isNull()) {
482 if(info_if_not_found) data_value = '[' + data_src + ']';
484 else {
485 if(data_src == S_TABLE_ROWNO) {
486 data_value = det->currentRowNo() + 1;
488 else {
489 data_value = r.value(data_src, (info_if_not_found)? "$" + data_src: default_value);
493 else {
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());
499 return data_value;
502 QFReportItemMetaPaint * QFReportProcessorItem::createMetaPaintItem(QFReportItemMetaPaint * parent)
504 QFReportItemMetaPaint *ret = NULL;
505 ret = new QFReportItemMetaPaintFrame(parent, this);
506 return ret;
509 QString QFReportProcessorItem::toString(int indent, int indent_offset)
511 QString ret;
512 QString indent_str;
513 indent_str.fill(' ', indent_offset);
514 ret += indent_str + element.tagName();
515 for(int i=0; i<children().count(); i++) {
516 ret += '\n';
517 QFReportProcessorItem *it = childAt(i);
518 ret += it->toString(indent, indent_offset += indent);
520 return ret;
523 //==========================================================
524 // QFReportItemBreak
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;
531 breaking = false;
534 QFReportProcessorItem::PrintResult QFReportItemBreak::printMetaPaint(QFReportItemMetaPaint *out, const QFReportProcessorItem::Rect &bounding_rect )
536 qfTrash() << QF_FUNC_NAME << element.tagName();
537 Q_UNUSED(bounding_rect);
538 Q_UNUSED(out);
539 PrintResult res = PrintOk;
540 if(!breaking) res = PrintNotFit;
541 breaking = !breaking;
542 return res;
545 //==========================================================
546 // QFReportItemFrame
547 //==========================================================
548 QFReportItemFrame::QFReportItemFrame(QFReportProcessor *proc, QFReportProcessorItem *parent, const QFDomElement &el)
549 : QFReportProcessorItem(proc, parent, el)
551 indexToPrint = 0;
552 qfTrash() << QF_FUNC_NAME << "*******************" << el.tagName() << el.attribute("id");
553 QFString s;
554 Point p;
555 s = element.attribute("x1");
556 if(!!s) {
557 designedRect.flags |= Rect::LeftFixed;
558 p.rx() = s.toDouble();
560 s = element.attribute("y1");
561 if(!!s) {
562 designedRect.flags |= Rect::TopFixed;
563 p.ry() = s.toDouble();
565 designedRect.setTopLeft(p);
566 s = element.attribute("x2");
567 if(!!s) {
568 designedRect.flags |= Rect::RightFixed;
569 p.rx() = s.toDouble();
571 s = element.attribute("y2");
572 if(!!s) {
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"); }
581 else {
582 if(s[-1] == '%') {
583 s = s.slice(0, -1);
584 //if(!s) s = 100;
585 designedRect.horizontalUnit = Rect::UnitPercent;
587 qreal d = s.toDouble();
588 if(d > 0) {
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"); }
600 else {
601 if(s[-1] == '%') {
602 s = s.slice(0, -1);
603 designedRect.verticalUnit = Rect::UnitPercent;
605 qreal d = s.toDouble();
606 if(d > 0) {
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();
617 if(s.toBool()) {
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();
624 if(s.toBool()) {
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;
633 hinset = vinset = 0;
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();
641 alignment = 0;
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;
682 int cnt_percent = 0;
683 int cnt_0_percent = 0;
684 int cnt_0_mm = 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;
700 cnt_percent++;
701 if(sz.size == 0) {
702 cnt_0_percent++;
703 //only_last_child_has_0_percent = true;
706 else if(sz.unit == Rect::UnitMM) {
707 if(sz.size == 0) {
708 last_rubber_ix = i;
709 cnt_0_mm++;
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
736 indexToPrint = 0;
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) {
755 /// tisk 2. metodou
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;
762 qreal sum_mm = 0;
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) {
769 Rect ch_bbr = bbr;
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) {
781 poradi_tisku << i;
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?"; }
789 else {
790 qfInfo() << "\t NOT OK";
791 res = ch_res;
792 break;
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) {
807 has_percent = true;
808 if(sz.size == 0) cnt_0_percent++;
809 else sum_percent += sz.size;
812 if(has_percent) {
813 if(rest_mm <= 0) {
814 qfWarning() << "Percent exist but rest_mm is" << rest_mm << ". Ignoring rest of frames";
816 else {
817 /// vytiskni procenta
818 qreal percent_0 = 0;
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) {
824 qreal d;
825 if(sz.size == 0) d = rest_mm * percent_0 / 100;
826 else d = rest_mm * sz.size / 100;
827 Rect ch_bbr = bbr;
828 ch_bbr.setWidth(d);
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) {
835 poradi_tisku << i;
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
850 qreal offset_x = 0;
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);
865 else {
866 /// can_print_children_in_natural_order
868 /// rozpocitej procenta
869 qreal sum_percent = 0;
870 cnt_0_percent = 0;
871 qreal sum_mm = 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;
882 qreal percent_0 = 0;
883 if(cnt_0_percent > 0) percent_0 = rest_percent / cnt_0_percent;
884 /// tiskni
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);
889 Rect ch_bbr = bbr;
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) {
902 qreal p = sz.size;
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();
938 else {
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);
946 else {
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;
956 res = ch_res;
957 break;
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();
964 return res;
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;
977 updateChildren();
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
983 bbr = designedRect;
984 if(bbr.isRubber(QFGraphics::LayoutHorizontal)) bbr.setRight(bounding_rect.right());
985 if(bbr.isRubber(QFGraphics::LayoutVertical)) bbr.setBottom(bounding_rect.bottom());
987 else {
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)";
1019 SAFE_DELETE(mp);
1020 return checkPrintResult(res);
1023 mp->setParent(out);
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;
1028 qreal sum_mm = 0;
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;
1036 if(offset > 0) {
1037 QFReportItemMetaPaint *it = mp->childAt(filllayout_child_ix);
1038 it->renderedRect.setSizeInLayout(it->renderedRect.sizeInLayout(layout) + offset, layout);
1039 it->alignChildren();
1040 Point p;
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);
1045 it->shift(p);
1050 #if 0
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();
1058 // mp->dump();
1060 qreal max_mm = 0;
1061 for(int i=0; i<mp->children.count(); i++) {
1062 QFReportItemMetaPaint *it = mp->childAt(i);
1063 //qfInfo() << "\t " << it->reportElement.toString();
1064 //it->dump();
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());
1072 #endif
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();
1105 /// alignment
1106 qfTrash() << "\tALIGN:" << QString::number((int)alignment, 16);
1107 //alignChildren(mp, dirty_rect);
1108 //if(0)
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");
1123 return res;
1126 void QFReportItemFrame::alignChildren(QFReportItemMetaPaintFrame *mp, const QFReportProcessorItem::Rect & dirty_rect)
1128 if(!dirty_rect.isNull()) {
1129 if(alignment & ~(Qt::AlignLeft | Qt::AlignTop)) {
1130 Point offset;
1131 /// ve smeru layoutu posun cely blok
1133 Rect r1;
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);
1139 qreal al = 0, d;
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();
1163 qreal al = 0, d;
1165 if(orthogonalLayout() == QFGraphics::LayoutHorizontal) {
1166 offset.rx() = 0;
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) {
1176 offset.ry() = 0;
1177 al = 0;
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;
1198 return frm->layout;
1201 void QFReportItemFrame::resetIndexToPrintRecursively(bool including_para_texts)
1203 //qfInfo() << "resetIndexToPrintRecursively()";
1204 indexToPrint = 0;
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();
1230 sz.transpose();
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;
1246 //updateChildren();
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);
1254 return res;
1257 QFXmlTable& QFReportItemReport::dataTable()
1259 return f_dataTable;
1262 //==========================================================
1263 // QFReportItemBody
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;
1272 return res;
1275 #if 0
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 //==========================================================
1286 // QFReportItemRow
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 //==========================================================
1295 // QFReportItemCell
1296 //==========================================================
1297 QFReportProcessorItem::PrintResult QFReportItemCell::printMetaPaint(QFReportItemMetaPaint *out, const Rect &bounding_rect)
1299 qfTrash() << QF_FUNC_NAME;
1300 return QFReportItemFrame::printMetaPaint(out, bounding_rect);
1302 #endif
1303 //==========================================================
1304 // QFReportItemPara
1305 //==========================================================
1306 QFReportItemPara::QFReportItemPara(QFReportProcessor * proc, QFReportProcessorItem * parent, const QFDomElement & el)
1307 : QFReportItemFrame(proc, parent, el)
1309 qfLogFuncFrame();
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)
1320 qfLogFuncFrame();
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"));
1335 QFString s;
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);
1346 int flags = 0;
1348 if(QFString(elementAttribute("wrap", "1")).toBool()) flags |= Qt::TextWordWrap;
1349 QFString s;
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;
1359 Rect br;
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;
1371 else {
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;
1384 /// do layout
1386 qreal leading = font_metrics.leading();
1387 qreal height = 0;
1388 qreal width = 0;
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);
1397 //int old_pos = 0;
1398 //QString tx1 = text;
1399 //qfInfo() << "text to layout:" << text;
1400 while (1) {
1401 QTextLine line = textLayout.createLine();
1402 if(!line.isValid()) {
1403 //qfInfo() << "veslo se VSECHNO";
1404 indexToPrint = printedText.length();
1405 break;
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";
1412 res = PrintNotFit;
1413 if(height == 0) {
1414 /// nevejde se ani jeden radek
1415 text_item_should_be_created = false;
1416 break;
1418 else {
1419 /// neco se preci jenom veslo
1420 //splitted = true;
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);
1428 break;
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();
1439 br.setWidth(width);
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;
1474 mt->text = text;
1475 mt->flags = flags;
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);
1486 return res;
1489 QString QFReportItemPara::paraText()
1491 qfTrash().color(QFLog::Cyan) << QF_FUNC_NAME;
1492 QString ret;
1493 QString to_localize;
1494 QStringList data_texts;
1495 int data_cnt = 0;
1496 for(QFDomNode nd = element.firstChild(); !!nd; nd = nd.nextSibling()) {
1497 if(nd.isText()) {
1498 to_localize += nodeText(nd);
1500 else {
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 << "'";
1523 return ret;
1527 //==========================================================
1528 // QFReportItemBand
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);
1561 else {
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;
1570 return f_dataTable;
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
1580 PrintResult res;
1581 res.value = PrintOk;
1582 return res;
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);
1590 indexToPrint = 0;
1592 PrintResult res = QFReportItemFrame::printMetaPaint(out, bounding_rect);
1593 //res = checkPrintResult(res);
1594 qfTrash().color(QFLog::Green) << "\tRETURN:" << res.toString();
1595 return res;
1598 //==========================================================
1599 // QFReportItemDetail
1600 //==========================================================
1601 QFReportItemDetail::QFReportItemDetail(QFReportProcessor *proc, QFReportProcessorItem *parent, const QFDomElement &_el)
1602 : QFReportItemFrame(proc, parent, _el)
1604 //qfInfo() << QF_FUNC_NAME;
1605 f_currentRowNo = 0;
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();
1615 if(b) {
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();
1623 f_currentRowNo = 0;
1627 PrintResult res;
1628 if(!design_mode && f_dataRow.isNull()) {
1629 /// prazdnej detail vubec netiskni
1630 res.value = PrintOk;
1631 return res;
1633 res = QFReportItemFrame::printMetaPaint(out, bounding_rect);
1634 if(res.value == PrintOk) {
1635 if(b) {
1636 /// vezmi dalsi radek dat
1637 f_dataRow = b->dataTable().nextRow(f_dataRow);
1638 f_currentRowNo++;
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();
1648 return res;
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");
1664 deleteChildren();
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()
1675 //return;
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");
1702 el_header = el1;
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);
1711 el_detail = el1;
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");
1721 el_footer = el1;
1722 el_footer.setAttribute("__fakeBandFooterRow", 1); /// napomaha exportu do HTML
1725 bool has_footer = false;
1726 if(from_data) {
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);
1770 else {
1771 QFDomElement el = element.firstChildElement("cols");
1772 for(el=el.firstChildElement("col"); !!el; el=el.nextSiblingElement("col")) {
1773 //QString w = el.attribute("w");
1774 QFDomElement el1;
1775 el1 = el.firstChildElement("colheader");
1776 if(!!el1) {
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");
1787 if(!!el1) {
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");
1798 if(!!el1) {
1799 has_footer = true;
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)
1819 createFakeBand();
1820 return QFReportItemBand::printMetaPaint(out, bounding_rect);
1823 //===============================================================
1824 // QFReportItemIf
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();
1834 if(!!el) {
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);
1839 if(bool_res) {
1840 if(dynamic_cast<QFReportItemIfTrue*>(it)) {
1841 it_res = it;
1842 break;
1845 else {
1846 if(dynamic_cast<QFReportItemIfFalse*>(it)) {
1847 it_res = it;
1848 break;
1852 if(it_res) {
1853 res = it_res->printMetaPaint(out, bbr);
1856 return res;
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;
1872 src = orig_src;
1873 QFReportProcessorItem::Image im;
1874 if(orig_src.startsWith("key:/")) {
1875 /// obrazek je ocekavan v processor->images(), takze neni treba delat nic
1876 src = QString();
1878 else if(orig_src.isEmpty()) {
1879 /// obrazek bude v datech
1880 src = QString();
1882 if(!src.isEmpty()) {
1883 src = QFReportProcessor::searchDirs().findFile(src);
1884 if(src.isEmpty()) {
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)) {
1904 QSvgRenderer ren;
1905 if(!ren.load(src)) qfWarning() << "SVG data read error src:" << src;
1906 else {
1907 //qfInfo() << "default size::" << ren.defaultSize().width() << ren.defaultSize().height();
1908 QPicture pic;
1909 QPainter painter(&pic);
1910 ren.render(&painter);
1911 painter.end();
1912 im.picture = pic;
1913 //qfInfo() << "bounding rect:" << Rect(pic.boundingRect()).toString();
1916 else {
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);
1931 src = QString();
1933 else {
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);
1956 else {
1957 QFReportProcessorItem::Image im = processor->images().value(src);
1958 if(src.isEmpty()) {
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;
1963 QByteArray data;
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") {
1982 QSvgRenderer ren;
1983 if(!ren.load(data)) qfWarning() << "SVG data read error, format:" << format;
1984 else {
1985 QPicture pic;
1986 QPainter painter(&pic);
1987 ren.render(&painter);
1988 painter.end();
1989 im.picture = pic;
1992 else {
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) {
2013 double w = 0;
2014 double h = 0;
2015 if(im.isImage()) {
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();
2030 br.setWidth(d);
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();
2037 br.setHeight(d);
2039 else {
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()) {
2046 br.setWidth(d);
2048 else {
2049 /// pretece to designedrect ve smeru y?
2050 d = br.width() * sz.height() / sz.width();
2051 if(d > designedRect.height()) {
2052 br.setHeight(d);
2057 img->image = im;
2058 img->renderedRect = br;
2059 img->renderedRect.flags = designedRect.flags;
2061 //QFLog::setDomainTresholds(QStringList());
2063 return res;
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()
2086 QPicture pict;
2087 QFGraph *graph = QFGraph::createGraph(element, findDataTable(element.attribute("datatablename")));
2088 if(graph) {
2089 graph->setStyleCache(processor->context().styleCache());
2090 QPainter painter;
2091 painter.begin(&pict);
2092 graph->draw(&painter, br.size());
2093 painter.end();
2094 processor->addImage(src, QFReportProcessorItem::Image(pict));
2095 delete graph;
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);
2102 return res;