示例#1
0
/*
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;
}