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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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