KD Reports API Documentation  2.2
KDReportsPreviewWidget.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** This file is part of the KD Reports library.
4 **
5 ** SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6 **
7 ** SPDX-License-Identifier: MIT
8 **
9 ****************************************************************************/
10 
11 #include "KDReportsPreviewWidget.h"
12 #include "KDReportsReport.h"
13 #include <QDebug>
14 #include <QKeyEvent>
15 #include <QPainter>
16 #include <QPointer>
17 #include <QPrintDialog>
18 #include <QProgressDialog>
19 #include <QShortcut>
20 #include <QTime>
21 #include <QTimer>
22 #include <qmath.h> // qCeil
23 
24 #include "ui_previewdialogbase.h"
25 
26 enum
27 {
28  PreviewSize = 200
29 };
30 
33 class PagePreviewWidget : public QWidget
34 {
35  Q_OBJECT
36 public:
37  PagePreviewWidget(QWidget *parent = nullptr)
38  : QWidget(parent)
39  {
40  // For link hovered functionality
41  setMouseTracking(true);
42  }
43  void setPixmap(const QPixmap &pixmap)
44  {
45  m_pixmap = pixmap;
46  update();
47  }
48  int pixmapWidth() const
49  {
50  return m_pixmap.width();
51  }
52  int pixmapHeight() const
53  {
54  return m_pixmap.height();
55  }
56  QSize pixmapSize() const
57  {
58  return m_pixmap.size();
59  }
60 
61 Q_SIGNALS:
62  void mouseMoved(QPoint pos);
63  void mouseClicked(QPoint pos);
64 
65 protected:
66  QPoint pixmapOffset() const
67  {
68  return QPoint((width() - m_pixmap.width()) / 2, (height() - m_pixmap.height()) / 2);
69  }
70 
71  void paintEvent(QPaintEvent *) override
72  {
73  QPainter painter(this);
74  // painter.fillRect( event->rect(), QColor(224,224,224) );
75  painter.drawPixmap(pixmapOffset(), m_pixmap);
76  }
78  void mouseMoveEvent(QMouseEvent *ev) override
79  {
80  Q_EMIT mouseMoved(ev->pos() - pixmapOffset());
81  }
83  void mouseReleaseEvent(QMouseEvent *ev) override
84  {
85  Q_EMIT mouseClicked(ev->pos() - pixmapOffset());
86  }
87 
88 private:
89  QPixmap m_pixmap;
90 };
91 
92 class KDReports::PreviewWidgetPrivate : public Ui::PreviewWidgetBase
93 {
94 public:
95  PreviewWidgetPrivate(KDReports::PreviewWidget *w);
96 
97  // not in ctor because the init calls q->slotFoo which uses d->, so d must be set first.
98  void init();
99 
100  void paintItem(QListWidgetItem *item, int index) const;
101  QPixmap paintPreview(int index) const;
102  void printSelectedPages();
103  void setupComboBoxes();
104  void pageCountChanged();
105  void centerPreview();
106  void zoomChanged();
107  void fillZoomCombo();
108  void updatePageButtons();
109  void updatePreview();
110  void pageNumberReturnPressed();
111  void setReport(KDReports::Report *report);
112 
113  void handleMouseMove(QPoint pos);
114  void handleMouseRelease(QPoint pos);
115  void slotCurrentPageChanged();
116  void slotFirstPage();
117  void slotPrevPage();
118  void slotNextPage();
119  void slotLastPage();
120  void slotPaperSizeActivated(int);
121  void slotPaperOrientationActivated(int);
122  void slotZoomIn();
123  void slotZoomOut();
124  void slotZoomChanged();
125  void previewNextItems();
126 
127  PagePreviewWidget *m_previewWidget;
128  QPrinter m_printer;
129  qreal m_zoomFactor = 1.0;
130  qreal m_endlessPrinterWidth = 114.0;
131  KDReports::Report *m_report = nullptr;
132  QTimer m_previewTimer;
134  int m_pageCount = 0;
135  int m_firstDirtyPreviewItem = -1;
136  bool m_eatPageNumberClick = false;
137  bool m_onAnchor = false;
138 };
139 
140 KDReports::PreviewWidgetPrivate::PreviewWidgetPrivate(KDReports::PreviewWidget *w)
141  : m_previewWidget(new PagePreviewWidget)
142  , q(w)
143 {
144  QObject::connect(&m_previewTimer, &QTimer::timeout, q, [this]() { previewNextItems(); });
145  QObject::connect(m_previewWidget, &PagePreviewWidget::mouseMoved, q, [this](QPoint pos) {
146  handleMouseMove(pos);
147  });
148  QObject::connect(m_previewWidget, &PagePreviewWidget::mouseClicked, q, [this](QPoint pos) {
149  handleMouseRelease(pos);
150  });
151 }
152 
153 void KDReports::PreviewWidgetPrivate::init()
154 {
155  setupUi(q);
156  actionBar->setEnabled(false);
157 
158  m_printer.setFullPage(true);
159 
160  pageList->setIconSize(QSize(PreviewSize, PreviewSize));
161  pageList->setViewMode(QListView::IconMode);
162  pageList->setMovement(QListView::Static);
163  previewArea->setWidget(m_previewWidget);
164  setupComboBoxes();
165  previewArea->setFocus();
166  fillZoomCombo();
167 
168  // m_tableBreakingButton = buttonBox->addButton( tr("Table Breaking / Font Scaling..." ), QDialogButtonBox::ActionRole );
169  QObject::connect(tableBreakingButton, &QAbstractButton::clicked, q, &PreviewWidget::tableSettingsClicked);
170 
171  QObject::connect(firstPage, &QAbstractButton::clicked, q, [this]() { slotFirstPage(); });
172  QObject::connect(prevPage, &QAbstractButton::clicked, q, [this]() { slotPrevPage(); });
173  QObject::connect(nextPage, &QAbstractButton::clicked, q, [this]() { slotNextPage(); });
174  QObject::connect(lastPage, &QAbstractButton::clicked, q, [this]() { slotLastPage(); });
175  QObject::connect(zoomIn, &QAbstractButton::clicked, q, [this]() { slotZoomIn(); });
176  QObject::connect(zoomOut, &QAbstractButton::clicked, q, [this]() { slotZoomOut(); });
177  QObject::connect(zoomCombo, QOverload<int>::of(&QComboBox::activated), q, [this]() { slotZoomChanged(); });
178  QObject::connect(pageList, &QListWidget::currentRowChanged, q, [this]() { slotCurrentPageChanged(); });
179  QObject::connect(paperSizeCombo, QOverload<int>::of(&QComboBox::activated), q, [this](int idx) { slotPaperSizeActivated(idx); });
180  QObject::connect(paperOrientationCombo, QOverload<int>::of(&QComboBox::activated), q, [this](int idx) { slotPaperOrientationActivated(idx); });
181 
182  auto *nextPageShortcut = new QShortcut(q);
183  nextPageShortcut->setKey(Qt::CTRL | Qt::Key_PageDown);
184  QObject::connect(nextPageShortcut, &QShortcut::activated, q, [this]() { slotNextPage(); });
185  auto *prevPageShortcut = new QShortcut(q);
186  prevPageShortcut->setKey(Qt::CTRL | Qt::Key_PageUp);
187  QObject::connect(prevPageShortcut, &QShortcut::activated, q, [this]() { slotPrevPage(); });
188  pageNumber->setValidator(new QIntValidator(1, 100000, pageNumber));
189  pageNumber->installEventFilter(q);
190 }
191 
192 void KDReports::PreviewWidgetPrivate::paintItem(QListWidgetItem *item, int index) const
193 {
194  // qDebug() << "paintItem" << index;
195 
196  // Use a QImage so that the raster paint engine is used.
197  // Gives a 7.7 times speedup (!) compared to X11.
198  const qreal dpr = q->devicePixelRatioF();
199  QImage img(PreviewSize * dpr, PreviewSize * dpr, QImage::Format_ARGB32_Premultiplied);
200  img.setDevicePixelRatio(dpr);
201  img.fill(Qt::transparent);
202  const QSizeF paperSize = m_report->paperSize();
203  const qreal paperWidth = paperSize.width();
204  const qreal paperHeight = paperSize.height();
205  const qreal longestSide = qMax(paperWidth, paperHeight);
206  const qreal width = PreviewSize * paperWidth / longestSide;
207  const qreal height = PreviewSize * paperHeight / longestSide;
208  QPainter painter(&img);
209  painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform, true);
210  painter.translate((PreviewSize - width) / 2, (PreviewSize - height) / 2);
211  painter.fillRect(QRectF(0, 0, width, height), QBrush(Qt::white));
212  painter.scale(PreviewSize / longestSide, PreviewSize / longestSide);
213  m_report->paintPage(index, painter);
214  painter.setPen(QPen(1));
215  painter.drawRect(QRectF(0, 0, paperWidth, paperHeight));
216 
217  item->setIcon(QIcon(QPixmap::fromImage(img)));
218 }
219 
220 void KDReports::PreviewWidgetPrivate::previewNextItems()
221 {
222  if (m_firstDirtyPreviewItem == -1 || m_firstDirtyPreviewItem >= m_pageCount) {
223  m_previewTimer.stop();
224  m_firstDirtyPreviewItem = -1;
225  } else {
226  // Do next preview
227  paintItem(pageList->item(m_firstDirtyPreviewItem), m_firstDirtyPreviewItem);
228  ++m_firstDirtyPreviewItem;
229  }
230 }
231 
232 QPixmap KDReports::PreviewWidgetPrivate::paintPreview(int index) const
233 {
234  const QSizeF paperSize = m_report->paperSize();
235  const int width = qCeil(paperSize.width() * m_zoomFactor);
236  const int height = qCeil(paperSize.height() * m_zoomFactor);
237  const qreal dpr = q->devicePixelRatioF();
238 
239  QPixmap pixmap(width * dpr, height * dpr);
240  pixmap.setDevicePixelRatio(dpr);
241  pixmap.fill(Qt::transparent);
242  // qDebug() << width << "," << height;
243 
244  // qDebug() << "paintPreview " << index;
245 
246  QPainter painter(&pixmap);
247  painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform, true);
248 
249  painter.fillRect(QRectF(0, 0, width, height), QBrush(Qt::white));
250  painter.scale(m_zoomFactor, m_zoomFactor);
251  m_report->paintPage(index, painter);
252  painter.setPen(QPen(1));
253  painter.drawRect(QRectF(0, 0, paperSize.width(), paperSize.height()));
254 
255  return pixmap;
256 }
257 
258 void KDReports::PreviewWidgetPrivate::handleMouseMove(QPoint pos)
259 {
260  const QPoint unscaledPos = pos / m_zoomFactor;
261  const QString link = m_report->anchorAt(pageList->currentRow(), unscaledPos);
262  if (link.isEmpty()) { // restore cursor
263  q->unsetCursor();
264  m_onAnchor = false;
265  } else if (!m_onAnchor) {
266  q->setCursor(Qt::PointingHandCursor);
267  m_onAnchor = true;
268  }
269 }
270 
271 void KDReports::PreviewWidgetPrivate::handleMouseRelease(QPoint pos)
272 {
273  const QPoint unscaledPos = pos / m_zoomFactor;
274  const QString link = m_report->anchorAt(pageList->currentRow(), unscaledPos);
275  if (!link.isEmpty()) {
276  Q_EMIT q->linkActivated(link);
277  }
278 }
279 
280 void KDReports::PreviewWidgetPrivate::printSelectedPages()
281 {
282  // Well, the user can modify the page size in the printer dialog too - ensure layout matches
283  // qDebug() << "pageSize: " << m_printer.pageSize();
284  m_report->setPageSize(m_printer.pageLayout().pageSize());
285  m_report->setPageOrientation(m_printer.pageLayout().orientation());
286  pageCountChanged();
287 
288  // ### But how do we match "marked pages" from a previous layout into the new layout?
289  // ### Hardly makes sense...
290 
291  int markedPages = 0;
292  for (int pageIndex = 0; pageIndex < pageList->count(); ++pageIndex) {
293  if (pageList->item(pageIndex)->checkState() == Qt::Checked)
294  ++markedPages;
295  }
296 
297  QProgressDialog dialog(QObject::tr("Printing"), QObject::tr("Cancel"), 0, markedPages, q);
298  dialog.setWindowModality(Qt::ApplicationModal);
299 
300  QPainter painter;
301  painter.begin(&m_printer);
302 
303  int printed = 0;
304  bool firstPage = true;
305  for (int pageIndex = 0; pageIndex < m_pageCount; ++pageIndex) {
306 
307  // OK because the dialog is modal
308  qApp->processEvents();
309 
310  if (dialog.wasCanceled())
311  break;
312 
313  if (q->isSelected(pageIndex)) {
314  // Print all pages that are marked
315  if (!firstPage)
316  m_printer.newPage();
317 
318  m_report->paintPage(pageIndex, painter);
319  dialog.setValue(++printed);
320  firstPage = false;
321  }
322  }
323  painter.end();
324 }
325 
326 void KDReports::PreviewWidgetPrivate::setupComboBoxes()
327 {
328  paperSizeCombo->addItem(PreviewWidget::tr("A0 (841 x 1189 mm)"), QPageSize::A0);
329  paperSizeCombo->addItem(PreviewWidget::tr("A1 (594 x 841 mm)"), QPageSize::A1);
330  paperSizeCombo->addItem(PreviewWidget::tr("A2 (420 x 594 mm)"), QPageSize::A2);
331  paperSizeCombo->addItem(PreviewWidget::tr("A3 (297 x 420 mm)"), QPageSize::A3);
332  paperSizeCombo->addItem(PreviewWidget::tr("A4 (210 x 297 mm)"), QPageSize::A4);
333  paperSizeCombo->addItem(PreviewWidget::tr("A5 (148 x 210 mm)"), QPageSize::A5);
334  paperSizeCombo->addItem(PreviewWidget::tr("A6 (105 x 148 mm)"), QPageSize::A6);
335  paperSizeCombo->addItem(PreviewWidget::tr("A7 (74 x 105 mm)"), QPageSize::A7);
336  paperSizeCombo->addItem(PreviewWidget::tr("A8 (52 x 74 mm)"), QPageSize::A8);
337  // paperSizeCombo->addItem(PreviewWidget::tr("A9 (37 x 52 mm)"), QPageSize::A9);
338  paperSizeCombo->addItem(PreviewWidget::tr("B0 (1000 x 1414 mm)"), QPageSize::B0);
339  paperSizeCombo->addItem(PreviewWidget::tr("B1 (707 x 1000 mm)"), QPageSize::B1);
340  paperSizeCombo->addItem(PreviewWidget::tr("B2 (500 x 707 mm)"), QPageSize::B2);
341  paperSizeCombo->addItem(PreviewWidget::tr("B3 (353 x 500 mm)"), QPageSize::B3);
342  paperSizeCombo->addItem(PreviewWidget::tr("B4 (250 x 353 mm)"), QPageSize::B4);
343  paperSizeCombo->addItem(PreviewWidget::tr("B5 (176 x 250 mm)"), QPageSize::B5);
344  paperSizeCombo->addItem(PreviewWidget::tr("B6 (125 x 176 mm)"), QPageSize::B6);
345  paperSizeCombo->addItem(PreviewWidget::tr("B7 (88 x 125 mm)"), QPageSize::B7);
346  paperSizeCombo->addItem(PreviewWidget::tr("B8 (62 x 88 mm)"), QPageSize::B8);
347  // paperSizeCombo->addItem(PreviewWidget::tr("B9 (44 x 62 mm)"), QPageSize::B9);
348  // paperSizeCombo->addItem(PreviewWidget::tr("B10 (31 x 44 mm)"), QPageSize::B10);
349  paperSizeCombo->addItem(PreviewWidget::tr("C5E (163 x 229 mm)"), QPageSize::C5E);
350  paperSizeCombo->addItem(PreviewWidget::tr("DLE (110 x 220 mm)"), QPageSize::DLE);
351  paperSizeCombo->addItem(PreviewWidget::tr("Executive (7.5 x 10 inches)"), QPageSize::Executive);
352  paperSizeCombo->addItem(PreviewWidget::tr("Folio (210 x 330 mm)"), QPageSize::Folio);
353  paperSizeCombo->addItem(PreviewWidget::tr("Ledger (432 x 279 mm)"), QPageSize::Ledger);
354  paperSizeCombo->addItem(PreviewWidget::tr("Legal (8.5 x 14 inches)"), QPageSize::Legal);
355  paperSizeCombo->addItem(PreviewWidget::tr("Letter (8.5 x 11 inches)"), QPageSize::Letter);
356  paperSizeCombo->addItem(PreviewWidget::tr("Tabloid (279 x 432 mm)"), QPageSize::Tabloid);
357  paperSizeCombo->addItem(PreviewWidget::tr("US #10 Envelope (105 x 241 mm)"), QPageSize::Comm10E);
358  paperSizeCombo->addItem(PreviewWidget::tr("Endless printer (%1 mm wide)").arg(m_endlessPrinterWidth), QPageSize::Custom);
359 
360  paperOrientationCombo->addItem(PreviewWidget::tr("Portrait"), QPageLayout::Portrait);
361  paperOrientationCombo->addItem(PreviewWidget::tr("Landscape"), QPageLayout::Landscape);
362 }
363 
364 void KDReports::PreviewWidgetPrivate::slotCurrentPageChanged()
365 {
366  updatePreview();
367  updatePageButtons();
368 }
369 
370 void KDReports::PreviewWidgetPrivate::updatePageButtons()
371 {
372  prevPage->setEnabled(pageList->currentRow() > 0);
373  nextPage->setEnabled(pageList->currentRow() < pageList->count() - 1);
374  pageNumber->setText(QString::number(pageList->currentRow() + 1));
375 }
376 
377 void KDReports::PreviewWidgetPrivate::updatePreview()
378 {
379  if (!pageList->currentItem())
380  return;
381  const QSize oldSize = m_previewWidget->pixmapSize();
382  const QPixmap pixmap = paintPreview(pageList->currentRow());
383  m_previewWidget->setPixmap(pixmap);
384  if (pixmap.size() != oldSize) {
385  centerPreview();
386  }
387 }
388 
389 void KDReports::PreviewWidgetPrivate::pageNumberReturnPressed()
390 {
391  bool ok;
392  const int newPageNumber = pageNumber->text().toInt(&ok) - 1;
393  if (!ok || newPageNumber < 0 || newPageNumber > pageList->count() - 1)
394  return;
395  pageList->setCurrentRow(newPageNumber);
396 }
397 
398 void KDReports::PreviewWidgetPrivate::slotFirstPage()
399 {
400  pageList->setCurrentRow(0);
401 }
402 
403 void KDReports::PreviewWidgetPrivate::slotPrevPage()
404 {
405  if (!pageList->currentItem() || pageList->currentRow() == 0)
406  return;
407  pageList->setCurrentRow(pageList->currentRow() - 1);
408 }
409 
410 void KDReports::PreviewWidgetPrivate::slotNextPage()
411 {
412  if (!pageList->currentItem() || pageList->currentRow() >= pageList->count() - 1)
413  return;
414  pageList->setCurrentRow(pageList->currentRow() + 1);
415 }
416 
417 void KDReports::PreviewWidgetPrivate::slotLastPage()
418 {
419  if (pageList->count() == 0) // can't happen
420  return;
421  pageList->setCurrentRow(pageList->count() - 1);
422 }
423 
424 void KDReports::PreviewWidgetPrivate::slotPaperSizeActivated(int index)
425 {
426  const QPageSize qPageSize(static_cast<QPageSize::PageSizeId>(paperSizeCombo->itemData(index).toInt()));
427  m_printer.setPageSize(qPageSize);
428  if (qPageSize.id() == QPageSize::Custom) {
429  m_report->setWidthForEndlessPrinter(m_endlessPrinterWidth);
430  } else {
431  m_report->setWidthForEndlessPrinter(0);
432  m_report->setPageSize(qPageSize);
433  }
434  pageCountChanged();
435 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
436  emit q->pageSizeChanged(static_cast<QPrinter::PageSize>(qPageSize.id()));
437 #else
438  emit q->pageSizeChanged(qPageSize);
439 #endif
440 }
441 
442 void KDReports::PreviewWidgetPrivate::slotPaperOrientationActivated(int index)
443 {
444  const QPageLayout::Orientation orientation = static_cast<QPageLayout::Orientation>(paperOrientationCombo->itemData(index).toInt());
445  m_printer.setPageOrientation(orientation);
446  m_report->setPageOrientation(orientation);
447  pageCountChanged();
448 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
449  emit q->orientationChanged(static_cast<QPrinter::Orientation>(orientation));
450 #else
451  emit q->orientationChanged(orientation);
452 #endif
453 }
454 
455 void KDReports::PreviewWidgetPrivate::pageCountChanged()
456 {
457  qApp->setOverrideCursor(Qt::WaitCursor); // layouting could take a long time
458  if (m_printer.pageLayout().pageSize().id() == QPageSize::Custom) {
459  // Printing without page breaks -> only one page
460  m_pageCount = 1;
461  } else {
462  m_pageCount = m_report->numberOfPages();
463  // qDebug() << "Report has" << m_pageCount << "pages";
464  }
465 
466 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
467  int numberWidth = 20 + pageNumber->fontMetrics().width(QString::number(m_pageCount));
468 #else
469  int numberWidth = 20 + pageNumber->fontMetrics().horizontalAdvance(QString::number(m_pageCount));
470 #endif
471  pageNumber->setMinimumWidth(numberWidth);
472  pageNumber->setMaximumWidth(numberWidth);
473  pageCount->setText(QStringLiteral(" / ") + QString::number(m_pageCount));
474 
475  // Ensure that the treewidget has the right number of items
476  int numberOfItems = pageList->count();
477  while (numberOfItems < m_pageCount) {
478  auto *item = new QListWidgetItem(pageList);
479  item->setText(QString::number(numberOfItems + 1));
480  item->setCheckState(Qt::Checked);
481  ++numberOfItems;
482  }
483  if (pageList->currentRow() >= m_pageCount) { // avoid crash
484  // qDebug() << "Adjusting current row to" << m_pageCount - 1;
485  pageList->setCurrentRow(m_pageCount - 1);
486  }
487  while (numberOfItems > m_pageCount) {
488  delete pageList->item(numberOfItems - 1);
489  --numberOfItems;
490  }
491 
492  QPixmap whitePixmap(PreviewSize, PreviewSize);
493  whitePixmap.fill(Qt::white);
494 
495  for (int index = 0; index < m_pageCount; ++index)
496  pageList->item(index)->setIcon(whitePixmap);
497 
498  m_firstDirtyPreviewItem = 0;
499 // #define PAINT_ALL_PREVIEWS
500 #ifdef PAINT_ALL_PREVIEWS
501  QTime dt;
502  dt.start();
503  while (m_firstDirtyPreviewItem != -1) {
504  previewNextItems();
505  }
506  // Debug mode:
507  // 500 rows, Qt-4.5 or 4.6, no antialiasing, T500 laptop, -O0 or -O2: 42 previews in 8.2s to 8.8s
508  qDebug() << m_pageCount << "previews in" << dt.elapsed() / 1000.0 << "s";
509 #else
510  m_previewTimer.start(0);
511 #endif
512 
513  updatePageButtons();
514  updatePreview();
515  centerPreview();
516  qApp->restoreOverrideCursor();
517 }
518 
519 void KDReports::PreviewWidgetPrivate::centerPreview()
520 {
521 #if 0 // extreme flicker, due to QScrollArea doing a move(0,0) every time (issue N152085)
522  // TT suggested as workaround to use QAbstractScrollArea instead, didn't try yet.
523  const QPoint offset( ( previewArea->width() - m_previewWidget->width() ) / 2,
524  ( previewArea->height() - m_previewWidget->height() ) / 2 );
525  qDebug() << "Moving to " << offset;
526  m_previewWidget->move( offset );
527 #endif
528  // So: make it big, instead. At least as big as the viewport.
529  int width = qMax(m_previewWidget->pixmapWidth(), previewArea->viewport()->width());
530  int height = qMax(m_previewWidget->pixmapHeight(), previewArea->viewport()->height());
531  m_previewWidget->resize(width, height);
532 }
533 
534 void KDReports::PreviewWidgetPrivate::slotZoomIn()
535 {
536  if (m_zoomFactor > 1.99)
537  m_zoomFactor = qMin<qreal>(4.0, m_zoomFactor + 0.5);
538  else if (m_zoomFactor > 0.99)
539  m_zoomFactor += 0.2;
540  else
541  m_zoomFactor += 0.1;
542  fillZoomCombo();
543  zoomChanged();
544 }
545 
546 void KDReports::PreviewWidgetPrivate::slotZoomOut()
547 {
548  if (m_zoomFactor > 1.99)
549  m_zoomFactor -= 0.5;
550  else if (m_zoomFactor > 0.99)
551  m_zoomFactor -= 0.2;
552  else if (m_zoomFactor >= 0.2)
553  m_zoomFactor -= 0.1;
554  fillZoomCombo();
555  zoomChanged();
556 }
557 
558 void KDReports::PreviewWidgetPrivate::slotZoomChanged()
559 {
560  QString str = zoomCombo->currentText();
561  m_zoomFactor = str.remove(str.indexOf(QChar::fromLatin1('%')), 1).toDouble() / 100.0;
562  zoomChanged();
563 }
564 
565 void KDReports::PreviewWidgetPrivate::zoomChanged()
566 {
567  // qDebug() << m_zoomFactor;
568  updatePreview();
569  centerPreview();
570 }
571 
572 void KDReports::PreviewWidgetPrivate::fillZoomCombo()
573 {
574  static const double s_zoomFactors[] = {0.125, 0.25, 0.333, 0.5, 0.667, 0.75, 1, 1.25, 1.50, 2, 4};
575 
576  zoomCombo->clear();
577  bool currentZoomFound = false;
578  for (const qreal val : s_zoomFactors) {
579  if (!currentZoomFound && m_zoomFactor <= val - 0.001) {
580  zoomCombo->addItem(QString::number(m_zoomFactor * 100) + QChar::fromLatin1('%'), QVariant(val));
581  zoomCombo->setCurrentIndex(zoomCombo->count() - 1);
582  currentZoomFound = true;
583  }
584  zoomCombo->addItem(QString::number(val * 100) + QChar::fromLatin1('%'), QVariant(val));
585  if (m_zoomFactor > val - 0.001 && m_zoomFactor < val + 0.001) {
586  zoomCombo->setCurrentIndex(zoomCombo->count() - 1);
587  currentZoomFound = true;
588  }
589  }
590 }
591 
593 
595  : QWidget(parent)
596  , d(new PreviewWidgetPrivate(this))
597 {
598  d->init();
599 }
600 
602 {
603 }
604 
605 bool KDReports::PreviewWidget::isSelected(int pageNumber) const
606 {
607  if (pageNumber >= 0 && pageNumber < d->pageList->count())
608  return (d->pageList->item(pageNumber)->checkState() == Qt::Checked);
609  else
610  return false;
611 }
612 
614 {
615  d->centerPreview();
616 }
617 
619 {
620  d->paperSizeCombo->setVisible(b);
621  d->paperOrientationCombo->setVisible(b);
622  d->labelPaperSize->setVisible(b);
623  d->labelOrientation->setVisible(b);
624 }
625 
627 {
628  d->tableBreakingButton->setVisible(b);
629 }
630 
631 bool KDReports::PreviewWidget::eventFilter(QObject *obj, QEvent *ev)
632 {
633  // Watch for Return in the pageNumber lineedit.
634  // We could just connect to returnPressed(), but the dialog's OK button would still trigger.
635  if (obj == d->pageNumber) {
636  if (ev->type() == QEvent::KeyPress) {
637  auto *keyev = static_cast<QKeyEvent *>(ev);
638  if (keyev->key() == Qt::Key_Enter || keyev->key() == Qt::Key_Return) {
639  d->pageNumberReturnPressed();
640  keyev->accept();
641  d->previewArea->setFocus();
642  return true;
643  }
644  } else if (ev->type() == QEvent::FocusIn) {
645  d->m_eatPageNumberClick = true;
646  d->pageNumber->selectAll();
647  } else if (ev->type() == QEvent::MouseButtonPress && d->m_eatPageNumberClick) {
648  d->m_eatPageNumberClick = false;
649  return true;
650  }
651  }
652 
653  return QWidget::eventFilter(obj, ev);
654 }
655 
657 {
658  d->m_endlessPrinterWidth = widthMM;
659 }
660 
662 {
663  return d->m_report;
664 }
665 
667 {
668  QPointer<QPrintDialog> dialog = new QPrintDialog(&d->m_printer, this);
669  // cppcheck-suppress nullPointerRedundantCheck
670  dialog->setOption(QAbstractPrintDialog::PrintSelection, true);
671  // cppcheck-suppress nullPointerRedundantCheck
672  dialog->setOption(QAbstractPrintDialog::PrintPageRange, true);
673  bool ok = false;
674  // cppcheck-suppress nullPointerRedundantCheck
675  if (dialog->exec() == QDialog::Accepted && dialog) {
676  if (dialog->printRange() == QAbstractPrintDialog::AllPages) {
677  // Select all pages
678  for (int pageIndex = 0; pageIndex < d->pageList->count(); ++pageIndex) {
679  d->pageList->item(pageIndex)->setCheckState(Qt::Checked);
680  }
681  } else if (dialog->printRange() == QAbstractPrintDialog::PageRange) {
682  const int fromPage = dialog->fromPage() - 1; // dialog is 1 based
683  const int toPage = dialog->toPage() - 1;
684  // Select only pages from <fromPage> to <toPage>
685  for (int pageIndex = 0; pageIndex < d->pageList->count(); ++pageIndex) {
686  const bool checked = (pageIndex >= fromPage && pageIndex <= toPage);
687  d->pageList->item(pageIndex)->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
688  }
689  }
690  d->printSelectedPages();
691  ok = true;
692  }
693  delete dialog;
694  return ok;
695 }
696 
698 {
699  d->setReport(report);
700 }
701 
702 void KDReports::PreviewWidgetPrivate::setReport(KDReports::Report *report)
703 {
704  Q_ASSERT(report);
705  m_report = report;
706  actionBar->setEnabled(true);
707 
708  // initialize combos from report
709 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
710  paperSizeCombo->setCurrentIndex(paperSizeCombo->findData(m_report->pageSize()));
711 #else
712  paperSizeCombo->setCurrentIndex(paperSizeCombo->findData(m_report->pageSize().id()));
713 #endif
714  paperOrientationCombo->setCurrentIndex(paperOrientationCombo->findData(m_report->pageOrientation()));
715 
716  tableBreakingButton->setVisible(m_report->reportMode() == KDReports::Report::SpreadSheet);
717 
718  m_report->setupPrinter(&m_printer);
719  pageCountChanged();
720  if (!pageList->currentItem()) {
721  // No page selected yet - select the first one
722  pageList->setCurrentItem(pageList->item(0));
723  }
724  slotCurrentPageChanged(); // update preview and buttons
725  pageList->scrollToTop();
726 }
727 
729 {
730  d->pageList->setVisible(show);
731 }
732 
734 {
735  d->pageCountChanged();
736  d->slotCurrentPageChanged(); // update preview and buttons
737 }
738 
740 {
741  return QSize(800, 600);
742 }
743 
744 #include "KDReportsPreviewWidget.moc"
PreviewWidget(QWidget *parent=nullptr)
void resizeEvent(QResizeEvent *) override
Reimplemented for internal purposes. .
bool isSelected(int pageNumber) const
void setWidthForEndlessPrinter(qreal widthMM)
void setReport(KDReports::Report *report)
bool eventFilter(QObject *, QEvent *) override
Reimplemented for internal purposes. .
KDReports::Report * report() const
QSize sizeHint() const override
@ AllPages
All pages (except first and last if FirstPage or LastPage have their own headers)

© Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
https://www.kdab.com/development-resources/qt-tools/kd-reports/
Generated by doxygen 1.9.1