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

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