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

© 2007-2021 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 on Sat Jan 8 2022 02:38:32 for KD Reports API Documentation by doxygen 1.8.17