1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qprintpreviewdialog.h"
5#include "qprintpreviewwidget.h"
6#include <private/qprinter_p.h>
7#include "qprintdialog.h"
8
9#include <QtGui/qaction.h>
10#include <QtGui/qactiongroup.h>
11#include <QtWidgets/qboxlayout.h>
12#include <QtWidgets/qcombobox.h>
13#include <QtWidgets/qlineedit.h>
14#include <QtPrintSupport/qpagesetupdialog.h>
15#include <QtPrintSupport/qprinter.h>
16#include <QtWidgets/qstyle.h>
17#include <QtWidgets/qtoolbutton.h>
18#include <QtGui/qvalidator.h>
19#if QT_CONFIG(filedialog)
20#include <QtWidgets/qfiledialog.h>
21#endif
22#include <QtWidgets/qmainwindow.h>
23#include <QtWidgets/qtoolbar.h>
24#include <QtCore/QCoreApplication>
25
26#include "private/qdialog_p.h"
27
28#include <QtWidgets/qformlayout.h>
29#include <QtWidgets/qlabel.h>
30
31#include <QtCore/qpointer.h>
32
33static void _q_ppd_initResources()
34{
35 static bool resourcesInitialized = false;
36 if (!resourcesInitialized) {
37 Q_INIT_RESOURCE(qprintdialog);
38 resourcesInitialized = true;
39 }
40}
41
42QT_BEGIN_NAMESPACE
43
44using namespace Qt::StringLiterals;
45
46namespace {
47class QPrintPreviewMainWindow : public QMainWindow
48{
49public:
50 QPrintPreviewMainWindow(QWidget *parent) : QMainWindow(parent) {}
51 QMenu *createPopupMenu() override { return nullptr; }
52};
53
54class ZoomFactorValidator : public QDoubleValidator
55{
56public:
57 ZoomFactorValidator(QObject* parent)
58 : QDoubleValidator(parent) {}
59 ZoomFactorValidator(qreal bottom, qreal top, int decimals, QObject *parent)
60 : QDoubleValidator(bottom, top, decimals, parent) {}
61
62 State validate(QString &input, int &pos) const override
63 {
64 bool replacePercent = false;
65 if (input.endsWith(c: u'%')) {
66 input = input.left(n: input.size() - 1);
67 replacePercent = true;
68 }
69 State state = QDoubleValidator::validate(input, pos);
70 if (replacePercent)
71 input += u'%';
72 const int num_size = 4;
73 if (state == Intermediate) {
74 int i = input.indexOf(s: QLocale::system().decimalPoint());
75 if ((i == -1 && input.size() > num_size)
76 || (i != -1 && i > num_size))
77 return Invalid;
78 }
79 return state;
80 }
81};
82
83class LineEdit : public QLineEdit
84{
85 Q_OBJECT
86public:
87 LineEdit(QWidget* parent = nullptr)
88 : QLineEdit(parent)
89 {
90 setContextMenuPolicy(Qt::NoContextMenu);
91 connect(sender: this, signal: &LineEdit::returnPressed, context: this, slot: &LineEdit::handleReturnPressed);
92 }
93
94protected:
95 void focusInEvent(QFocusEvent *e) override
96 {
97 origText = text();
98 QLineEdit::focusInEvent(e);
99 }
100
101 void focusOutEvent(QFocusEvent *e) override
102 {
103 if (isModified() && !hasAcceptableInput())
104 setText(origText);
105 QLineEdit::focusOutEvent(e);
106 }
107
108private slots:
109 void handleReturnPressed()
110 {
111 origText = text();
112 }
113
114private:
115 QString origText;
116};
117} // anonymous namespace
118
119class QPrintPreviewDialogPrivate : public QDialogPrivate
120{
121 Q_DECLARE_PUBLIC(QPrintPreviewDialog)
122public:
123 QPrintPreviewDialogPrivate()
124 : printDialog(nullptr), pageSetupDialog(nullptr),
125 ownPrinter(false), initialized(false) {}
126
127 // private slots
128 void _q_fit(QAction *action);
129 void _q_zoomIn();
130 void _q_zoomOut();
131 void _q_navigate(QAction *action);
132 void _q_setMode(QAction *action);
133 void _q_pageNumEdited();
134 void _q_print();
135 void _q_pageSetup();
136 void _q_previewChanged();
137 void _q_zoomFactorChanged();
138
139 void init(QPrinter *printer = nullptr);
140 void populateScene();
141 void layoutPages();
142 void setupActions();
143 void updateNavActions();
144 QString formattedZoomFactor(double value);
145 void setFitting(bool on);
146 bool isFitting();
147 void updatePageNumLabel();
148 void updateZoomFactor();
149
150 QPrintDialog *printDialog;
151 QPageSetupDialog *pageSetupDialog;
152 QPrintPreviewWidget *preview;
153 QPrinter *printer;
154 bool ownPrinter;
155 bool initialized;
156
157 // widgets:
158 QLineEdit *pageNumEdit;
159 QLabel *pageNumLabel;
160 QComboBox *zoomFactor;
161
162 // actions:
163 QActionGroup* navGroup;
164 QAction *nextPageAction;
165 QAction *prevPageAction;
166 QAction *firstPageAction;
167 QAction *lastPageAction;
168
169 QActionGroup* fitGroup;
170 QAction *fitWidthAction;
171 QAction *fitPageAction;
172
173 QActionGroup* zoomGroup;
174 QAction *zoomInAction;
175 QAction *zoomOutAction;
176
177 QActionGroup* orientationGroup;
178 QAction *portraitAction;
179 QAction *landscapeAction;
180
181 QActionGroup* modeGroup;
182 QAction *singleModeAction;
183 QAction *facingModeAction;
184 QAction *overviewModeAction;
185
186 QActionGroup *printerGroup;
187 QAction *printAction;
188 QAction *pageSetupAction;
189
190 QPointer<QObject> receiverToDisconnectOnClose;
191 QByteArray memberToDisconnectOnClose;
192};
193
194void QPrintPreviewDialogPrivate::init(QPrinter *_printer)
195{
196 Q_Q(QPrintPreviewDialog);
197
198 _q_ppd_initResources();
199
200 if (_printer) {
201 preview = new QPrintPreviewWidget(_printer, q);
202 printer = _printer;
203 } else {
204 ownPrinter = true;
205 printer = new QPrinter;
206 preview = new QPrintPreviewWidget(printer, q);
207 }
208 QObject::connect(sender: preview, SIGNAL(paintRequested(QPrinter*)), receiver: q, SIGNAL(paintRequested(QPrinter*)));
209 QObject::connect(sender: preview, SIGNAL(previewChanged()), receiver: q, SLOT(_q_previewChanged()));
210 setupActions();
211
212 pageNumEdit = new LineEdit;
213 pageNumEdit->setAlignment(Qt::AlignRight);
214 pageNumEdit->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
215 pageNumLabel = new QLabel;
216 QObject::connect(sender: pageNumEdit, SIGNAL(editingFinished()), receiver: q, SLOT(_q_pageNumEdited()));
217
218 zoomFactor = new QComboBox;
219 zoomFactor->setEditable(true);
220 zoomFactor->setMinimumContentsLength(7);
221 zoomFactor->setInsertPolicy(QComboBox::NoInsert);
222 LineEdit *zoomEditor = new LineEdit;
223 zoomEditor->setValidator(new ZoomFactorValidator(1, 1000, 1, zoomEditor));
224 zoomFactor->setLineEdit(zoomEditor);
225 static const short factorsX2[] = { 25, 50, 100, 200, 250, 300, 400, 800, 1600 };
226 for (auto factorX2 : factorsX2)
227 zoomFactor->addItem(atext: formattedZoomFactor(value: factorX2 / 2.0));
228 QObject::connect(sender: zoomFactor->lineEdit(), SIGNAL(editingFinished()),
229 receiver: q, SLOT(_q_zoomFactorChanged()));
230 QObject::connect(sender: zoomFactor, SIGNAL(currentIndexChanged(int)),
231 receiver: q, SLOT(_q_zoomFactorChanged()));
232
233 QPrintPreviewMainWindow *mw = new QPrintPreviewMainWindow(q);
234 QToolBar *toolbar = new QToolBar(mw);
235 toolbar->addAction(action: fitWidthAction);
236 toolbar->addAction(action: fitPageAction);
237 toolbar->addSeparator();
238 toolbar->addWidget(widget: zoomFactor);
239 toolbar->addAction(action: zoomOutAction);
240 toolbar->addAction(action: zoomInAction);
241 toolbar->addSeparator();
242 toolbar->addAction(action: portraitAction);
243 toolbar->addAction(action: landscapeAction);
244 toolbar->addSeparator();
245 toolbar->addAction(action: firstPageAction);
246 toolbar->addAction(action: prevPageAction);
247
248 // this is to ensure the label text and the editor text are
249 // aligned in all styles - the extra QVBoxLayout is a workaround
250 // for bug in QFormLayout
251 QWidget *pageEdit = new QWidget(toolbar);
252 QVBoxLayout *vboxLayout = new QVBoxLayout;
253 vboxLayout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
254#ifdef Q_OS_MACOS
255 // We query the widgets about their size and then we fix the size.
256 // This should do the trick for the laying out part...
257 QSize pageNumEditSize, pageNumLabelSize;
258 pageNumEditSize = pageNumEdit->minimumSizeHint();
259 pageNumLabelSize = pageNumLabel->minimumSizeHint();
260 pageNumEdit->resize(pageNumEditSize);
261 pageNumLabel->resize(pageNumLabelSize);
262#endif
263 QFormLayout *formLayout = new QFormLayout;
264#ifdef Q_OS_MACOS
265 // We have to change the growth policy in Mac.
266 formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
267#endif
268 formLayout->setWidget(row: 0, role: QFormLayout::LabelRole, widget: pageNumEdit);
269 formLayout->setWidget(row: 0, role: QFormLayout::FieldRole, widget: pageNumLabel);
270 vboxLayout->addLayout(layout: formLayout);
271 vboxLayout->setAlignment(Qt::AlignVCenter);
272 pageEdit->setLayout(vboxLayout);
273 toolbar->addWidget(widget: pageEdit);
274
275 toolbar->addAction(action: nextPageAction);
276 toolbar->addAction(action: lastPageAction);
277 toolbar->addSeparator();
278 toolbar->addAction(action: singleModeAction);
279 toolbar->addAction(action: facingModeAction);
280 toolbar->addAction(action: overviewModeAction);
281 toolbar->addSeparator();
282 toolbar->addAction(action: pageSetupAction);
283 toolbar->addAction(action: printAction);
284
285 // Cannot use the actions' triggered signal here, since it doesn't autorepeat
286 QToolButton *zoomInButton = static_cast<QToolButton *>(toolbar->widgetForAction(action: zoomInAction));
287 QToolButton *zoomOutButton = static_cast<QToolButton *>(toolbar->widgetForAction(action: zoomOutAction));
288 zoomInButton->setAutoRepeat(true);
289 zoomInButton->setAutoRepeatInterval(200);
290 zoomInButton->setAutoRepeatDelay(200);
291 zoomOutButton->setAutoRepeat(true);
292 zoomOutButton->setAutoRepeatInterval(200);
293 zoomOutButton->setAutoRepeatDelay(200);
294 QObject::connect(sender: zoomInButton, SIGNAL(clicked()), receiver: q, SLOT(_q_zoomIn()));
295 QObject::connect(sender: zoomOutButton, SIGNAL(clicked()), receiver: q, SLOT(_q_zoomOut()));
296
297 mw->addToolBar(toolbar);
298 mw->setCentralWidget(preview);
299 // QMainWindows are always created as top levels, force it to be a
300 // plain widget
301 mw->setParent(parent: q, f: Qt::Widget);
302
303 QVBoxLayout *topLayout = new QVBoxLayout;
304 topLayout->addWidget(mw);
305 topLayout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
306 q->setLayout(topLayout);
307
308 QString caption = QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Print Preview");
309 if (!printer->docName().isEmpty())
310 caption += ": "_L1 + printer->docName();
311 q->setWindowTitle(caption);
312
313 if (!printer->isValid()
314#if defined(Q_OS_WIN) || defined(Q_OS_APPLE)
315 || printer->outputFormat() != QPrinter::NativeFormat
316#endif
317 )
318 pageSetupAction->setEnabled(false);
319 preview->setFocus();
320}
321
322static inline void qt_setupActionIcon(QAction *action, QLatin1StringView name)
323{
324 const auto imagePrefix = ":/qt-project.org/dialogs/qprintpreviewdialog/images/"_L1;
325 QIcon icon = QIcon::fromTheme(name);
326 icon.addFile(fileName: imagePrefix + name + "-24.png"_L1, size: QSize(24, 24));
327 icon.addFile(fileName: imagePrefix + name + "-32.png"_L1, size: QSize(32, 32));
328 action->setIcon(icon);
329}
330
331void QPrintPreviewDialogPrivate::setupActions()
332{
333 Q_Q(QPrintPreviewDialog);
334
335 // Navigation
336 navGroup = new QActionGroup(q);
337 navGroup->setExclusive(false);
338 nextPageAction = navGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Next page"));
339 prevPageAction = navGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Previous page"));
340 firstPageAction = navGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "First page"));
341 lastPageAction = navGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Last page"));
342 qt_setupActionIcon(action: nextPageAction, name: "go-next"_L1);
343 qt_setupActionIcon(action: prevPageAction, name: "go-previous"_L1);
344 qt_setupActionIcon(action: firstPageAction, name: "go-first"_L1);
345 qt_setupActionIcon(action: lastPageAction, name: "go-last"_L1);
346 QObject::connect(sender: navGroup, SIGNAL(triggered(QAction*)), receiver: q, SLOT(_q_navigate(QAction*)));
347
348
349 fitGroup = new QActionGroup(q);
350 fitWidthAction = fitGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Fit width"));
351 fitPageAction = fitGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Fit page"));
352 fitWidthAction->setObjectName("fitWidthAction"_L1);
353 fitPageAction->setObjectName("fitPageAction"_L1);
354 fitWidthAction->setCheckable(true);
355 fitPageAction->setCheckable(true);
356 qt_setupActionIcon(action: fitWidthAction, name: "zoom-fit-width"_L1);
357 qt_setupActionIcon(action: fitPageAction, name: "zoom-fit-page"_L1);
358 QObject::connect(sender: fitGroup, SIGNAL(triggered(QAction*)), receiver: q, SLOT(_q_fit(QAction*)));
359
360 // Zoom
361 zoomGroup = new QActionGroup(q);
362 zoomInAction = zoomGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Zoom in"));
363 zoomOutAction = zoomGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Zoom out"));
364 qt_setupActionIcon(action: zoomInAction, name: "zoom-in"_L1);
365 qt_setupActionIcon(action: zoomOutAction, name: "zoom-out"_L1);
366
367 // Portrait/Landscape
368 orientationGroup = new QActionGroup(q);
369 portraitAction = orientationGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Portrait"));
370 landscapeAction = orientationGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Landscape"));
371 portraitAction->setCheckable(true);
372 landscapeAction->setCheckable(true);
373 qt_setupActionIcon(action: portraitAction, name: "layout-portrait"_L1);
374 qt_setupActionIcon(action: landscapeAction, name: "layout-landscape"_L1);
375 QObject::connect(sender: portraitAction, SIGNAL(triggered(bool)), receiver: preview, SLOT(setPortraitOrientation()));
376 QObject::connect(sender: landscapeAction, SIGNAL(triggered(bool)), receiver: preview, SLOT(setLandscapeOrientation()));
377
378 // Display mode
379 modeGroup = new QActionGroup(q);
380 singleModeAction = modeGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Show single page"));
381 facingModeAction = modeGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Show facing pages"));
382 overviewModeAction = modeGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Show overview of all pages"));
383 qt_setupActionIcon(action: singleModeAction, name: "view-pages-single"_L1);
384 qt_setupActionIcon(action: facingModeAction, name: "view-pages-facing"_L1);
385 qt_setupActionIcon(action: overviewModeAction, name: "view-pages-overview"_L1);
386 singleModeAction->setObjectName("singleModeAction"_L1);
387 facingModeAction->setObjectName("facingModeAction"_L1);
388 overviewModeAction->setObjectName("overviewModeAction"_L1);
389
390 singleModeAction->setCheckable(true);
391 facingModeAction->setCheckable(true);
392 overviewModeAction->setCheckable(true);
393 QObject::connect(sender: modeGroup, SIGNAL(triggered(QAction*)), receiver: q, SLOT(_q_setMode(QAction*)));
394
395 // Print
396 printerGroup = new QActionGroup(q);
397 printAction = printerGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Print"));
398 pageSetupAction = printerGroup->addAction(text: QCoreApplication::translate(context: "QPrintPreviewDialog", key: "Page setup"));
399 qt_setupActionIcon(action: printAction, name: "printer"_L1);
400 qt_setupActionIcon(action: pageSetupAction, name: "page-setup"_L1);
401 QObject::connect(sender: printAction, SIGNAL(triggered(bool)), receiver: q, SLOT(_q_print()));
402 QObject::connect(sender: pageSetupAction, SIGNAL(triggered(bool)), receiver: q, SLOT(_q_pageSetup()));
403
404 // Initial state:
405 fitPageAction->setChecked(true);
406 singleModeAction->setChecked(true);
407 if (preview->orientation() == QPageLayout::Portrait)
408 portraitAction->setChecked(true);
409 else
410 landscapeAction->setChecked(true);
411}
412
413
414bool QPrintPreviewDialogPrivate::isFitting()
415{
416 return (fitGroup->isExclusive()
417 && (fitWidthAction->isChecked() || fitPageAction->isChecked()));
418}
419
420
421void QPrintPreviewDialogPrivate::setFitting(bool on)
422{
423 if (isFitting() == on)
424 return;
425 fitGroup->setExclusive(on);
426 if (on) {
427 QAction* action = fitWidthAction->isChecked() ? fitWidthAction : fitPageAction;
428 action->setChecked(true);
429 if (fitGroup->checkedAction() != action) {
430 // work around exclusitivity problem
431 fitGroup->removeAction(a: action);
432 fitGroup->addAction(a: action);
433 }
434 } else {
435 fitWidthAction->setChecked(false);
436 fitPageAction->setChecked(false);
437 }
438}
439
440QString QPrintPreviewDialogPrivate::formattedZoomFactor(double value)
441{
442 //: Zoom factor percentage value, % is the percent sign
443 return QPrintPreviewDialog::tr(s: "%1%").arg(a: QLocale().toString(f: value, format: 'f', precision: 1));
444}
445
446void QPrintPreviewDialogPrivate::updateNavActions()
447{
448 int curPage = preview->currentPage();
449 int numPages = preview->pageCount();
450 nextPageAction->setEnabled(curPage < numPages);
451 prevPageAction->setEnabled(curPage > 1);
452 firstPageAction->setEnabled(curPage > 1);
453 lastPageAction->setEnabled(curPage < numPages);
454 pageNumEdit->setText(QString::number(curPage));
455}
456
457void QPrintPreviewDialogPrivate::updatePageNumLabel()
458{
459 Q_Q(QPrintPreviewDialog);
460
461 int numPages = preview->pageCount();
462 int maxChars = QString::number(numPages).size();
463 pageNumLabel->setText(QString::fromLatin1(ba: "/ %1").arg(a: numPages));
464 int cyphersWidth = q->fontMetrics().horizontalAdvance(QString().fill(c: u'8', size: maxChars));
465 int maxWidth = pageNumEdit->minimumSizeHint().width() + cyphersWidth;
466 pageNumEdit->setMinimumWidth(maxWidth);
467 pageNumEdit->setMaximumWidth(maxWidth);
468 pageNumEdit->setValidator(new QIntValidator(1, numPages, pageNumEdit));
469 // any old one will be deleted later along with its parent pageNumEdit
470}
471
472void QPrintPreviewDialogPrivate::updateZoomFactor()
473{
474 zoomFactor->lineEdit()->setText(formattedZoomFactor(value: preview->zoomFactor() * 100));
475}
476
477void QPrintPreviewDialogPrivate::_q_fit(QAction* action)
478{
479 setFitting(true);
480 if (action == fitPageAction)
481 preview->fitInView();
482 else
483 preview->fitToWidth();
484}
485
486void QPrintPreviewDialogPrivate::_q_zoomIn()
487{
488 setFitting(false);
489 preview->zoomIn();
490 updateZoomFactor();
491}
492
493void QPrintPreviewDialogPrivate::_q_zoomOut()
494{
495 setFitting(false);
496 preview->zoomOut();
497 updateZoomFactor();
498}
499
500void QPrintPreviewDialogPrivate::_q_pageNumEdited()
501{
502 bool ok = false;
503 int res = pageNumEdit->text().toInt(ok: &ok);
504 if (ok)
505 preview->setCurrentPage(res);
506}
507
508void QPrintPreviewDialogPrivate::_q_navigate(QAction* action)
509{
510 int curPage = preview->currentPage();
511 if (action == prevPageAction)
512 preview->setCurrentPage(curPage - 1);
513 else if (action == nextPageAction)
514 preview->setCurrentPage(curPage + 1);
515 else if (action == firstPageAction)
516 preview->setCurrentPage(1);
517 else if (action == lastPageAction)
518 preview->setCurrentPage(preview->pageCount());
519 updateNavActions();
520}
521
522void QPrintPreviewDialogPrivate::_q_setMode(QAction* action)
523{
524 if (action == overviewModeAction) {
525 preview->setViewMode(QPrintPreviewWidget::AllPagesView);
526 setFitting(false);
527 fitGroup->setEnabled(false);
528 navGroup->setEnabled(false);
529 pageNumEdit->setEnabled(false);
530 pageNumLabel->setEnabled(false);
531 } else if (action == facingModeAction) {
532 preview->setViewMode(QPrintPreviewWidget::FacingPagesView);
533 } else {
534 preview->setViewMode(QPrintPreviewWidget::SinglePageView);
535 }
536 if (action == facingModeAction || action == singleModeAction) {
537 fitGroup->setEnabled(true);
538 navGroup->setEnabled(true);
539 pageNumEdit->setEnabled(true);
540 pageNumLabel->setEnabled(true);
541 setFitting(true);
542 }
543}
544
545void QPrintPreviewDialogPrivate::_q_print()
546{
547 Q_Q(QPrintPreviewDialog);
548
549#if defined(Q_OS_WIN) || defined(Q_OS_APPLE)
550 if (printer->outputFormat() != QPrinter::NativeFormat) {
551 QString title = QCoreApplication::translate("QPrintPreviewDialog", "Export to PDF");
552 QString suffix = ".pdf"_L1;
553 QString fileName;
554#if QT_CONFIG(filedialog)
555 fileName = QFileDialog::getSaveFileName(q, title, printer->outputFileName(), u'*' + suffix);
556#endif
557 if (!fileName.isEmpty()) {
558 if (QFileInfo(fileName).suffix().isEmpty())
559 fileName.append(suffix);
560 printer->setOutputFileName(fileName);
561 }
562 if (!printer->outputFileName().isEmpty())
563 preview->print();
564 q->accept();
565 return;
566 }
567#endif
568
569 if (!printDialog)
570 printDialog = new QPrintDialog(printer, q);
571 if (printDialog->exec() == QDialog::Accepted) {
572 preview->print();
573 q->accept();
574 }
575}
576
577void QPrintPreviewDialogPrivate::_q_pageSetup()
578{
579 Q_Q(QPrintPreviewDialog);
580
581 if (!pageSetupDialog)
582 pageSetupDialog = new QPageSetupDialog(printer, q);
583
584 if (pageSetupDialog->exec() == QDialog::Accepted) {
585 // update possible orientation changes
586 if (preview->orientation() == QPageLayout::Portrait) {
587 portraitAction->setChecked(true);
588 preview->setPortraitOrientation();
589 }else {
590 landscapeAction->setChecked(true);
591 preview->setLandscapeOrientation();
592 }
593 }
594}
595
596void QPrintPreviewDialogPrivate::_q_previewChanged()
597{
598 updateNavActions();
599 updatePageNumLabel();
600 updateZoomFactor();
601}
602
603void QPrintPreviewDialogPrivate::_q_zoomFactorChanged()
604{
605 QString text = zoomFactor->lineEdit()->text();
606 bool ok;
607 qreal factor = text.remove(c: u'%').toFloat(ok: &ok);
608 factor = qMax(a: qreal(1.0), b: qMin(a: qreal(1000.0), b: factor));
609 if (ok) {
610 preview->setZoomFactor(factor/100.0);
611 zoomFactor->setEditText(formattedZoomFactor(value: factor));
612 setFitting(false);
613 }
614}
615
616///////////////////////////////////////////////////////////////////////////
617
618/*!
619 \class QPrintPreviewDialog
620 \since 4.4
621
622 \brief The QPrintPreviewDialog class provides a dialog for
623 previewing and configuring page layouts for printer output.
624
625 \ingroup standard-dialogs
626 \ingroup printing
627 \inmodule QtPrintSupport
628
629 Using QPrintPreviewDialog in your existing application is
630 straightforward:
631
632 \list 1
633 \li Create the QPrintPreviewDialog.
634
635 You can construct a QPrintPreviewDialog with an existing QPrinter
636 object, or you can have QPrintPreviewDialog create one for you,
637 which will be the system default printer.
638
639 \li Connect the paintRequested() signal to a slot.
640
641 When the dialog needs to generate a set of preview pages, the
642 paintRequested() signal will be emitted. You can use the exact
643 same code for the actual printing as for having the preview
644 generated, including calling QPrinter::newPage() to start a new
645 page in the preview. Connect a slot to the paintRequested()
646 signal, where you draw onto the QPrinter object that is passed
647 into the slot.
648
649 \li Call exec().
650
651 Call QPrintPreviewDialog::exec() to show the preview dialog.
652 \endlist
653
654 \sa QPrinter, QPrintDialog, QPageSetupDialog, QPrintPreviewWidget
655*/
656
657/*!
658 Constructs a QPrintPreviewDialog based on \a printer and with \a
659 parent as the parent widget. The widget flags \a flags are passed on
660 to the QWidget constructor.
661
662 \sa QWidget::setWindowFlags()
663*/
664QPrintPreviewDialog::QPrintPreviewDialog(QPrinter* printer, QWidget *parent, Qt::WindowFlags flags)
665 : QDialog(*new QPrintPreviewDialogPrivate, parent, flags)
666{
667 Q_D(QPrintPreviewDialog);
668 d->init(printer: printer);
669}
670
671/*!
672 \overload
673 \fn QPrintPreviewDialog::QPrintPreviewDialog(QWidget *parent, Qt::WindowFlags flags)
674
675 This will create an internal QPrinter object, which will use the
676 system default printer.
677*/
678QPrintPreviewDialog::QPrintPreviewDialog(QWidget *parent, Qt::WindowFlags f)
679 : QDialog(*new QPrintPreviewDialogPrivate, parent, f)
680{
681 Q_D(QPrintPreviewDialog);
682 d->init();
683}
684
685/*!
686 Destroys the QPrintPreviewDialog.
687*/
688QPrintPreviewDialog::~QPrintPreviewDialog()
689{
690 Q_D(QPrintPreviewDialog);
691 if (d->ownPrinter)
692 delete d->printer;
693 delete d->printDialog;
694 delete d->pageSetupDialog;
695}
696
697/*!
698 \reimp
699*/
700void QPrintPreviewDialog::setVisible(bool visible)
701{
702 Q_D(QPrintPreviewDialog);
703 // this will make the dialog get a decent default size
704 if (visible && !d->initialized) {
705 d->preview->updatePreview();
706 d->initialized = true;
707 }
708 QDialog::setVisible(visible);
709}
710
711/*!
712 \reimp
713*/
714void QPrintPreviewDialog::done(int result)
715{
716 Q_D(QPrintPreviewDialog);
717 QDialog::done(result);
718 if (d->receiverToDisconnectOnClose) {
719 disconnect(sender: this, SIGNAL(finished(int)),
720 receiver: d->receiverToDisconnectOnClose, member: d->memberToDisconnectOnClose);
721 d->receiverToDisconnectOnClose = nullptr;
722 }
723 d->memberToDisconnectOnClose.clear();
724}
725
726/*!
727 \overload
728 \since 4.5
729
730 Opens the dialog and connects its finished(int) signal to the slot specified
731 by \a receiver and \a member.
732
733 The signal will be disconnected from the slot when the dialog is closed.
734*/
735void QPrintPreviewDialog::open(QObject *receiver, const char *member)
736{
737 Q_D(QPrintPreviewDialog);
738 // the int parameter isn't very useful here; we could just as well connect
739 // to reject(), but this feels less robust somehow
740 connect(sender: this, SIGNAL(finished(int)), receiver, member);
741 d->receiverToDisconnectOnClose = receiver;
742 d->memberToDisconnectOnClose = member;
743 QDialog::open();
744}
745
746/*!
747 Returns a pointer to the QPrinter object this dialog is currently
748 operating on.
749*/
750QPrinter *QPrintPreviewDialog::printer()
751{
752 Q_D(QPrintPreviewDialog);
753 return d->printer;
754}
755
756/*!
757 \fn void QPrintPreviewDialog::paintRequested(QPrinter *printer)
758
759 This signal is emitted when the QPrintPreviewDialog needs to generate
760 a set of preview pages.
761
762 The \a printer instance supplied is the paint device onto which you should
763 paint the contents of each page, using the QPrinter instance in the same way
764 as you would when printing directly.
765*/
766
767
768QT_END_NAMESPACE
769
770#include "moc_qprintpreviewdialog.cpp"
771#include "qprintpreviewdialog.moc"
772

source code of qtbase/src/printsupport/dialogs/qprintpreviewdialog.cpp