17 #include <QPrintDialog>
18 #include <QProgressDialog>
24 #include "ui_previewdialogbase.h"
33 class PagePreviewWidget :
public QWidget
37 PagePreviewWidget(QWidget *parent =
nullptr)
41 setMouseTracking(
true);
43 void setPixmap(
const QPixmap &pixmap)
48 int pixmapWidth()
const
50 return m_pixmap.width();
52 int pixmapHeight()
const
54 return m_pixmap.height();
56 QSize pixmapSize()
const
58 return m_pixmap.size();
62 void mouseMoved(QPoint pos);
63 void mouseClicked(QPoint pos);
66 QPoint pixmapOffset()
const
68 return QPoint((width() - m_pixmap.width()) / 2, (height() - m_pixmap.height()) / 2);
71 void paintEvent(QPaintEvent *)
override
73 QPainter painter(
this);
75 painter.drawPixmap(pixmapOffset(), m_pixmap);
78 void mouseMoveEvent(QMouseEvent *ev)
override
80 Q_EMIT mouseMoved(ev->pos() - pixmapOffset());
83 void mouseReleaseEvent(QMouseEvent *ev)
override
85 Q_EMIT mouseClicked(ev->pos() - pixmapOffset());
92 class KDReports::PreviewWidgetPrivate :
public Ui::PreviewWidgetBase
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();
107 void fillZoomCombo();
108 void updatePageButtons();
109 void updatePreview();
110 void pageNumberReturnPressed();
113 void handleMouseMove(QPoint pos);
114 void handleMouseRelease(QPoint pos);
115 void slotCurrentPageChanged();
116 void slotFirstPage();
120 void slotPaperSizeActivated(
int);
121 void slotPaperOrientationActivated(
int);
124 void slotZoomChanged();
125 void previewNextItems();
127 PagePreviewWidget *m_previewWidget;
129 qreal m_zoomFactor = 1.0;
130 qreal m_endlessPrinterWidth = 114.0;
132 QTimer m_previewTimer;
135 int m_firstDirtyPreviewItem = -1;
136 bool m_eatPageNumberClick =
false;
137 bool m_onAnchor =
false;
141 : m_previewWidget(new PagePreviewWidget)
144 QObject::connect(&m_previewTimer, &QTimer::timeout, q, [
this]() { previewNextItems(); });
145 QObject::connect(m_previewWidget, &PagePreviewWidget::mouseMoved, q, [
this](QPoint pos) {
146 handleMouseMove(pos);
148 QObject::connect(m_previewWidget, &PagePreviewWidget::mouseClicked, q, [
this](QPoint pos) {
149 handleMouseRelease(pos);
153 void KDReports::PreviewWidgetPrivate::init()
156 actionBar->setEnabled(
false);
158 m_printer.setFullPage(
true);
161 pageList->setViewMode(QListView::IconMode);
162 pageList->setMovement(QListView::Static);
163 previewArea->setWidget(m_previewWidget);
165 previewArea->setFocus();
169 QObject::connect(tableBreakingButton, &QAbstractButton::clicked, q, &PreviewWidget::tableSettingsClicked);
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); });
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);
192 void KDReports::PreviewWidgetPrivate::paintItem(QListWidgetItem *item,
int index)
const
198 const qreal dpr = q->devicePixelRatioF();
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);
211 painter.fillRect(QRectF(0, 0, width, height), QBrush(Qt::white));
213 m_report->paintPage(index, painter);
214 painter.setPen(QPen(1));
215 painter.drawRect(QRectF(0, 0, paperWidth, paperHeight));
217 item->setIcon(QIcon(QPixmap::fromImage(img)));
220 void KDReports::PreviewWidgetPrivate::previewNextItems()
222 if (m_firstDirtyPreviewItem == -1 || m_firstDirtyPreviewItem >= m_pageCount) {
223 m_previewTimer.stop();
224 m_firstDirtyPreviewItem = -1;
227 paintItem(pageList->item(m_firstDirtyPreviewItem), m_firstDirtyPreviewItem);
228 ++m_firstDirtyPreviewItem;
232 QPixmap KDReports::PreviewWidgetPrivate::paintPreview(
int index)
const
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();
239 QPixmap pixmap(width * dpr, height * dpr);
240 pixmap.setDevicePixelRatio(dpr);
241 pixmap.fill(Qt::transparent);
246 QPainter painter(&pixmap);
247 painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform,
true);
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()));
258 void KDReports::PreviewWidgetPrivate::handleMouseMove(QPoint pos)
260 const QPoint unscaledPos = pos / m_zoomFactor;
261 const QString link = m_report->anchorAt(pageList->currentRow(), unscaledPos);
262 if (link.isEmpty()) {
265 }
else if (!m_onAnchor) {
266 q->setCursor(Qt::PointingHandCursor);
271 void KDReports::PreviewWidgetPrivate::handleMouseRelease(QPoint pos)
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);
280 void KDReports::PreviewWidgetPrivate::printSelectedPages()
284 m_report->setPageSize(m_printer.pageLayout().pageSize());
285 m_report->setPageOrientation(m_printer.pageLayout().orientation());
292 for (
int pageIndex = 0; pageIndex < pageList->count(); ++pageIndex) {
293 if (pageList->item(pageIndex)->checkState() == Qt::Checked)
297 QProgressDialog dialog(QObject::tr(
"Printing"), QObject::tr(
"Cancel"), 0, markedPages, q);
298 dialog.setWindowModality(Qt::ApplicationModal);
301 painter.begin(&m_printer);
304 bool firstPage =
true;
305 for (
int pageIndex = 0; pageIndex < m_pageCount; ++pageIndex) {
308 qApp->processEvents();
310 if (dialog.wasCanceled())
313 if (q->isSelected(pageIndex)) {
318 m_report->paintPage(pageIndex, painter);
319 dialog.setValue(++printed);
326 void KDReports::PreviewWidgetPrivate::setupComboBoxes()
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);
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);
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);
360 paperOrientationCombo->addItem(PreviewWidget::tr(
"Portrait"), QPageLayout::Portrait);
361 paperOrientationCombo->addItem(PreviewWidget::tr(
"Landscape"), QPageLayout::Landscape);
364 void KDReports::PreviewWidgetPrivate::slotCurrentPageChanged()
370 void KDReports::PreviewWidgetPrivate::updatePageButtons()
372 prevPage->setEnabled(pageList->currentRow() > 0);
373 nextPage->setEnabled(pageList->currentRow() < pageList->count() - 1);
374 pageNumber->setText(QString::number(pageList->currentRow() + 1));
377 void KDReports::PreviewWidgetPrivate::updatePreview()
379 if (!pageList->currentItem())
381 const QSize oldSize = m_previewWidget->pixmapSize();
382 const QPixmap pixmap = paintPreview(pageList->currentRow());
383 m_previewWidget->setPixmap(pixmap);
384 if (pixmap.size() != oldSize) {
389 void KDReports::PreviewWidgetPrivate::pageNumberReturnPressed()
392 const int newPageNumber = pageNumber->text().toInt(&ok) - 1;
393 if (!ok || newPageNumber < 0 || newPageNumber > pageList->count() - 1)
395 pageList->setCurrentRow(newPageNumber);
398 void KDReports::PreviewWidgetPrivate::slotFirstPage()
400 pageList->setCurrentRow(0);
403 void KDReports::PreviewWidgetPrivate::slotPrevPage()
405 if (!pageList->currentItem() || pageList->currentRow() == 0)
407 pageList->setCurrentRow(pageList->currentRow() - 1);
410 void KDReports::PreviewWidgetPrivate::slotNextPage()
412 if (!pageList->currentItem() || pageList->currentRow() >= pageList->count() - 1)
414 pageList->setCurrentRow(pageList->currentRow() + 1);
417 void KDReports::PreviewWidgetPrivate::slotLastPage()
419 if (pageList->count() == 0)
421 pageList->setCurrentRow(pageList->count() - 1);
424 void KDReports::PreviewWidgetPrivate::slotPaperSizeActivated(
int index)
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);
431 m_report->setWidthForEndlessPrinter(0);
432 m_report->setPageSize(qPageSize);
435 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
436 emit q->pageSizeChanged(
static_cast<QPrinter::PageSize
>(qPageSize.id()));
438 emit q->pageSizeChanged(qPageSize);
442 void KDReports::PreviewWidgetPrivate::slotPaperOrientationActivated(
int index)
444 const QPageLayout::Orientation orientation =
static_cast<QPageLayout::Orientation
>(paperOrientationCombo->itemData(index).toInt());
445 m_printer.setPageOrientation(orientation);
446 m_report->setPageOrientation(orientation);
448 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
449 emit q->orientationChanged(
static_cast<QPrinter::Orientation
>(orientation));
451 emit q->orientationChanged(orientation);
455 void KDReports::PreviewWidgetPrivate::pageCountChanged()
457 qApp->setOverrideCursor(Qt::WaitCursor);
458 if (m_printer.pageLayout().pageSize().id() == QPageSize::Custom) {
462 m_pageCount = m_report->numberOfPages();
466 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
467 int numberWidth = 20 + pageNumber->fontMetrics().width(QString::number(m_pageCount));
469 int numberWidth = 20 + pageNumber->fontMetrics().horizontalAdvance(QString::number(m_pageCount));
471 pageNumber->setMinimumWidth(numberWidth);
472 pageNumber->setMaximumWidth(numberWidth);
473 pageCount->setText(QStringLiteral(
" / ") + QString::number(m_pageCount));
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);
483 if (pageList->currentRow() >= m_pageCount) {
485 pageList->setCurrentRow(m_pageCount - 1);
487 while (numberOfItems > m_pageCount) {
488 delete pageList->item(numberOfItems - 1);
493 whitePixmap.fill(Qt::white);
495 for (
int index = 0; index < m_pageCount; ++index)
496 pageList->item(index)->setIcon(whitePixmap);
498 m_firstDirtyPreviewItem = 0;
500 #ifdef PAINT_ALL_PREVIEWS
503 while (m_firstDirtyPreviewItem != -1) {
508 qDebug() << m_pageCount <<
"previews in" << dt.elapsed() / 1000.0 <<
"s";
510 m_previewTimer.start(0);
516 qApp->restoreOverrideCursor();
519 void KDReports::PreviewWidgetPrivate::centerPreview()
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 );
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);
534 void KDReports::PreviewWidgetPrivate::slotZoomIn()
536 if (m_zoomFactor > 1.99)
537 m_zoomFactor = qMin<qreal>(4.0, m_zoomFactor + 0.5);
538 else if (m_zoomFactor > 0.99)
546 void KDReports::PreviewWidgetPrivate::slotZoomOut()
548 if (m_zoomFactor > 1.99)
550 else if (m_zoomFactor > 0.99)
552 else if (m_zoomFactor >= 0.2)
558 void KDReports::PreviewWidgetPrivate::slotZoomChanged()
560 QString str = zoomCombo->currentText();
561 m_zoomFactor = str.remove(str.indexOf(QChar::fromLatin1(
'%')), 1).toDouble() / 100.0;
565 void KDReports::PreviewWidgetPrivate::zoomChanged()
572 void KDReports::PreviewWidgetPrivate::fillZoomCombo()
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};
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;
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;
596 , d(new PreviewWidgetPrivate(this))
607 if (pageNumber >= 0 && pageNumber < d->pageList->count())
608 return (d->pageList->item(pageNumber)->checkState() == Qt::Checked);
620 d->paperSizeCombo->setVisible(b);
621 d->paperOrientationCombo->setVisible(b);
622 d->labelPaperSize->setVisible(b);
623 d->labelOrientation->setVisible(b);
628 d->tableBreakingButton->setVisible(b);
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();
641 d->previewArea->setFocus();
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;
653 return QWidget::eventFilter(obj, ev);
658 d->m_endlessPrinterWidth = widthMM;
668 QPointer<QPrintDialog> dialog =
new QPrintDialog(&d->m_printer,
this);
670 dialog->setOption(QAbstractPrintDialog::PrintSelection,
true);
672 dialog->setOption(QAbstractPrintDialog::PrintPageRange,
true);
675 if (dialog->exec() == QDialog::Accepted && dialog) {
678 for (
int pageIndex = 0; pageIndex < d->pageList->count(); ++pageIndex) {
679 d->pageList->item(pageIndex)->setCheckState(Qt::Checked);
681 }
else if (dialog->printRange() == QAbstractPrintDialog::PageRange) {
682 const int fromPage = dialog->fromPage() - 1;
683 const int toPage = dialog->toPage() - 1;
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);
690 d->printSelectedPages();
699 d->setReport(report);
706 actionBar->setEnabled(
true);
709 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
710 paperSizeCombo->setCurrentIndex(paperSizeCombo->findData(m_report->pageSize()));
712 paperSizeCombo->setCurrentIndex(paperSizeCombo->findData(m_report->pageSize().id()));
714 paperOrientationCombo->setCurrentIndex(paperOrientationCombo->findData(m_report->pageOrientation()));
718 m_report->setupPrinter(&m_printer);
720 if (!pageList->currentItem()) {
722 pageList->setCurrentItem(pageList->item(0));
724 slotCurrentPageChanged();
725 pageList->scrollToTop();
730 d->pageList->setVisible(show);
735 d->pageCountChanged();
736 d->slotCurrentPageChanged();
741 return QSize(800, 600);
744 #include "KDReportsPreviewWidget.moc"
@ AllPages
All pages (except first and last if FirstPage or LastPage have their own headers)