Line data Source code
1 : #include "convertertopdf.hpp"
2 :
3 : #include <QPdfWriter>
4 : #include <QPainter>
5 : #include "utils/replacer.hpp"
6 : #include "convertertoqwidget.hpp"
7 :
8 : namespace qtreports {
9 : namespace detail {
10 :
11 9 : ConverterToPDF::ConverterToPDF(const ReportPtr & report) :
12 : m_report(report),
13 : m_currentResolution(75),
14 9 : m_currentHeight(0) {}
15 :
16 :
17 9 : ConverterToPDF::~ConverterToPDF() {}
18 :
19 6 : bool ConverterToPDF::convert(const QString & path)
20 : {
21 6 : return create(path);
22 : }
23 :
24 1 : void ConverterToPDF::setDPI(int dpi)
25 : {
26 1 : m_currentResolution = dpi;
27 1 : }
28 :
29 3 : int ConverterToPDF::getDPI() const
30 : {
31 3 : return m_currentResolution;
32 : }
33 :
34 6 : bool ConverterToPDF::create(const QString & path)
35 : {
36 6 : if(m_report.isNull()) {
37 1 : m_lastError = "Report is empty";
38 1 : return false;
39 : }
40 :
41 10 : QPdfWriter writer(path);
42 5 : writer.setCreator("QReports Library");
43 5 : writer.setTitle(m_report->getName());
44 5 : writer.setResolution(m_currentResolution);
45 10 : QPainter painter(&writer);
46 10 : QFont reportFont;
47 10 : QPen reportPen;
48 :
49 : // Настройка стилей. Стили считываются из отчета.
50 5 : auto &styles = m_report->getStyles();
51 5 : auto index = styles.begin();
52 5 : auto *style = (*index).data();
53 5 : reportFont.setFamily(style->getFontName());
54 5 : reportFont.setPointSize(style->getFontSize());
55 5 : style->isItalic() ? reportFont.setItalic(true) : reportFont.setItalic(false);
56 5 : style->isBold() ? reportFont.setBold(true) : reportFont.setBold(false);
57 5 : style->isUnderline() ? reportFont.setUnderline(true) : reportFont.setUnderline(false);
58 5 : style->isStrikeThrough() ? reportFont.setStrikeOut(true) : reportFont.setStrikeOut(false);
59 5 : reportPen.setColor(style->getFontColor());
60 :
61 5 : painter.setFont(reportFont);
62 5 : painter.setPen(reportPen);
63 :
64 10 : auto title = m_report->getTitle();
65 5 : if(!title.isNull())
66 : {
67 2 : if(!createSection(writer, painter, title, 0))
68 : {
69 0 : m_lastError = "Report->Section is not created: title";
70 0 : return false;
71 : }
72 : }
73 :
74 10 : auto detail = m_report->getDetail();
75 5 : if(detail.isNull())
76 : {
77 2 : m_lastError = "Report->Detail is empty";
78 2 : return false;
79 : }
80 :
81 3 : if(!addGroupsIntoReport(writer, painter, m_report, detail))
82 0 : return false;
83 :
84 6 : auto summary = m_report->getSummary();
85 3 : if(!summary.isNull())
86 : {
87 2 : int lastField = m_report->getFieldsDataCount() - 1;
88 2 : if(!createSection(writer, painter, summary, lastField))
89 : {
90 0 : m_lastError = "Report->Section is not created: summary";
91 0 : return false;
92 : }
93 : }
94 :
95 3 : painter.end();
96 3 : return true;
97 :
98 : }
99 :
100 47 : bool ConverterToPDF::createSection(QPdfWriter &writer, QPainter &painter, const SectionPtr §ion, int i)
101 : {
102 94 : detail::Replacer replacer;
103 47 : if(!replacer.replace(section, m_report, i))
104 : {
105 0 : m_lastError = "Error in replacing process: " + replacer.getLastError();
106 0 : return false;
107 : }
108 :
109 47 : if(!createBands(writer, painter, section))
110 : {
111 0 : m_lastError = "Error in creating bands process: " + replacer.getLastError();
112 0 : return false;
113 : }
114 :
115 47 : return true;
116 : }
117 :
118 47 : bool ConverterToPDF::createBands(QPdfWriter &writer, QPainter &painter, const SectionPtr §ion)
119 : {
120 104 : for(auto && band: section->getBands())
121 : {
122 57 : if(m_currentHeight + band->getHeight() > m_report->getHeight())
123 : {
124 18 : writer.newPage();
125 18 : m_currentHeight = 0;
126 : }
127 :
128 124 : for(auto && textField : band->getTextFields()) {
129 67 : if(textField->getText() != "") {
130 67 : Qt::AlignmentFlag alignment = Qt::AlignCenter;
131 67 : if ((textField->getAlignment() & Qt::AlignLeft) == Qt::AlignLeft)
132 54 : alignment = Qt::AlignLeft;
133 67 : if ((textField->getAlignment() & Qt::AlignRight) == Qt::AlignRight)
134 11 : alignment = Qt::AlignRight;
135 67 : if ((textField->getAlignment() & Qt::AlignHCenter) == Qt::AlignHCenter)
136 2 : alignment = Qt::AlignCenter;
137 67 : if ((textField->getAlignment() & Qt::AlignJustify) == Qt::AlignJustify)
138 0 : alignment = Qt::AlignJustify;
139 67 : int x = textField->getX();
140 67 : int y = textField->getY();
141 67 : int w = textField->getWidth();
142 67 : int h = textField->getHeight();
143 67 : painter.drawText(x, y + m_currentHeight, w, h, alignment, textField->getText());
144 : }
145 : }
146 :
147 77 : for(auto && staticText : band->getStaticTexts()) {
148 20 : if(staticText->getText() != "") {
149 20 : Qt::AlignmentFlag alignment = Qt::AlignCenter;
150 20 : if ((staticText->getAlignment() & Qt::AlignLeft) == Qt::AlignLeft)
151 7 : alignment = Qt::AlignLeft;
152 20 : if ((staticText->getAlignment() & Qt::AlignRight) == Qt::AlignRight)
153 12 : alignment = Qt::AlignRight;
154 20 : if ((staticText->getAlignment() & Qt::AlignHCenter) == Qt::AlignHCenter)
155 1 : alignment = Qt::AlignCenter;
156 20 : if ((staticText->getAlignment() & Qt::AlignJustify) == Qt::AlignJustify)
157 0 : alignment = Qt::AlignJustify;
158 :
159 20 : int x = staticText->getX();
160 20 : int y = staticText->getY();
161 20 : int w = staticText->getWidth();
162 20 : int h = staticText->getHeight();
163 20 : painter.drawText(x, y + m_currentHeight, w, h, alignment, staticText->getText());
164 : }
165 : }
166 :
167 69 : for(auto && image : band->getImages()) {
168 24 : QImage img = image->getImage();
169 12 : QRect imageRect;
170 12 : imageRect.setX(image->getX());
171 12 : imageRect.setY(image->getY());
172 12 : imageRect.setWidth(image->getWidth());
173 12 : imageRect.setHeight(image->getHeight());
174 12 : painter.drawImage(imageRect, img);
175 : }
176 :
177 76 : for(auto && line : band->getLines()) {
178 19 : int x1 = line->getX();
179 19 : int y1 = line->getY() + m_currentHeight;
180 19 : int x2 = x1 + line->getWidth() - 1;
181 19 : int y2 = y1 + line->getHeight();
182 19 : QLine qline(x1, y1, x2, y2);
183 19 : painter.drawLine(qline);
184 : }
185 :
186 71 : for(auto && rect : band->getRects()) {
187 14 : QRect rectC;
188 14 : rectC.setX(rect->getRect().x());
189 14 : rectC.setY(rect->getRect().y() + m_currentHeight);
190 14 : rectC.setHeight(rect->getRect().height());
191 14 : rectC.setWidth(rect->getRect().width());
192 14 : painter.drawRect(rectC);
193 : }
194 :
195 69 : for(auto && ellipse : band->getEllipses()) {
196 12 : QRect rectE;
197 12 : rectE.setX(ellipse->getRect().x());
198 12 : rectE.setY(ellipse->getRect().y() + m_currentHeight);
199 12 : rectE.setHeight(ellipse->getRect().height());
200 12 : rectE.setWidth(ellipse->getRect().width());
201 12 : painter.drawEllipse(rectE);
202 : }
203 :
204 58 : for(auto && crosstab : band->getCrosstabs())
205 : {
206 2 : detail::Replacer replacer;
207 :
208 2 : QList<QString> colGroups;
209 1 : replacer.replaceColumnGroupsInCrosstab(crosstab, m_report, colGroups);
210 :
211 2 : QList<QString> rowGroups;
212 1 : replacer.replaceRowGroupsInCrosstab(crosstab, m_report, rowGroups);
213 :
214 2 : QList<QString> cells;
215 1 : replacer.replaceCellsInCrosstab(crosstab, m_report, cells);
216 :
217 1 : QRect crosstabRect = crosstab->getRect();
218 :
219 2 : auto rowGroup = crosstab->getRowGroup();
220 2 : auto colGroup = crosstab->getColumnGroup();
221 2 : auto cell = crosstab->getCrosstabCell();
222 :
223 1 : QRect emptyRect = QRect();
224 1 : emptyRect.setX(crosstabRect.x());
225 1 : emptyRect.setY(crosstabRect.y() + m_currentHeight);
226 1 : emptyRect.setWidth(rowGroup->getWidth());
227 1 : emptyRect.setHeight(cell->getHeight());
228 1 : painter.drawRect(emptyRect);
229 :
230 1 : int colX = crosstabRect.x() + rowGroup->getWidth();
231 5 : for (int i = 0; i < colGroups.size(); i++)
232 : {
233 4 : Qt::AlignmentFlag alignment = Qt::AlignCenter;
234 4 : if ((colGroup->getHeader()->getCellContents()->getAlignment() & Qt::AlignLeft) == Qt::AlignLeft)
235 4 : alignment = Qt::AlignLeft;
236 4 : if ((colGroup->getHeader()->getCellContents()->getAlignment() & Qt::AlignRight) == Qt::AlignRight)
237 0 : alignment = Qt::AlignRight;
238 4 : if ((colGroup->getHeader()->getCellContents()->getAlignment() & Qt::AlignHCenter) == Qt::AlignHCenter)
239 0 : alignment = Qt::AlignCenter;
240 4 : if ((colGroup->getHeader()->getCellContents()->getAlignment() & Qt::AlignJustify) == Qt::AlignJustify)
241 0 : alignment = Qt::AlignJustify;
242 :
243 4 : int x = colX + colGroup->getHeader()->getCellContents()->getTextField()->getX();
244 4 : int y = crosstabRect.y() + colGroup->getHeader()->getCellContents()->getTextField()->getY();
245 4 : int w = colGroup->getHeader()->getCellContents()->getTextField()->getWidth();
246 4 : int h = colGroup->getHeader()->getCellContents()->getTextField()->getHeight();
247 4 : painter.drawText(x, y + m_currentHeight, w, h, alignment, colGroups[i]);
248 :
249 4 : QRect colRect = QRect();
250 4 : colRect.setX(colX);
251 4 : colRect.setY(crosstabRect.y() + m_currentHeight);
252 4 : colRect.setWidth(cell->getWidth());
253 4 : colRect.setHeight(colGroup->getHeight());
254 4 : painter.drawRect(colRect);
255 :
256 4 : colX += cell->getWidth();
257 : }
258 :
259 1 : int rowY = crosstabRect.y();
260 5 : for (int i = 0; i < rowGroups.size(); i++)
261 : {
262 4 : rowY += cell->getHeight();
263 :
264 4 : Qt::AlignmentFlag alignment = Qt::AlignCenter;
265 4 : if ((rowGroup->getHeader()->getCellContents()->getAlignment() & Qt::AlignLeft) == Qt::AlignLeft)
266 4 : alignment = Qt::AlignLeft;
267 4 : if ((rowGroup->getHeader()->getCellContents()->getAlignment() & Qt::AlignRight) == Qt::AlignRight)
268 0 : alignment = Qt::AlignRight;
269 4 : if ((rowGroup->getHeader()->getCellContents()->getAlignment() & Qt::AlignHCenter) == Qt::AlignHCenter)
270 0 : alignment = Qt::AlignCenter;
271 4 : if ((rowGroup->getHeader()->getCellContents()->getAlignment() & Qt::AlignJustify) == Qt::AlignJustify)
272 0 : alignment = Qt::AlignJustify;
273 :
274 4 : int x = crosstabRect.x() + rowGroup->getHeader()->getCellContents()->getTextField()->getX();
275 4 : int y = rowY + rowGroup->getHeader()->getCellContents()->getTextField()->getY();
276 4 : int w = rowGroup->getHeader()->getCellContents()->getTextField()->getWidth();
277 4 : int h = rowGroup->getHeader()->getCellContents()->getTextField()->getHeight();
278 4 : painter.drawText(x, y + m_currentHeight, w, h, alignment, rowGroups[i]);
279 :
280 4 : QRect rowRect = QRect();
281 4 : rowRect.setX(crosstabRect.x());
282 4 : rowRect.setY(rowY + m_currentHeight);
283 4 : rowRect.setWidth(rowGroup->getWidth());
284 4 : rowRect.setHeight(cell->getHeight());
285 4 : painter.drawRect(rowRect);
286 : }
287 :
288 1 : int cellX = crosstabRect.x();
289 1 : int cellY = crosstabRect.y();
290 1 : int cellCount = 0;
291 5 : for (int i = 0; i < rowGroups.size(); i++)
292 : {
293 4 : cellX += emptyRect.width();
294 4 : cellY += emptyRect.height();
295 20 : for(int j = 0; j < colGroups.size(); j++)
296 : {
297 16 : Qt::AlignmentFlag alignment = Qt::AlignCenter;
298 16 : if ((cell->getCellContents()->getAlignment() & Qt::AlignLeft) == Qt::AlignLeft)
299 16 : alignment = Qt::AlignLeft;
300 16 : if ((cell->getCellContents()->getAlignment() & Qt::AlignRight) == Qt::AlignRight)
301 0 : alignment = Qt::AlignRight;
302 16 : if ((cell->getCellContents()->getAlignment() & Qt::AlignHCenter) == Qt::AlignHCenter)
303 0 : alignment = Qt::AlignCenter;
304 16 : if ((cell->getCellContents()->getAlignment() & Qt::AlignJustify) == Qt::AlignJustify)
305 0 : alignment = Qt::AlignJustify;
306 :
307 16 : int x = cellX + cell->getCellContents()->getTextField()->getX();
308 16 : int y = cellY + cell->getCellContents()->getTextField()->getY();
309 16 : int w = cell->getCellContents()->getTextField()->getWidth();
310 16 : int h = cell->getCellContents()->getTextField()->getHeight();
311 16 : painter.drawText(x, y + m_currentHeight, w, h, alignment, cells[cellCount]);
312 :
313 16 : QRect cellRect = QRect();
314 16 : cellRect.setX(cellX);
315 16 : cellRect.setY(cellY + m_currentHeight);
316 16 : cellRect.setWidth(cell->getWidth());
317 16 : cellRect.setHeight(cell->getHeight());
318 16 : painter.drawRect(cellRect);
319 :
320 16 : cellCount++;
321 16 : cellX += cell->getWidth();
322 : }
323 4 : cellX = crosstabRect.x();
324 : }
325 : }
326 :
327 57 : m_currentHeight += band->getHeight();
328 : }
329 :
330 47 : return true;
331 : }
332 :
333 5 : const QString ConverterToPDF::getLastError() const
334 : {
335 5 : return m_lastError;
336 : }
337 :
338 3 : bool ConverterToPDF::addGroupsIntoReport(QPdfWriter &writer, QPainter &painter, const ReportPtr &report, const DetailPtr &detail)
339 : {
340 6 : detail::Replacer replacer;
341 6 : QList<GroupPtr> groups = report->getGroups().values();
342 6 : QList<QString> groupNames;
343 : // Сюда помещаем конкретные имена по которым группируем
344 6 : QList<QString> particularNames;
345 4 : for(int i = 0; i < groups.length(); i++)
346 : {
347 2 : auto groupExpression = groups[i]->getExpression();
348 1 : if(groupExpression == "")
349 : {
350 0 : return false;
351 : }
352 1 : groupNames.append(groupExpression);
353 1 : particularNames.append(replacer.replaceField(groupNames[i], report, 0));
354 : }
355 :
356 : // Открываем хедеры групп
357 4 : for(int i = 0; i < groups.length(); i++)
358 : {
359 2 : auto header = groups[i]->getHeader();
360 1 : if(!header.isNull())
361 : {
362 1 : if(!createSection(writer, painter, header, 0))
363 : {
364 0 : return false;
365 : }
366 : }
367 : }
368 :
369 3 : int rowCount = report->getRowCount();
370 30 : for(int i = 0; i < rowCount; i++)
371 : {
372 : // Закрываем футеры, если группа закончилась
373 38 : for(int j = groups.length() - 1; j >= 0; j--)
374 : {
375 : // Сверяем поле в заголовке и текущее поле
376 11 : if(particularNames[j] != replacer.replaceField(groupNames[j], report, i))
377 : {
378 14 : auto footer = report->getGroupByIndex(j)->getFooter();
379 7 : if(!footer.isNull())
380 : {
381 7 : if(!createSection(writer, painter, footer, i - 1))
382 : {
383 0 : return false;
384 : }
385 : }
386 : }
387 : }
388 : // Аналогично открываем хедеры
389 38 : for(int j = 0; j < groupNames.length(); j++)
390 : {
391 : // Сверяем поле в заголовке и текущее поле
392 11 : if(particularNames[j] != replacer.replaceField(groupNames[j], report, i))
393 : {
394 14 : auto header = report->getGroupByIndex(j)->getHeader();
395 7 : if(!header.isNull())
396 : {
397 7 : if(!createSection(writer, painter, header, i))
398 : {
399 0 : return false;
400 : }
401 : }
402 : }
403 : }
404 : // Переписываем имена для сравнения
405 38 : for(int j = 0; j < groupNames.length(); j++)
406 : {
407 11 : particularNames[j] = replacer.replaceField(groupNames[j], report, i);
408 : }
409 : // Выводим поле
410 27 : if(!createSection(writer, painter, detail, i))
411 : {
412 0 : return false;
413 : }
414 : }
415 : // Закрываем хедеры групп
416 4 : for(int i = groups.length() - 1; i >= 0; i--)
417 : {
418 2 : auto footer = groups[i]->getFooter();
419 1 : if(!footer.isNull())
420 : {
421 1 : if(!createSection(writer, painter, footer, (rowCount - 1)))
422 : {
423 0 : return false;
424 : }
425 : }
426 : }
427 3 : return true;
428 : }
429 :
430 : }
431 : }
|