ReportItem::PrintResult ReportItemBand::printMetaPaint(ReportItemMetaPaint *out, const ReportItem::Rect &bounding_rect) { qfLogFuncFrame() << this; if(isCreateFromData() && !detail()) { createChildItemsFromData(); } //qfInfo() << dataTable().toString(); /*-- if(dataTable().isNull() && !processor()->isDesignMode()) { /// pokud neni table (treba bez radku), band se vubec netiskne PrintResult res; res.value = PrintOk; return res; } --*/ if(isHeaderOnBreak()) { /// print everything except of detail again ReportItemDetail *it_det = detail(); if(it_det) it_det->resetIndexToPrintRecursively(ReportItem::IncludingParaTexts); indexToPrint = 0; } PrintResult res = Super::printMetaPaint(out, bounding_rect); qfDebug() << "\tRETURN:" << res.toString(); return res; }
ReportItem::PrintResult ReportItemBand::printMetaPaint(ReportItemMetaPaint *out, const Rect &bounding_rect) { qfLogFuncFrame() << this; //qfInfo() << dataTable().toString(); /*-- if(dataTable().isNull() && !processor()->isDesignMode()) { /// pokud neni table (treba bez radku), band se vubec netiskne PrintResult res; res.value = PrintOk; return res; } --*/ if(isHeaderOnBreak()) { /// print everything except of detail again for(int i=0; i<itemCount(); i++) { ReportItem *it = itemAt(i); if(it->toDetail() == NULL) it->resetIndexToPrintRecursively(ReportItem::IncludingParaTexts); } indexToPrint = 0; } PrintResult res = ReportItemFrame::printMetaPaint(out, bounding_rect); qfDebug() << "\tRETURN:" << res.toString(); return res; }
ReportItem::PrintResult ReportItemPara::printMetaPaintChildren(ReportItemMetaPaint *out, const ReportItem::Rect &bounding_rect) { qfLogFuncFrame() << this << bounding_rect.toString(); PrintResult res = PR_PrintedOk; if(m_indexToPrint == 0) { printedText = paraText(); } //qfInfo() << printedText; QString text = printedText.mid(m_indexToPrint); int initial_index_to_print = m_indexToPrint; QString sql_id = sqlId(); /// tiskne se prazdny text bool omit_empty_text = isOmitEmptyText(); if(text.isEmpty() && omit_empty_text) { } else { QString text_to_layout = text; //qfWarning() << "length: " << text.length() << " text: [" << text << "]\n" << text.toUtf8().toHex(); bool text_item_should_be_created = true; style::CompiledTextStyle style; style::Text *p_text_style = effectiveTextStyle(); if(p_text_style) { style = p_text_style->textStyle(); } QFontMetricsF font_metrics = processor()->fontMetrics(style.font()); QTextOption text_option; { if(isTextWrap()) text_option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); //alignment_flags |= Qt::TextWordWrap; int al = textHAlign() | textVAlign(); Qt::Alignment alignment_flags = (Qt::Alignment)al; text_option.setAlignment(alignment_flags); } Rect rendered_bounding_rect; /// velikost boundingRect je v mm, tak to prepocitej na body vystupniho zarizeni rendered_bounding_rect = qmlwidgets::graphics::mm2device(bounding_rect, processor()->paintDevice()); bool render_check_mark = false; QRegExp rx = ReportItemMetaPaint::checkReportSubstitutionRegExp; if(rx.exactMatch(text_to_layout)) { //bool check_on = rx.capturedTexts().value(1) == "1"; rendered_bounding_rect = font_metrics.boundingRect('X'); render_check_mark = true; m_indexToPrint += text_to_layout.length(); } else { if(text_to_layout.isEmpty()) { /// neni omitEmptyString, takze i prazdnej text vyrendruj alespon jako mezeru aby se na to dalo treba kliknout text_to_layout = ' '; } //text.replace(ReportItemMetaPaint::checkOnReportSubstitution, "X"); //text.replace(ReportItemMetaPaint::checkOffReportSubstitution, "X"); //qfInfo().noSpace().color(QFLog::Green) << "index to print: " << indexToPrint << " text: '" << text << "'"; //qfInfo() << "bounding rect:" << bounding_rect.toString(); //qfWarning() << "device physical DPI:" << processor()->paintDevice()->physicalDpiX() << processor()->paintDevice()->physicalDpiY(); //qfWarning().noSpace() << "'" << text << "' font metrics: " << br.toString(); //QString text = element.text().simplified().replace("\\n", "\n"); //qfInfo() << "br:" << br.toString(); //Rect br_debug = br; //bool splitted = false; /// do layout { qreal leading = font_metrics.leading(); qreal height = 0; qreal width = 0; textLayout.setFont(style.font()); textLayout.setTextOption(text_option); textLayout.setText(text_to_layout); textLayout.beginLayout(); bool finished = false; while (!finished) { QTextLine line = textLayout.createLine(); finished = !line.isValid(); if(!finished) { line.setLineWidth(rendered_bounding_rect.width()); /// setWidth() nastavi spravne line.height(), proto musi byt pred merenim popsane vysky. if((line.textLength() == 0) && (line.textStart() + line.textLength() == text_to_layout.length())) { /// nevim kde je chyba, pri vicerakovych textech mi to pridava jeden prazdnej radek na konec, takhle se tomu snazim zabranit (Qt 4.6.3) finished = true; } else { qreal interline_space = (height > 0)? leading: 0; if(height + interline_space + line.height() > rendered_bounding_rect.height()) { res = PR_PrintAgainOnNextPage; if(height == 0) { /// nevejde se ani jeden radek text_item_should_be_created = false; break; } else { /// neco se preci jenom veslo int pos = line.textStart(); m_indexToPrint += pos; break; } } height += interline_space; line.setPosition(QPointF(0., height)); height += line.height(); width = qMax(width, line.naturalTextWidth()); } } if(finished) { m_indexToPrint = printedText.length(); } } textLayout.endLayout(); rendered_bounding_rect.setWidth(width); rendered_bounding_rect.setHeight(height); } } /// velikost boundingRect je v bodech vystupniho zarizeni, tak to prepocitej na mm rendered_bounding_rect = qmlwidgets::graphics::device2mm(rendered_bounding_rect, processor()->paintDevice()); /// rendered rect is left aligned, if text is reight aligned or centered, the ReportItemMetaPaintText::paint() does it if(text_item_should_be_created ) { ReportItemMetaPaintText *mt; if(render_check_mark ) mt = new ReportItemMetaPaintCheck(out, this); else { mt = new ReportItemMetaPaintText(out, this); mt->sqlId = sql_id; //--mt->editGrants = elementAttribute("editGrants"); } //qfInfo() << "creating item:" << mt; mt->pen = style.pen(); mt->font = style.font(); mt->text = text.mid(0, m_indexToPrint - initial_index_to_print); //qfWarning() << "text:" << text; mt->textOption = text_option; mt->renderedRect = rendered_bounding_rect; mt->renderedRect.flags = designedRect.flags; } //qfDebug().color(QFLog::Green, QFLog::Red) << "\tleading:" << processor()->fontMetrics(style.font).leading() << "\theight:" << processor()->fontMetrics(style.font).height(); qfDebug() << "\tchild rendered rect:" << rendered_bounding_rect.toString(); } qfDebug() << "\t<<< CHILDREN paraText return:" << res.toString(); return res; }
/* class N { static int& nref() { static int n = 0; return n; } public: N() {nref()++;} ~N() {nref()--;} operator int() const {return nref();} }; */ ReportItem::PrintResult ReportItemFrame::printMetaPaintChildren(ReportItemMetaPaint *out, const ReportItem::Rect &bounding_rect) { qfLogFuncFrame();// << element.tagName() << "id:" << element.attribute("id") << "itemCount:" << itemsToPrintCount() << "indexToPrint:" << indexToPrint; qfDebug() << "\tbounding_rect:" << bounding_rect.toString(); //N n; //QF_TIME_SCOPE(QString::number((int)n) + ": ReportItemFrame::printMetaPaintChildren"); PrintResult res = PR_PrintedOk; Rect paint_area_rect = bounding_rect; if(layout() == LayoutStacked) { /// allways print all the children) in the stacked layout /// it is used mainly for page header & footers, they shoud be on each page //Rect rendered_rect; for(m_indexToPrint=0; m_indexToPrint<itemsToPrintCount(); m_indexToPrint++) { ReportItem *it = itemToPrintAt(m_indexToPrint); Rect children_paint_area_rect = paint_area_rect; ChildSize sz = it->childSize(LayoutVertical); children_paint_area_rect.setHeight(sz.fromParentSize(paint_area_rect.height())); PrintResult ch_res = it->printMetaPaint(out, children_paint_area_rect); if(ch_res == PR_PrintAgainOnNextPage) { if(res == PR_PrintedOk) { /// only one child can be printed again /// others are ignored in ch_res flags res = ch_res; } } else { // print item again on new page it->resetIndexToPrintRecursively(true); } //qfInfo() << indexToPrint << "ch res:" << ch_res.toString() << "res:" << res.toString(); } } else if(layout() == LayoutHorizontal) { /// Break is ignored in horizontal layout QList<ChildSize> layout_sizes; m_indexToPrint = 0; /// allways print from 0 index (all the children) in horizontal layout /// horizontalni layout musi mit procenta rozpocitany dopredu, protoze jinak by se mi nezalamovaly texty v tabulkach { /// get layout sizes in the layout direction for(int i=m_indexToPrint; i<itemsToPrintCount(); i++) { ReportItem *it = itemToPrintAt(i); layout_sizes << it->childSize(layout()); } } /// get layout sizes in the orthogonal layout direction /// je to bud absolutni hodnota nebo % z bbr QList<ChildSize> orthogonal_sizes; for(int i=m_indexToPrint; i<itemsToPrintCount(); i++) { ReportItem *it = itemToPrintAt(i); Layout ol = orthogonalLayout(); ChildSize sz = it->childSize(ol); if(sz.unit == Rect::UnitPercent) { sz.size = paint_area_rect.sizeInLayout(ol); /// udelej z nej rubber, roztahne se dodatecne } orthogonal_sizes << sz; } /// Items should be printed in special order to make proper layout of all the kinds of size specifiers (xx, undefined, "xx%") /// in horizontal layout, print fixed mm size width items first, the rubber (without width specified) ones as second, rest of space divide according to % value /// when printed, rearange printed items to their original layout order QMap<int, int> layout_ix_to_print_ix; /// layout_ix->print_ix qreal sum_mm = 0; bool has_percent = false; /// print rubber and fixed for(int i=0; i<itemsToPrintCount(); i++) { ReportItem *it = itemToPrintAt(i); ChildSize sz = layout_sizes.value(i); //qfInfo() << "child:" << i << "size:" << sz.size << "unit:" << Rect::unitToString(sz.unit); if(sz.unit == Rect::UnitMM) { Rect ch_bbr = paint_area_rect; ch_bbr.setLeft(paint_area_rect.left() + sum_mm); if(sz.size > 0) ch_bbr.setWidth(sz.size); else ch_bbr.setWidth(paint_area_rect.width() - sum_mm); if(orthogonal_sizes[i].size > 0) { ch_bbr.setSizeInLayout(orthogonal_sizes[i].size, orthogonalLayout()); } //qfInfo() << "\t tisknu fixed:" << it->designedRect.toString(); int prev_children_cnt = out->childrenCount(); PrintResult ch_res = it->printMetaPaint(out, ch_bbr); if(out->children().count() > prev_children_cnt) { //qfInfo() << "rubber fixed:" << i << "->" << prev_children_cnt; layout_ix_to_print_ix[i] = prev_children_cnt; double width = out->lastChild()->renderedRect.width(); sum_mm += width; //qfInfo() << "\t sum_mm:" << sum_mm; if(ch_res == PR_PrintAgainOnNextPage) { /// para can be printed as NotFit if it owerflows its parent frame res = ch_res; } } else { if(ch_res == PR_PrintedOk) { /// jediny, kdo se nemusi vytisknout je band if(it->isVisible()) { qfWarning() << "jak to, ze se dite nevytisklo v horizontalnim layoutu?" << it; } } else { //qfInfo() << "\t NOT OK"; res = ch_res; break; } } } else { has_percent = true; } } qreal rest_mm = paint_area_rect.width() - sum_mm; if(res == PR_PrintedOk) { if(has_percent) { /// divide rest of space to xx% items qreal sum_percent = 0; int cnt_0_percent = 0; for(int i=0; i<itemsToPrintCount(); i++) { ReportItem *it = itemToPrintAt(i); ChildSize sz = it->childSize(layout()); if(sz.unit == Rect::UnitPercent) { if(sz.size == 0) cnt_0_percent++; else sum_percent += sz.size; } } if(rest_mm <= 0) { qfWarning() << "Percent exist but rest_mm is" << rest_mm << ". Ignoring rest of frames"; } else { /// print percent items qreal percent_0 = 0; if(cnt_0_percent > 0) percent_0 = (100 - sum_percent) / cnt_0_percent; for(int i=0; i<itemsToPrintCount(); i++) { ReportItem *it = itemToPrintAt(i); ChildSize sz = it->childSize(layout()); if(sz.unit == Rect::UnitPercent) { qreal d; if(sz.size == 0) d = rest_mm * percent_0 / 100; else d = rest_mm * sz.size / 100; //qfInfo() << d; Rect ch_bbr = paint_area_rect; ch_bbr.setWidth(d); if(orthogonal_sizes[i].size > 0) { ch_bbr.setSizeInLayout(orthogonal_sizes[i].size, orthogonalLayout()); } //qfInfo() << it << "tisknu percent" << it->designedRect.toString(); //qfInfo() << "chbr" << ch_bbr.toString(); int prev_children_cnt = out->childrenCount(); PrintResult ch_res = it->printMetaPaint(out, ch_bbr); if(out->children().count() > prev_children_cnt) { //qfInfo() << "percent:" << i << "->" << prev_children_cnt; layout_ix_to_print_ix[i] = prev_children_cnt; if(ch_res == PR_PrintAgainOnNextPage) { /// para se muze vytisknout a pritom bejt not fit, pokud pretece res = ch_res; } } else { if(ch_res == PR_PrintedOk) { /// jediny, kdo se nemusi vytisknout je band if(it->isVisible()) { qfWarning() << "jak to, ze se dite nevytisklo v horizontalnim layoutu?" << it; } } else { res = ch_res; break; } } } } } /// arrange prited children to their original order //qfInfo() << "\t poradi tisku cnt:<<" << poradi_tisku.count() << out->childrenCount(); if(layout_ix_to_print_ix.count() == out->children().count()) { int children_count = out->children().count(); //qfInfo() << "children cnt:" << children_count; //QF_ASSERT(poradi_tisku.count() == out->children().count(), "nevytiskly se vsechny deti v horizontalnim layoutu"); QVector<qf::core::utils::TreeItemBase*> old_children(layout_ix_to_print_ix.count()); /// get printed children pointers for(int i=0; i<children_count; i++) old_children[i] = out->children()[i]; /// arrange them to the original order /// v mape nemusi byt rada klicu souvisla (kdyz se nejake dite nevytiskne) QMapIterator<int, int> iter(layout_ix_to_print_ix); int new_print_ix = 0; while(iter.hasNext()) { iter.next(); int old_print_ix = iter.value(); if(0 <= new_print_ix && new_print_ix < children_count) { //qfInfo() << old_print_ix << "->" << new_print_ix; if(new_print_ix != old_print_ix) out->childrenRef()[new_print_ix] = old_children[old_print_ix]; new_print_ix++; } else qfWarning() << QF_FUNC_NAME << "order:" << old_print_ix << "new_ix:" << new_print_ix << "out of range:" << children_count; } /// set children proper offsets qreal offset_x = 0; for(int i=0; i<layout_ix_to_print_ix.count(); i++) { //qfInfo() << "\t poradi tisku <<" << i << "offset:" << offset_x; ReportItemMetaPaint *it = out->child(i); /// shift them including their own children recursively :( double shift_x = paint_area_rect.left() + offset_x - it->renderedRect.left(); //if(parent_grid) qfInfo() << i << "offset_x:" << offset_x << "bbr left:" << bbr.left() << "chbbr left:" << ch_bbr.left(); if(qFloatDistance(shift_x, 0) > 200) it->shift(Point(shift_x, 0)); offset_x += it->renderedRect.width(); } } else { qfWarning() << this << "nesedi poradi pocty tisku" << layout_ix_to_print_ix.count() << out->children().count(); } } } if(res == PR_PrintAgainOnNextPage) { /// detail by mel mit, pokud se ma zalamovat, vzdy vertikalni layout, jinak tato funkce zpusobi, ze se po zalomeni vsechny dcerine bandy budou tisknout cele znova /// zakomentoval jsem to a zda se, ze to zatim nicemu nevadi //resetIndexToPrintRecursively(!ReportItem::IncludingParaTexts); } } else { /// vertical layout /// print % like a rubber dimension and if print result is PrintOk resize rendered rect of printed metapaint item /// break funguje tak, ze pri 1., 3., 5. atd. tisku vraci PrintNotFit a pri sudych PrintOk /// prvni break na strance znamena, ze jsem tu uz po zalomeni, takze se tiskne to za break. int index_to_print_0 = m_indexToPrint; for(; m_indexToPrint<itemsToPrintCount(); m_indexToPrint++) { ReportItem *child_item_to_print = itemToPrintAt(m_indexToPrint); Rect children_paint_area_rect = paint_area_rect; qfDebug() << "\tch_bbr v1:" << children_paint_area_rect.toString(); { /// find child paint area size in layout direction qreal d = children_paint_area_rect.sizeInLayout(layout()); ChildSize sz = child_item_to_print->childSize(layout()); //qfInfo() << it << "chbrd:" << ch_bbr.toString() << "d:" << d;// << "size in ly:" << sz.fillLayoutRatio(); if(sz.fillLayoutRatio() >= 0) { } else if(sz.unit == Rect::UnitMM) { if(sz.size > 0) d = sz.size; } else { ReportItemFrame *frit = qobject_cast<ReportItemFrame*>(child_item_to_print); if(frit) qfWarning() << "This should never happen" << child_item_to_print; } //qfInfo() << "\t ch_bbr.sizeInLayout(layout():" << ch_bbr.sizeInLayout(layout()) << "d:" << d; d = qMin(children_paint_area_rect.sizeInLayout(layout()), d); children_paint_area_rect.setSizeInLayout(d, layout()); //qfInfo() << "\t ch_bbr:" << ch_bbr.toString(); } { /// orthogonal size Layout ol = orthogonalLayout(); ChildSize o_sz = child_item_to_print->childSize(ol); if(o_sz.unit == Rect::UnitPercent) { if(o_sz.size == 0) o_sz.size = paint_area_rect.sizeInLayout(ol); else o_sz.size = o_sz.size / 100 * paint_area_rect.sizeInLayout(ol); } //it->metaPaintOrthogonalLayoutLength = sz.size; qfDebug() << "\tsetting orthogonal length:" << o_sz.size; //if(it->isBreak() && i > indexToPrint && layout == LayoutVertical) break; /// v horizontalnim layoutu break ignoruj if(o_sz.size > 0) { children_paint_area_rect.setSizeInLayout(o_sz.size, orthogonalLayout()); } } qfDebug() << "\tch_bbr v2:" << children_paint_area_rect.toString(); int prev_children_cnt = out->childrenCount(); PrintResult ch_res = child_item_to_print->printMetaPaint(out, children_paint_area_rect); if(ch_res == PR_PrintedOk || ch_res == PR_PrintAgainDetail) { /// muze se stat, ze se dite nevytiskne, napriklad band nema zadna data if(out->children().count() > prev_children_cnt) { ReportItemMetaPaint *mpi = out->lastChild(); if(mpi) { const Rect &r = mpi->renderedRect; /// cut rendered area paint_area_rect.cutSizeInLayout(r, layout()); if(ch_res == PR_PrintAgainDetail) { m_indexToPrint--; /// vytiskni ho znovu } } } } else { /// pokud je vertikalni layout, a dite se nevejde vrat PrintNotFit res = ch_res; break; } if(child_item_to_print->isBreak() && m_indexToPrint > index_to_print_0) break; } } //res = checkPrintResult(res); qfDebug() << "\t<<< CHILDREN return:" << res.toString(); return res; }