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 | |
33 | static void _q_ppd_initResources() |
34 | { |
35 | static bool resourcesInitialized = false; |
36 | if (!resourcesInitialized) { |
37 | Q_INIT_RESOURCE(qprintdialog); |
38 | resourcesInitialized = true; |
39 | } |
40 | } |
41 | |
42 | QT_BEGIN_NAMESPACE |
43 | |
44 | using namespace Qt::StringLiterals; |
45 | |
46 | namespace { |
47 | class QPrintPreviewMainWindow : public QMainWindow |
48 | { |
49 | public: |
50 | QPrintPreviewMainWindow(QWidget *parent) : QMainWindow(parent) {} |
51 | QMenu *createPopupMenu() override { return nullptr; } |
52 | }; |
53 | |
54 | class ZoomFactorValidator : public QDoubleValidator |
55 | { |
56 | public: |
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 | |
83 | class LineEdit : public QLineEdit |
84 | { |
85 | Q_OBJECT |
86 | public: |
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 | |
94 | protected: |
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 | |
108 | private slots: |
109 | void handleReturnPressed() |
110 | { |
111 | origText = text(); |
112 | } |
113 | |
114 | private: |
115 | QString origText; |
116 | }; |
117 | } // anonymous namespace |
118 | |
119 | class QPrintPreviewDialogPrivate : public QDialogPrivate |
120 | { |
121 | Q_DECLARE_PUBLIC(QPrintPreviewDialog) |
122 | public: |
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 | |
193 | void 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 | |
321 | static 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 | |
330 | void 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 | |
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 | |
413 | bool QPrintPreviewDialogPrivate::isFitting() |
414 | { |
415 | return (fitGroup->isExclusive() |
416 | && (fitWidthAction->isChecked() || fitPageAction->isChecked())); |
417 | } |
418 | |
419 | |
420 | void 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 | |
439 | void 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 | |
450 | void 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 | |
465 | void QPrintPreviewDialogPrivate::updateZoomFactor() |
466 | { |
467 | zoomFactor->lineEdit()->setText(QString::asprintf(format: "%.1f%%", preview->zoomFactor()*100)); |
468 | } |
469 | |
470 | void QPrintPreviewDialogPrivate::_q_fit(QAction* action) |
471 | { |
472 | setFitting(true); |
473 | if (action == fitPageAction) |
474 | preview->fitInView(); |
475 | else |
476 | preview->fitToWidth(); |
477 | } |
478 | |
479 | void QPrintPreviewDialogPrivate::_q_zoomIn() |
480 | { |
481 | setFitting(false); |
482 | preview->zoomIn(); |
483 | updateZoomFactor(); |
484 | } |
485 | |
486 | void QPrintPreviewDialogPrivate::_q_zoomOut() |
487 | { |
488 | setFitting(false); |
489 | preview->zoomOut(); |
490 | updateZoomFactor(); |
491 | } |
492 | |
493 | void 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 | |
501 | void 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 | |
515 | void 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 | |
538 | void 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 | |
570 | void 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 | |
589 | void QPrintPreviewDialogPrivate::_q_previewChanged() |
590 | { |
591 | updateNavActions(); |
592 | updatePageNumLabel(); |
593 | updateZoomFactor(); |
594 | } |
595 | |
596 | void 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 | */ |
657 | QPrintPreviewDialog::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 | */ |
671 | QPrintPreviewDialog::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 | */ |
681 | QPrintPreviewDialog::~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 | */ |
693 | void 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 | */ |
707 | void 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 | */ |
728 | void 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 | */ |
743 | QPrinter *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 | |
761 | QT_END_NAMESPACE |
762 | |
763 | #include "moc_qprintpreviewdialog.cpp" |
764 | #include "qprintpreviewdialog.moc" |
765 |
Definitions
- _q_ppd_initResources
- QPrintPreviewMainWindow
- QPrintPreviewMainWindow
- createPopupMenu
- ZoomFactorValidator
- ZoomFactorValidator
- ZoomFactorValidator
- validate
- LineEdit
- LineEdit
- focusInEvent
- focusOutEvent
- handleReturnPressed
- QPrintPreviewDialogPrivate
- QPrintPreviewDialogPrivate
- init
- qt_setupActionIcon
- setupActions
- isFitting
- setFitting
- updateNavActions
- updatePageNumLabel
- updateZoomFactor
- _q_fit
- _q_zoomIn
- _q_zoomOut
- _q_pageNumEdited
- _q_navigate
- _q_setMode
- _q_print
- _q_pageSetup
- _q_previewChanged
- _q_zoomFactorChanged
- QPrintPreviewDialog
- QPrintPreviewDialog
- ~QPrintPreviewDialog
- setVisible
- done
- open
Learn to use CMake with our Intro Training
Find out more