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

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