23 #include <QPrintDialog>
24 #include <QProgressDialog>
30 #include "ui_previewdialogbase.h"
36 class PagePreviewWidget :
public QWidget
40 PagePreviewWidget(QWidget *parent =
nullptr)
44 setMouseTracking(
true);
46 void setPixmap(
const QPixmap &pixmap)
51 int pixmapWidth()
const {
return m_pixmap.width(); }
52 int pixmapHeight()
const {
return m_pixmap.height(); }
53 QSize pixmapSize()
const {
return m_pixmap.size(); }
56 void mouseMoved(QPoint pos);
57 void mouseClicked(QPoint pos);
60 QPoint pixmapOffset()
const
62 return QPoint((width() - m_pixmap.width()) / 2, (height() - m_pixmap.height()) / 2);
65 void paintEvent(QPaintEvent *)
override
67 QPainter painter(
this);
69 painter.drawPixmap(pixmapOffset(), m_pixmap);
72 void mouseMoveEvent(QMouseEvent *ev)
override
74 Q_EMIT mouseMoved(ev->pos() - pixmapOffset());
77 void mouseReleaseEvent(QMouseEvent *ev)
override
79 Q_EMIT mouseClicked(ev->pos() - pixmapOffset());
86 class KDReports::PreviewWidgetPrivate :
public Ui::PreviewWidgetBase
94 void paintItem(QListWidgetItem *item,
int index)
const;
95 QPixmap paintPreview(
int index)
const;
96 void printSelectedPages();
97 void setupComboBoxes();
98 void pageCountChanged();
101 void fillZoomCombo();
102 void updatePageButtons();
103 void updatePreview();
104 void pageNumberReturnPressed();
107 void handleMouseMove(QPoint pos);
108 void handleMouseRelease(QPoint pos);
109 void slotCurrentPageChanged();
110 void slotFirstPage();
114 void slotPaperSizeActivated(
int);
115 void slotPaperOrientationActivated(
int);
118 void slotZoomChanged();
119 void previewNextItems();
121 PagePreviewWidget *m_previewWidget;
123 qreal m_zoomFactor = 1.0;
124 qreal m_endlessPrinterWidth = 114.0;
126 QTimer m_previewTimer;
129 int m_firstDirtyPreviewItem = -1;
130 bool m_eatPageNumberClick =
false;
131 bool m_onAnchor =
false;
135 : m_previewWidget(new PagePreviewWidget)
138 QObject::connect(&m_previewTimer, &QTimer::timeout, q, [
this]() { previewNextItems(); });
139 QObject::connect(m_previewWidget, &PagePreviewWidget::mouseMoved, q, [
this](QPoint pos) {
140 handleMouseMove(pos);
142 QObject::connect(m_previewWidget, &PagePreviewWidget::mouseClicked, q, [
this](QPoint pos) {
143 handleMouseRelease(pos);
147 void KDReports::PreviewWidgetPrivate::init()
150 actionBar->setEnabled(
false);
152 m_printer.setFullPage(
true);
155 pageList->setViewMode(QListView::IconMode);
156 pageList->setMovement(QListView::Static);
157 previewArea->setWidget(m_previewWidget);
159 previewArea->setFocus();
163 QObject::connect(tableBreakingButton, &QAbstractButton::clicked, q, &PreviewWidget::tableSettingsClicked);
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); });
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);
186 void KDReports::PreviewWidgetPrivate::paintItem(QListWidgetItem *item,
int index)
const
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;
198 img.fill(qRgba(0, 0, 0, 0));
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()));
208 item->setIcon(QIcon(QPixmap::fromImage(img)));
211 void KDReports::PreviewWidgetPrivate::previewNextItems()
213 if (m_firstDirtyPreviewItem == -1 || m_firstDirtyPreviewItem >= m_pageCount) {
214 m_previewTimer.stop();
215 m_firstDirtyPreviewItem = -1;
218 paintItem(pageList->item(m_firstDirtyPreviewItem), m_firstDirtyPreviewItem);
219 ++m_firstDirtyPreviewItem;
223 QPixmap KDReports::PreviewWidgetPrivate::paintPreview(
int index)
const
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);
229 QPixmap pixmap(width, height);
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()));
246 void KDReports::PreviewWidgetPrivate::handleMouseMove(QPoint pos)
248 const QPoint unscaledPos = pos / m_zoomFactor;
249 const QString link = m_report->anchorAt(pageList->currentRow(), unscaledPos);
250 if (link.isEmpty()) {
253 }
else if (!m_onAnchor) {
254 q->setCursor(Qt::PointingHandCursor);
259 void KDReports::PreviewWidgetPrivate::handleMouseRelease(QPoint pos)
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);
268 void KDReports::PreviewWidgetPrivate::printSelectedPages()
272 m_report->setPageSize(m_printer.pageLayout().pageSize());
273 m_report->setPageOrientation(m_printer.pageLayout().orientation());
280 for (
int pageIndex = 0; pageIndex < pageList->count(); ++pageIndex) {
281 if (pageList->item(pageIndex)->checkState() == Qt::Checked)
285 QProgressDialog dialog(QObject::tr(
"Printing"), QObject::tr(
"Cancel"), 0, markedPages, q);
286 dialog.setWindowModality(Qt::ApplicationModal);
289 painter.begin(&m_printer);
292 bool firstPage =
true;
293 for (
int pageIndex = 0; pageIndex < m_pageCount; ++pageIndex) {
296 qApp->processEvents();
298 if (dialog.wasCanceled())
301 if (q->isSelected(pageIndex)) {
306 m_report->paintPage(pageIndex, painter);
307 dialog.setValue(++printed);
314 void KDReports::PreviewWidgetPrivate::setupComboBoxes()
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);
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);
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);
348 paperOrientationCombo->addItem(PreviewWidget::tr(
"Portrait"), QPageLayout::Portrait);
349 paperOrientationCombo->addItem(PreviewWidget::tr(
"Landscape"), QPageLayout::Landscape);
352 void KDReports::PreviewWidgetPrivate::slotCurrentPageChanged()
358 void KDReports::PreviewWidgetPrivate::updatePageButtons()
360 prevPage->setEnabled(pageList->currentRow() > 0);
361 nextPage->setEnabled(pageList->currentRow() < pageList->count() - 1);
362 pageNumber->setText(QString::number(pageList->currentRow() + 1));
365 void KDReports::PreviewWidgetPrivate::updatePreview()
367 if (!pageList->currentItem())
369 const QSize oldSize = m_previewWidget->pixmapSize();
370 const QPixmap pixmap = paintPreview(pageList->currentRow());
371 m_previewWidget->setPixmap(pixmap);
372 if (pixmap.size() != oldSize) {
377 void KDReports::PreviewWidgetPrivate::pageNumberReturnPressed()
380 const int newPageNumber = pageNumber->text().toInt(&ok) - 1;
381 if (!ok || newPageNumber < 0 || newPageNumber > pageList->count() - 1)
383 pageList->setCurrentRow(newPageNumber);
386 void KDReports::PreviewWidgetPrivate::slotFirstPage()
388 pageList->setCurrentRow(0);
391 void KDReports::PreviewWidgetPrivate::slotPrevPage()
393 if (!pageList->currentItem() || pageList->currentRow() == 0)
395 pageList->setCurrentRow(pageList->currentRow() - 1);
398 void KDReports::PreviewWidgetPrivate::slotNextPage()
400 if (!pageList->currentItem() || pageList->currentRow() >= pageList->count() - 1)
402 pageList->setCurrentRow(pageList->currentRow() + 1);
405 void KDReports::PreviewWidgetPrivate::slotLastPage()
407 if (pageList->count() == 0)
409 pageList->setCurrentRow(pageList->count() - 1);
412 void KDReports::PreviewWidgetPrivate::slotPaperSizeActivated(
int index)
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);
419 m_report->setWidthForEndlessPrinter(0);
420 m_report->setPageSize(qPageSize);
423 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
424 emit q->pageSizeChanged(
static_cast<QPrinter::PageSize
>(qPageSize.id()));
426 emit q->pageSizeChanged(qPageSize);
430 void KDReports::PreviewWidgetPrivate::slotPaperOrientationActivated(
int index)
432 const QPageLayout::Orientation orientation =
static_cast<QPageLayout::Orientation
>(paperOrientationCombo->itemData(index).toInt());
433 m_printer.setPageOrientation(orientation);
434 m_report->setPageOrientation(orientation);
436 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
437 emit q->orientationChanged(
static_cast<QPrinter::Orientation
>(orientation));
439 emit q->orientationChanged(orientation);
443 void KDReports::PreviewWidgetPrivate::pageCountChanged()
445 qApp->setOverrideCursor(Qt::WaitCursor);
446 if (m_printer.pageLayout().pageSize().id() == QPageSize::Custom) {
450 m_pageCount = m_report->numberOfPages();
454 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
455 int numberWidth = 20 + pageNumber->fontMetrics().width(QString::number(m_pageCount));
457 int numberWidth = 20 + pageNumber->fontMetrics().horizontalAdvance(QString::number(m_pageCount));
459 pageNumber->setMinimumWidth(numberWidth);
460 pageNumber->setMaximumWidth(numberWidth);
461 pageCount->setText(QStringLiteral(
" / ") + QString::number(m_pageCount));
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);
471 if (pageList->currentRow() >= m_pageCount) {
473 pageList->setCurrentRow(m_pageCount - 1);
475 while (numberOfItems > m_pageCount) {
476 delete pageList->item(numberOfItems - 1);
481 whitePixmap.fill(Qt::white);
483 for (
int index = 0; index < m_pageCount; ++index)
484 pageList->item(index)->setIcon(whitePixmap);
486 m_firstDirtyPreviewItem = 0;
488 #ifdef PAINT_ALL_PREVIEWS
491 while (m_firstDirtyPreviewItem != -1) {
496 qDebug() << m_pageCount <<
"previews in" << dt.elapsed() / 1000.0 <<
"s";
498 m_previewTimer.start(0);
504 qApp->restoreOverrideCursor();
507 void KDReports::PreviewWidgetPrivate::centerPreview()
509 #if 0 // extreme flicker, due to QScrollArea doing a move(0,0) every time (issue N152085)
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 );
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);
522 void KDReports::PreviewWidgetPrivate::slotZoomIn()
524 if (m_zoomFactor > 1.99)
525 m_zoomFactor = qMin<qreal>(4.0, m_zoomFactor + 0.5);
526 else if (m_zoomFactor > 0.99)
534 void KDReports::PreviewWidgetPrivate::slotZoomOut()
536 if (m_zoomFactor > 1.99)
538 else if (m_zoomFactor > 0.99)
540 else if (m_zoomFactor >= 0.2)
546 void KDReports::PreviewWidgetPrivate::slotZoomChanged()
548 QString str = zoomCombo->currentText();
549 m_zoomFactor = str.remove(str.indexOf(QChar::fromLatin1(
'%')), 1).toDouble() / 100.0;
553 void KDReports::PreviewWidgetPrivate::zoomChanged()
560 void KDReports::PreviewWidgetPrivate::fillZoomCombo()
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};
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;
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;
584 , d(new PreviewWidgetPrivate(this))
596 if (pageNumber >= 0 && pageNumber < d->pageList->count())
597 return (d->pageList->item(pageNumber)->checkState() == Qt::Checked);
609 d->paperSizeCombo->setVisible(b);
610 d->paperOrientationCombo->setVisible(b);
611 d->labelPaperSize->setVisible(b);
612 d->labelOrientation->setVisible(b);
617 d->tableBreakingButton->setVisible(b);
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();
630 d->previewArea->setFocus();
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;
642 return QWidget::eventFilter(obj, ev);
647 d->m_endlessPrinterWidth = widthMM;
657 QPointer<QPrintDialog> dialog =
new QPrintDialog(&d->m_printer,
this);
658 dialog->setOption(QAbstractPrintDialog::PrintSelection,
true);
659 dialog->setOption(QAbstractPrintDialog::PrintPageRange,
true);
662 if (dialog->exec() == QDialog::Accepted && dialog) {
665 for (
int pageIndex = 0; pageIndex < d->pageList->count(); ++pageIndex) {
666 d->pageList->item(pageIndex)->setCheckState(Qt::Checked);
668 }
else if (dialog->printRange() == QAbstractPrintDialog::PageRange) {
669 const int fromPage = dialog->fromPage() - 1;
670 const int toPage = dialog->toPage() - 1;
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);
677 d->printSelectedPages();
686 d->setReport(report);
693 actionBar->setEnabled(
true);
696 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
697 paperSizeCombo->setCurrentIndex(paperSizeCombo->findData(m_report->pageSize()));
699 paperSizeCombo->setCurrentIndex(paperSizeCombo->findData(m_report->pageSize().id()));
701 paperOrientationCombo->setCurrentIndex(paperOrientationCombo->findData(m_report->pageOrientation()));
705 m_report->setupPrinter(&m_printer);
707 if (!pageList->currentItem()) {
709 pageList->setCurrentItem(pageList->item(0));
711 slotCurrentPageChanged();
712 pageList->scrollToTop();
717 d->pageList->setVisible(show);
722 d->pageCountChanged();
723 d->slotCurrentPageChanged();
728 return QSize(800, 600);
731 #include "KDReportsPreviewWidget.moc"