Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qprintdialog_unix.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
5#include "qplatformdefs.h"
6#include <QtPrintSupport/private/qtprintsupportglobal_p.h>
7
8#include "private/qabstractprintdialog_p.h"
9#if QT_CONFIG(messagebox)
10#include <QtWidgets/qmessagebox.h>
11#endif
12#include "qprintdialog.h"
13#if QT_CONFIG(filedialog)
14#include "qfiledialog.h"
15#endif
16#include <QtCore/qdebug.h>
17#include <QtCore/qdir.h>
18#include <QtCore/qglobal.h>
19#include <QtCore/qstringconverter.h>
20#include <QtGui/qevent.h>
21#if QT_CONFIG(filesystemmodel)
22#include <QtGui/qfilesystemmodel.h>
23#endif
24#include <QtWidgets/qstyleditemdelegate.h>
25#include <QtWidgets/qformlayout.h>
26#include <QtPrintSupport/qprinter.h>
27
28#include <qpa/qplatformprintplugin.h>
29#include <qpa/qplatformprintersupport.h>
30
31#include <private/qprintdevice_p.h>
32
33#include <QtWidgets/qdialogbuttonbox.h>
34
35#if QT_CONFIG(regularexpression)
36#include <qregularexpression.h>
37#endif
38
39#if QT_CONFIG(completer)
40#include <private/qcompleter_p.h>
41#endif
42#include "ui_qprintpropertieswidget.h"
43#include "ui_qprintsettingsoutput.h"
44#include "ui_qprintwidget.h"
45
46#if QT_CONFIG(cups)
48#include <private/qcups_p.h>
49#if QT_CONFIG(cupsjobwidget)
50#include "qcupsjobwidget_p.h"
51#endif
52#endif
53
54/*
55
56Print dialog class declarations
57
58 QPrintDialog: The main Print Dialog, nothing really held here.
59
60 QUnixPrintWidget:
61 QUnixPrintWidgetPrivate: The real Unix Print Dialog implementation.
62
63 Directly includes the upper half of the Print Dialog
64 containing the Printer Selection widgets and
65 Properties button.
66
67 Embeds the Properties pop-up dialog from
68 QPrintPropertiesDialog
69
70 Embeds the lower half from separate widget class
71 QPrintDialogPrivate
72
73 Layout in qprintwidget.ui
74
75 QPrintDialogPrivate: The lower half of the Print Dialog containing the
76 Copies and Options tabs that expands when the
77 Options button is selected.
78
79 Layout in qprintsettingsoutput.ui
80
81 QPrintPropertiesDialog: Dialog displayed when clicking on Properties button to
82 allow editing of Page and Advanced tabs.
83
84 Layout in qprintpropertieswidget.ui
85*/
86
88{
89 Q_INIT_RESOURCE(qprintdialog);
90}
91
92QT_BEGIN_NAMESPACE
93
94using namespace Qt::StringLiterals;
95
97{
99public:
104
105 void setupPrinter() const;
106
107private slots:
110
111private:
112 void showEvent(QShowEvent *event) override;
113
115#if QT_CONFIG(cups)
117#endif
118 Ui::QPrintPropertiesWidget widget;
119 QDialogButtonBox *m_buttons;
120#if QT_CONFIG(cupsjobwidget)
122#endif
123
124#if QT_CONFIG(cups)
129 bool anyPpdOptionConflict() const;
130 bool anyAdvancedOptionConflict() const;
131
133
136#endif
137};
138
140
142{
144
145public:
149
150private:
151 friend class QPrintDialog;
155 Q_PRIVATE_SLOT(d, void _q_printerChanged(int))
158};
159
193
195{
196 Q_DECLARE_PUBLIC(QPrintDialog)
198public:
201
202 void init();
203
204 void selectPrinter(const QPrinter::OutputFormat outputFormat);
205
207#if QT_CONFIG(messagebox)
208 void _q_checkFields();
209#endif
211
212#if QT_CONFIG(cups)
214#endif
217
218 virtual void setTabs(const QList<QWidget*> &tabs) override;
219
224 QPushButton *collapseButton;
226private:
227 void setExplicitDuplexMode(QPrint::DuplexMode duplexMode);
228 // duplex mode explicitly set by user, QPrint::DuplexAuto otherwise
229 QPrint::DuplexMode explicitDuplexMode;
230};
231
232////////////////////////////////////////////////////////////////////////////////
233////////////////////////////////////////////////////////////////////////////////
234
235/*
236
237 QPrintPropertiesDialog
238
239 Dialog displayed when clicking on Properties button to allow editing of Page
240 and Advanced tabs.
241
242*/
243
244QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrintDevice *currentPrintDevice,
245 QPrinter::OutputFormat outputFormat, const QString &printerName,
246 QAbstractPrintDialog *parent)
247 : QDialog(parent)
248#if QT_CONFIG(cups)
249 , m_printer(printer)
250#endif
251{
252 setWindowTitle(tr("Printer Properties"));
253 QVBoxLayout *lay = new QVBoxLayout(this);
254 QWidget *content = new QWidget(this);
255 widget.setupUi(content);
256 m_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
257 lay->addWidget(content);
258 lay->addWidget(m_buttons);
259
260 connect(m_buttons->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &QPrintPropertiesDialog::accept);
261 connect(m_buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &QPrintPropertiesDialog::reject);
262
263 widget.pageSetup->setPrinter(printer, currentPrintDevice, outputFormat, printerName);
264
265#if QT_CONFIG(cupsjobwidget)
266 m_jobOptions = new QCupsJobWidget(printer, currentPrintDevice);
267 widget.tabs->insertTab(1, m_jobOptions, tr("Job Options"));
268#endif
269
270 const int advancedTabIndex = widget.tabs->indexOf(widget.cupsPropertiesPage);
271#if QT_CONFIG(cups)
272 m_currentPrintDevice = currentPrintDevice;
273 const bool anyWidgetCreated = createAdvancedOptionsWidget();
274
275 widget.tabs->setTabEnabled(advancedTabIndex, anyWidgetCreated);
276
277 connect(widget.pageSetup, &QPageSetupWidget::ppdOptionChanged, this, [this] {
278 widget.conflictsLabel->setVisible(anyPpdOptionConflict());
279 });
280
281#else
282 Q_UNUSED(currentPrintDevice);
283 widget.tabs->setTabEnabled(advancedTabIndex, false);
284#endif
285}
286
290
292{
293#if QT_CONFIG(cups)
294 QCUPSSupport::clearCupsOptions(m_printer);
295#endif
296
297 widget.pageSetup->setupPrinter();
298#if QT_CONFIG(cupsjobwidget)
299 m_jobOptions->setupPrinter();
300#endif
301
302#if QT_CONFIG(cups)
303 // Set Color by default, that will change if the "ColorModel" property is available
304 m_printer->setColorMode(QPrinter::Color);
305
306 setPrinterAdvancedCupsOptions();
307#endif
308}
309
311{
312 widget.pageSetup->revertToSavedValues();
313
314#if QT_CONFIG(cupsjobwidget)
315 m_jobOptions->revertToSavedValues();
316#endif
317
318#if QT_CONFIG(cups)
319 revertAdvancedOptionsToSavedValues();
320#endif
321 QDialog::reject();
322}
323
325{
326#if QT_CONFIG(cups) && QT_CONFIG(messagebox)
327 if (widget.pageSetup->hasPpdConflict()) {
328 widget.tabs->setCurrentWidget(widget.tabPage);
329 const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Page Setup Conflicts"),
330 tr("There are conflicts in page setup options. Do you want to fix them?"),
331 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
332 if (answer != QMessageBox::No)
333 return;
334 } else if (anyAdvancedOptionConflict()) {
335 widget.tabs->setCurrentWidget(widget.cupsPropertiesPage);
336 const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Advanced Option Conflicts"),
337 tr("There are conflicts in some advanced options. Do you want to fix them?"),
338 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
339 if (answer != QMessageBox::No)
340 return;
341 }
342 advancedOptionsUpdateSavedValues();
343#endif
344
345#if QT_CONFIG(cupsjobwidget)
346 m_jobOptions->updateSavedValues();
347#endif
348
349 widget.pageSetup->updateSavedValues();
350
351 QDialog::accept();
352}
353
354void QPrintPropertiesDialog::showEvent(QShowEvent *event)
355{
356#if QT_CONFIG(cups)
357 widget.conflictsLabel->setVisible(anyPpdOptionConflict());
358#endif
359 QDialog::showEvent(event);
360}
361
362#if QT_CONFIG(cups)
363
364// Used to store the ppd_option_t for each QComboBox that represents an advanced option
365static const char *ppdOptionProperty = "_q_ppd_option";
366
367// Used to store the originally selected choice index for each QComboBox that represents an advanced option
368static const char *ppdOriginallySelectedChoiceProperty = "_q_ppd_originally_selected_choice";
369
370// Used to store the QLineEdit pointer for each advanced option that supports custom values
371static const char *customValueLineEditProperty = "_q_custom_value_lineedit";
372
373// Used to store the warning label pointer for each QComboBox that represents an advanced option
374static const char *warningLabelProperty = "_q_warning_label";
375
376static bool isBlacklistedGroup(const ppd_group_t *group) noexcept
377{
378 return qstrcmp(group->name, "InstallableOptions") == 0;
379};
380
381static bool isBlacklistedOption(const char *keyword) noexcept
382{
383 // We already let the user set these options elsewhere
384 const char *cupsOptionBlacklist[] = {
385 "Collate",
386 "Copies",
387 "OutputOrder",
388 "PageRegion",
389 "PageSize",
390 "Duplex" // handled by the main dialog
391 };
392 auto equals = [](const char *keyword) {
393 return [keyword](const char *candidate) {
394 return qstrcmp(keyword, candidate) == 0;
395 };
396 };
397 return std::any_of(std::begin(cupsOptionBlacklist), std::end(cupsOptionBlacklist), equals(keyword));
398};
399
400bool QPrintPropertiesDialog::createAdvancedOptionsWidget()
401{
402 bool anyWidgetCreated = false;
403
404 ppd_file_t *ppd = qvariant_cast<ppd_file_t*>(m_currentPrintDevice->property(PDPK_PpdFile));
405
406 if (ppd) {
407 toUnicode = QStringDecoder(ppd->lang_encoding, QStringDecoder::Flag::Stateless);
408 if (!toUnicode.isValid()) {
409 qWarning() << "QPrinSupport: Cups uses unsupported encoding" << ppd->lang_encoding;
410 toUnicode = QStringDecoder(QStringDecoder::Utf8, QStringDecoder::Flag::Stateless);
411 }
412
413 QWidget *holdingWidget = new QWidget();
414 QVBoxLayout *layout = new QVBoxLayout(holdingWidget);
415
416 for (int i = 0; i < ppd->num_groups; ++i) {
417 const ppd_group_t *group = &ppd->groups[i];
418
419 if (!isBlacklistedGroup(group)) {
420 QFormLayout *groupLayout = new QFormLayout();
421
422 for (int i = 0; i < group->num_options; ++i) {
423 const ppd_option_t *option = &group->options[i];
424
425 if (!isBlacklistedOption(option->keyword)) {
426 QComboBox *choicesCb = new QComboBox();
427
428 const auto setPpdOptionFromCombo = [this, choicesCb, option] {
429 // We can't use choicesCb->currentIndex() to know the index of the option in the choices[] array
430 // because some of them may not be present in the list because they conflict with the
431 // installable options so use the index passed on addItem
432 const int selectedChoiceIndex = choicesCb->currentData().toInt();
433 const QString &choice = QString::fromLatin1(
434 option->choices[selectedChoiceIndex].choice);
435 const QStringList &values { QString::fromLatin1(option->keyword), choice };
436 m_currentPrintDevice->setProperty(PDPK_PpdOption, values);
437 widget.conflictsLabel->setVisible(anyPpdOptionConflict());
438
439 if (auto *customValueEdit = qvariant_cast<QLineEdit *>(
440 choicesCb->property(customValueLineEditProperty))) {
441 const bool customSelected = choice == u"Custom";
442 customValueEdit->setVisible(customSelected);
443 if (customSelected) {
444 const QStringList params{ QString::fromLatin1(
445 option->keyword) };
446 QString value =
447 m_currentPrintDevice->property(PDPK_OptionValue, params)
448 .toString();
449 if (value.startsWith(u"Custom."))
450 customValueEdit->setText(value.mid(7));
451 }
452 }
453 };
454
455 bool foundMarkedChoice = false;
456 bool markedChoiceNotAvailable = false;
457 for (int i = 0; i < option->num_choices; ++i) {
458 const ppd_choice_t *choice = &option->choices[i];
459 const auto values = QStringList{} << QString::fromLatin1(option->keyword) << QString::fromLatin1(choice->choice);
460 const bool choiceIsInstallableConflict = m_currentPrintDevice->isFeatureAvailable(PDPK_PpdChoiceIsInstallableConflict, values);
461 if (choiceIsInstallableConflict && static_cast<int>(choice->marked) == 1) {
462 markedChoiceNotAvailable = true;
463 } else if (!choiceIsInstallableConflict) {
464 choicesCb->addItem(toUnicode(choice->text), i);
465 if (static_cast<int>(choice->marked) == 1) {
466 choicesCb->setCurrentIndex(choicesCb->count() - 1);
467 choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, QVariant(i));
468 foundMarkedChoice = true;
469 } else if (!foundMarkedChoice && qstrcmp(choice->choice, option->defchoice) == 0) {
470 choicesCb->setCurrentIndex(choicesCb->count() - 1);
471 choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, QVariant(i));
472 }
473 }
474 }
475
476 if (markedChoiceNotAvailable) {
477 // If the user default option is not available because of it conflicting with
478 // the installed options, we need to set the internal ppd value to the value
479 // being shown in the combo
480 setPpdOptionFromCombo();
481 }
482
483 if (choicesCb->count() > 1) {
484
485 connect(choicesCb, &QComboBox::currentIndexChanged, this, setPpdOptionFromCombo);
486
487 // We need an extra label at the end to show the conflict warning
488 QWidget *choicesCbWithLabel = new QWidget();
489 QHBoxLayout *choicesCbWithLabelLayout = new QHBoxLayout(choicesCbWithLabel);
490 choicesCbWithLabelLayout->setContentsMargins(0, 0, 0, 0);
491 QLabel *warningLabel = new QLabel();
492 choicesCbWithLabelLayout->addWidget(choicesCb);
493
494 const QString &optionText = toUnicode(option->text);
495 const QStringList &params{ QString::fromLatin1(option->keyword) };
496 const bool hasCustomOption = m_currentPrintDevice->isFeatureAvailable(
497 PDPK_PpdCustomOption, params);
498 if (hasCustomOption) {
499 auto *customValueEdit = new QLineEdit;
500 customValueEdit->setAccessibleName(
501 tr("Custom value for %1").arg(optionText));
502 choicesCbWithLabelLayout->addWidget(customValueEdit);
503 choicesCb->setProperty(customValueLineEditProperty,
504 QVariant::fromValue(customValueEdit));
505 // ensure line edit is shown/hidden as needed
506 setPpdOptionFromCombo();
507 }
508 choicesCbWithLabelLayout->addWidget(warningLabel);
509
510 QLabel *optionLabel = new QLabel(optionText);
511 optionLabel->setBuddy(choicesCb);
512 groupLayout->addRow(optionLabel, choicesCbWithLabel);
513 anyWidgetCreated = true;
514 choicesCb->setProperty(ppdOptionProperty, QVariant::fromValue(option));
515 choicesCb->setProperty(warningLabelProperty, QVariant::fromValue(warningLabel));
516 m_advancedOptionsCombos << choicesCb;
517 } else {
518 delete choicesCb;
519 }
520 }
521 }
522
523 if (groupLayout->rowCount() > 0) {
524 QGroupBox *groupBox = new QGroupBox(toUnicode(group->text));
525 groupBox->setLayout(groupLayout);
526 layout->addWidget(groupBox);
527 } else {
528 delete groupLayout;
529 }
530 }
531 }
532
533 layout->addStretch();
534 widget.scrollArea->setWidget(holdingWidget);
535 }
536
537 return anyWidgetCreated;
538}
539
540void QPrintPropertiesDialog::setPrinterAdvancedCupsOptions() const
541{
542 for (const QComboBox *choicesCb : m_advancedOptionsCombos) {
543 const ppd_option_t *option = qvariant_cast<const ppd_option_t *>(choicesCb->property(ppdOptionProperty));
544
545 // We can't use choicesCb->currentIndex() to know the index of the option in the choices[] array
546 // because some of them may not be present in the list because they conflict with the
547 // installable options so use the index passed on addItem
548 const int selectedChoiceIndex = choicesCb->currentData().toInt();
549 QString selectedChoice = QString::fromLatin1(option->choices[selectedChoiceIndex].choice);
550
551 if (selectedChoice == u"Custom") {
552 if (auto *customValueEdit = qvariant_cast<QLineEdit *>(
553 choicesCb->property(customValueLineEditProperty))) {
554 const QString &customValue = customValueEdit->text();
555 if (!customValue.isEmpty())
556 selectedChoice = u"Custom." + customValue;
557 }
558 }
559
560 if (qstrcmp(option->keyword, "ColorModel") == 0)
561 m_printer->setColorMode(selectedChoice == u"Gray" ? QPrinter::GrayScale
562 : QPrinter::Color);
563
564 if (qstrcmp(option->defchoice, selectedChoice.toLatin1().constData()) != 0)
565 QCUPSSupport::setCupsOption(m_printer, QString::fromLatin1(option->keyword),
566 selectedChoice);
567 }
568}
569
570void QPrintPropertiesDialog::revertAdvancedOptionsToSavedValues() const
571{
572 for (QComboBox *choicesCb : m_advancedOptionsCombos) {
573 const int originallySelectedChoice = qvariant_cast<int>(choicesCb->property(ppdOriginallySelectedChoiceProperty));
574 const int newComboIndexToSelect = choicesCb->findData(originallySelectedChoice);
575 choicesCb->setCurrentIndex(newComboIndexToSelect);
576 // The currentIndexChanged lambda takes care of resetting the ppd option
577 }
578 widget.conflictsLabel->setVisible(anyPpdOptionConflict());
579}
580
581void QPrintPropertiesDialog::advancedOptionsUpdateSavedValues() const
582{
583 for (QComboBox *choicesCb : m_advancedOptionsCombos)
584 choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, choicesCb->currentData());
585}
586
587bool QPrintPropertiesDialog::anyPpdOptionConflict() const
588{
589 // we need to execute both since besides returning true/false they update the warning icons
590 const bool pageSetupConflicts = widget.pageSetup->hasPpdConflict();
591 const bool advancedOptionConflicts = anyAdvancedOptionConflict();
592 return pageSetupConflicts || advancedOptionConflicts;
593}
594
595bool QPrintPropertiesDialog::anyAdvancedOptionConflict() const
596{
597 const QIcon warning = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr);
598
599 bool anyConflicted = false;
600
601 for (const QComboBox *choicesCb : m_advancedOptionsCombos) {
602 const ppd_option_t *option = qvariant_cast<const ppd_option_t *>(choicesCb->property(ppdOptionProperty));
603 QLabel *warningLabel = qvariant_cast<QLabel *>(choicesCb->property(warningLabelProperty));
604 if (option->conflicted) {
605 anyConflicted = true;
606 const int pixmap_size = choicesCb->sizeHint().height() * .75;
607 warningLabel->setPixmap(warning.pixmap(pixmap_size, pixmap_size));
608 } else {
609 warningLabel->setPixmap(QPixmap());
610 }
611 }
612
613 return anyConflicted;
614}
615
616#endif
617
618
619////////////////////////////////////////////////////////////////////////////////
620////////////////////////////////////////////////////////////////////////////////
621
622/*
623
624 QPrintDialogPrivate
625
626 The lower half of the Print Dialog containing the Copies and Options
627 tabs that expands when the Options button is selected.
628
629*/
630QPrintDialogPrivate::QPrintDialogPrivate()
631 : top(nullptr), bottom(nullptr), buttons(nullptr), collapseButton(nullptr),
632 explicitDuplexMode(QPrint::DuplexAuto)
633{
635}
636
640
642{
643 Q_Q(QPrintDialog);
644
645 top = new QUnixPrintWidget(q->printer(), q);
646 bottom = new QWidget(q);
647 options.setupUi(bottom);
648 options.color->setIconSize(QSize(32, 32));
649 options.color->setIcon(QIcon(":/qt-project.org/dialogs/qprintdialog/images/status-color.png"_L1));
650 options.grayscale->setIconSize(QSize(32, 32));
651 options.grayscale->setIcon(QIcon(":/qt-project.org/dialogs/qprintdialog/images/status-gray-scale.png"_L1));
652
653#if QT_CONFIG(cups)
654 // Add Page Set widget if CUPS is available
655 options.pageSetCombo->addItem(tr("All Pages"), QVariant::fromValue(QCUPSSupport::AllPages));
656 options.pageSetCombo->addItem(tr("Odd Pages"), QVariant::fromValue(QCUPSSupport::OddPages));
657 options.pageSetCombo->addItem(tr("Even Pages"), QVariant::fromValue(QCUPSSupport::EvenPages));
658#else
659 delete options.pagesRadioButton;
660 delete options.pagesLineEdit;
661 options.pagesRadioButton = nullptr;
662 options.pagesLineEdit = nullptr;
663#endif
664
666
667 buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, q);
668 collapseButton = new QPushButton(QPrintDialog::tr("&Options >>"), buttons);
669 buttons->addButton(collapseButton, QDialogButtonBox::ResetRole);
670 bottom->setVisible(false);
671
672 QPushButton *printButton = buttons->button(QDialogButtonBox::Ok);
673 printButton->setText(QPrintDialog::tr("&Print"));
674 printButton->setDefault(true);
675
676 QVBoxLayout *lay = new QVBoxLayout(q);
677 lay->addWidget(top);
678 lay->addWidget(bottom);
679 lay->addWidget(buttons);
680
681#if !QT_CONFIG(messagebox)
682 QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(accept()));
683#else
684 QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(_q_checkFields()));
685#endif
686 QObject::connect(buttons, SIGNAL(rejected()), q, SLOT(reject()));
687
688 QObject::connect(options.printSelection, SIGNAL(toggled(bool)),
689 q, SLOT(_q_togglePageSetCombo(bool)));
690
691 QObject::connect(options.printCurrentPage, SIGNAL(toggled(bool)),
692 q, SLOT(_q_togglePageSetCombo(bool)));
693
694 QObject::connect(collapseButton, SIGNAL(released()), q, SLOT(_q_collapseOrExpandDialog()));
695
696 QObject::connect(options.noDuplex, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexNone); });
697 QObject::connect(options.duplexLong, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexLongSide); });
698 QObject::connect(options.duplexShort, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexShortSide); });
699
700#if QT_CONFIG(cups)
701 QObject::connect(options.noDuplex, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.noDuplex); });
702 QObject::connect(options.duplexLong, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexLong); });
703 QObject::connect(options.duplexShort, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexShort); });
704#endif
705}
706
707// initialize printer options
708void QPrintDialogPrivate::selectPrinter(const QPrinter::OutputFormat outputFormat)
709{
710 Q_Q(QPrintDialog);
711 QPrinter *p = q->printer();
712 printerOutputFormat = outputFormat;
713
714 // printer supports duplex mode?
715 const auto supportedDuplexMode = top->d->m_currentPrintDevice.supportedDuplexModes();
716 options.duplexLong->setEnabled(supportedDuplexMode.contains(QPrint::DuplexLongSide));
717 options.duplexShort->setEnabled(supportedDuplexMode.contains(QPrint::DuplexShortSide));
718
719 if (p->colorMode() == QPrinter::Color)
720 options.color->setChecked(true);
721 else
722 options.grayscale->setChecked(true);
723
724 // duplex priorities to be as follows:
725 // 1) a user-selected duplex value in the dialog has highest priority
726 // 2) duplex value set in the QPrinter
727 QPrint::DuplexMode duplex;
728 if (explicitDuplexMode != QPrint::DuplexAuto && supportedDuplexMode.contains(explicitDuplexMode))
729 duplex = explicitDuplexMode;
730 else
731 duplex = static_cast<QPrint::DuplexMode>(p->duplex());
732 switch (duplex) {
733 case QPrint::DuplexNone:
734 options.noDuplex->setChecked(true); break;
735 case QPrint::DuplexLongSide:
736 case QPrint::DuplexAuto:
737 options.duplexLong->setChecked(true); break;
738 case QPrint::DuplexShortSide:
739 options.duplexShort->setChecked(true); break;
740 }
741 options.copies->setValue(p->copyCount());
742 options.collate->setChecked(p->collateCopies());
743 options.reverse->setChecked(p->pageOrder() == QPrinter::LastPageFirst);
744
745 if (outputFormat == QPrinter::PdfFormat || options.printSelection->isChecked()
746 || options.printCurrentPage->isChecked())
747
748 options.pageSetCombo->setEnabled(false);
749 else
750 options.pageSetCombo->setEnabled(true);
751
752#if QT_CONFIG(cups)
753 // Disable complex page ranges widget when printing to pdf
754 // It doesn't work since it relies on cups to do the heavy lifting and cups
755 // is not used when printing to PDF
756 options.pagesRadioButton->setEnabled(outputFormat != QPrinter::PdfFormat);
757
758 // Disable color options on main dialog if not printing to file, it will be handled by CUPS advanced dialog
759 options.colorMode->setVisible(outputFormat == QPrinter::PdfFormat);
760#endif
761}
762
763#if QT_CONFIG(cups)
764
765void QPrintDialogPrivate::updatePpdDuplexOption(QRadioButton *radio)
766{
767 const bool checked = radio->isChecked();
768 if (checked) {
769 if (radio == options.noDuplex) top->d->setPpdDuplex(QPrinter::DuplexNone);
770 else if (radio == options.duplexLong) top->d->setPpdDuplex(QPrinter::DuplexLongSide);
771 else if (radio == options.duplexShort) top->d->setPpdDuplex(QPrinter::DuplexShortSide);
772 }
773 const bool conflict = checked && top->d->m_duplexPpdOption && top->d->m_duplexPpdOption->conflicted;
774 radio->setIcon(conflict ? QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr) : QIcon());
775}
776
777#endif
778
779void QPrintDialogPrivate::setExplicitDuplexMode(const QPrint::DuplexMode duplexMode)
780{
781 explicitDuplexMode = duplexMode;
782}
783
785{
786 // First setup the requested OutputFormat, Printer and Page Size first
788
789 // Then setup Print Job options
790 Q_Q(QPrintDialog);
791 QPrinter* p = q->printer();
792
793 if (options.duplex->isEnabled()) {
794 if (options.noDuplex->isChecked())
795 p->setDuplex(QPrinter::DuplexNone);
796 else if (options.duplexLong->isChecked())
797 p->setDuplex(QPrinter::DuplexLongSide);
798 else
799 p->setDuplex(QPrinter::DuplexShortSide);
800 }
801
802#if QT_CONFIG(cups)
803 // When printing to a device the colorMode will be set by the advanced panel
804 if (p->outputFormat() == QPrinter::PdfFormat)
805#endif
806 p->setColorMode(options.color->isChecked() ? QPrinter::Color : QPrinter::GrayScale);
807
808 p->setPageOrder(options.reverse->isChecked() ? QPrinter::LastPageFirst : QPrinter::FirstPageFirst);
809
810 // print range
811 if (options.printAll->isChecked()) {
812 p->setPrintRange(QPrinter::AllPages);
813 p->setPageRanges(QPageRanges());
814 } else if (options.printSelection->isChecked()) {
815 p->setPrintRange(QPrinter::Selection);
816 p->setPageRanges(QPageRanges());
817 } else if (options.printCurrentPage->isChecked()) {
818 p->setPrintRange(QPrinter::CurrentPage);
819 p->setPageRanges(QPageRanges());
820 } else if (options.printRange->isChecked()) {
821 if (q->testOption(QPrintDialog::PrintPageRange)) {
822 p->setPrintRange(QPrinter::PageRange);
823 p->setFromTo(options.from->value(), qMax(options.from->value(), options.to->value()));
824 } else {
825 // This case happens when CUPS server-side page range is enabled
826 // Setting the range to the printer occurs below
827 p->setPrintRange(QPrinter::AllPages);
828 p->setPageRanges(QPageRanges());
829 }
830 }
831
832#if QT_CONFIG(cups)
833 if (options.pagesRadioButton->isChecked()) {
834 const QPageRanges ranges = QPageRanges::fromString(options.pagesLineEdit->text());
835 p->setPrintRange(QPrinter::AllPages);
836 p->setPageRanges(QPageRanges());
837
838 // server-side page filtering
839 QCUPSSupport::setPageRange(p, ranges.toString());
840 }
841
842 // page set
843 if (p->printRange() == QPrinter::AllPages || p->printRange() == QPrinter::PageRange) {
844 //If the application is selecting pages and the first page number is even then need to adjust the odd-even accordingly
845 QCUPSSupport::PageSet pageSet = qvariant_cast<QCUPSSupport::PageSet>(options.pageSetCombo->itemData(options.pageSetCombo->currentIndex()));
846 if (q->testOption(QPrintDialog::PrintPageRange)
847 && p->printRange() == QPrinter::PageRange
848 && (q->fromPage() % 2 == 0)) {
849
850 switch (pageSet) {
851 case QCUPSSupport::AllPages:
852 break;
853 case QCUPSSupport::OddPages:
854 QCUPSSupport::setPageSet(p, QCUPSSupport::EvenPages);
855 break;
856 case QCUPSSupport::EvenPages:
857 QCUPSSupport::setPageSet(p, QCUPSSupport::OddPages);
858 break;
859 }
860 } else if (pageSet != QCUPSSupport::AllPages) {
861 QCUPSSupport::setPageSet(p, pageSet);
862 }
863
864 // server-side page range, since we set the page range on the printer to 0-0/AllPages above,
865 // we need to take the values directly from the widget as q->fromPage() will return 0
866 if (!q->testOption(QPrintDialog::PrintPageRange) && options.printRange->isChecked())
867 QCUPSSupport::setPageRange(p, options.from->value(), qMax(options.from->value(), options.to->value()));
868 }
869#endif
870
871 // copies
872 p->setCopyCount(options.copies->value());
873 p->setCollateCopies(options.collate->isChecked());
874}
875
877{
878 if (printerOutputFormat == QPrinter::PdfFormat)
879 return;
880
881 options.pageSetCombo->setDisabled(checked);
882}
883
885{
886 int collapseHeight = 0;
887 Q_Q(QPrintDialog);
888 QWidget *widgetToHide = bottom;
889 if (widgetToHide->isVisible()) {
890 collapseButton->setText(QPrintDialog::tr("&Options >>"));
891 collapseHeight = widgetToHide->y() + widgetToHide->height() - (top->y() + top->height());
892 }
893 else
894 collapseButton->setText(QPrintDialog::tr("&Options <<"));
895 widgetToHide->setVisible(! widgetToHide->isVisible());
896 if (! widgetToHide->isVisible()) { // make it shrink
897 q->layout()->activate();
898 q->resize( QSize(q->width(), q->height() - collapseHeight) );
899 }
900}
901
902#if QT_CONFIG(messagebox)
903void QPrintDialogPrivate::_q_checkFields()
904{
905 Q_Q(QPrintDialog);
906 if (top->d->checkFields())
907 q->accept();
908}
909#endif // QT_CONFIG(messagebox)
910
911
913{
914 Q_Q(QPrintDialog);
915 options.gbPrintRange->setVisible(q->testOption(QPrintDialog::PrintPageRange) ||
916 q->testOption(QPrintDialog::PrintSelection) ||
917 q->testOption(QPrintDialog::PrintCurrentPage));
918
919 options.printRange->setEnabled(q->testOption(QPrintDialog::PrintPageRange));
920 options.printSelection->setVisible(q->testOption(QPrintDialog::PrintSelection));
921 options.printCurrentPage->setVisible(q->testOption(QPrintDialog::PrintCurrentPage));
922 options.collate->setVisible(q->testOption(QPrintDialog::PrintCollateCopies));
923
924#if QT_CONFIG(cups)
925 // Don't display Page Set if only Selection or Current Page are enabled
926 if (!q->testOption(QPrintDialog::PrintPageRange)
927 && (q->testOption(QPrintDialog::PrintSelection) || q->testOption(QPrintDialog::PrintCurrentPage))) {
928 options.pageSetCombo->setVisible(false);
929 options.pageSetLabel->setVisible(false);
930 } else {
931 options.pageSetCombo->setVisible(true);
932 options.pageSetLabel->setVisible(true);
933 }
934
935 if (!q->testOption(QPrintDialog::PrintPageRange)) {
936 // If we can do CUPS server side pages selection,
937 // display the page range widgets
938 options.gbPrintRange->setVisible(true);
939 options.printRange->setEnabled(true);
940 }
941#endif
942
943 switch (q->printRange()) {
944 case QPrintDialog::AllPages:
945 options.printAll->setChecked(true);
946 options.pageSetCombo->setEnabled(true);
947 break;
948 case QPrintDialog::Selection:
949 options.printSelection->setChecked(true);
950 options.pageSetCombo->setEnabled(false);
951 break;
952 case QPrintDialog::PageRange:
953 options.printRange->setChecked(true);
954 options.pageSetCombo->setEnabled(true);
955 break;
956 case QPrintDialog::CurrentPage:
957 if (q->testOption(QPrintDialog::PrintCurrentPage)) {
958 options.printCurrentPage->setChecked(true);
959 options.pageSetCombo->setEnabled(false);
960 }
961 break;
962 default:
963 break;
964 }
965 const int minPage = qMax(1, qMin(q->minPage() , q->maxPage()));
966 const int maxPage = qMax(1, q->maxPage() == INT_MAX ? 9999 : q->maxPage());
967
968 options.from->setMinimum(minPage);
969 options.to->setMinimum(minPage);
970 options.from->setMaximum(maxPage);
971 options.to->setMaximum(maxPage);
972
973 options.from->setValue(q->fromPage());
974 options.to->setValue(q->toPage());
976}
977
978void QPrintDialogPrivate::setTabs(const QList<QWidget*> &tabWidgets)
979{
980 QList<QWidget*>::ConstIterator iter = tabWidgets.begin();
981 while(iter != tabWidgets.constEnd()) {
982 QWidget *tab = *iter;
983 options.tabs->addTab(tab, tab->windowTitle());
984 ++iter;
985 }
986}
987
988////////////////////////////////////////////////////////////////////////////////
989////////////////////////////////////////////////////////////////////////////////
990
991/*
992
993 QPrintDialog
994
995 The main Print Dialog.
996
997*/
998
999QPrintDialog::QPrintDialog(QPrinter *printer, QWidget *parent)
1000 : QAbstractPrintDialog(*(new QPrintDialogPrivate), printer, parent)
1001{
1002 Q_D(QPrintDialog);
1003 d->init();
1004}
1005
1006/*!
1007 Constructs a print dialog with the given \a parent.
1008*/
1009QPrintDialog::QPrintDialog(QWidget *parent)
1010 : QAbstractPrintDialog(*(new QPrintDialogPrivate), nullptr, parent)
1011{
1012 Q_D(QPrintDialog);
1013 d->init();
1014}
1015
1016QPrintDialog::~QPrintDialog()
1017{
1018}
1019
1020void QPrintDialog::setVisible(bool visible)
1021{
1022 Q_D(QPrintDialog);
1023
1024 if (visible)
1025 d->updateWidgets();
1026
1027 QAbstractPrintDialog::setVisible(visible);
1028}
1029
1030int QPrintDialog::exec()
1031{
1032 return QAbstractPrintDialog::exec();
1033}
1034
1035void QPrintDialog::accept()
1036{
1037 Q_D(QPrintDialog);
1038#if QT_CONFIG(cups) && QT_CONFIG(messagebox)
1039 if (d->options.pagesRadioButton->isChecked()) {
1040 const QString rangesText = d->options.pagesLineEdit->text();
1041 if (rangesText.isEmpty() || QPageRanges::fromString(rangesText).isEmpty()) {
1042 QMessageBox::critical(this, tr("Invalid Pages Definition"),
1043 tr("%1 does not follow the correct syntax. Please use ',' to separate "
1044 "ranges and pages, '-' to define ranges and make sure ranges do "
1045 "not intersect with each other.").arg(rangesText),
1046 QMessageBox::Ok, QMessageBox::Ok);
1047 return;
1048 }
1049 }
1050 if (d->top->d->m_duplexPpdOption && d->top->d->m_duplexPpdOption->conflicted) {
1051 const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Duplex Settings Conflicts"),
1052 tr("There are conflicts in duplex settings. Do you want to fix them?"),
1053 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
1054 if (answer != QMessageBox::No)
1055 return;
1056 }
1057#endif
1058 d->setupPrinter();
1059 QDialog::accept();
1060}
1061
1062////////////////////////////////////////////////////////////////////////////////
1063////////////////////////////////////////////////////////////////////////////////
1064
1065/*
1066
1067 QUnixPrintWidget && QUnixPrintWidgetPrivate
1068
1069 The upper half of the Print Dialog containing the Printer Selection widgets
1070
1071*/
1072
1073#if defined (Q_OS_UNIX)
1074
1075/*! \internal
1076*/
1077QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p, QPrinter *prn)
1078 : parent(p), propertiesDialog(nullptr), printer(prn),
1079#if QT_CONFIG(cups)
1080 m_duplexPpdOption(nullptr),
1081#endif
1082 optionsPane(nullptr), filePrintersAdded(false)
1083{
1084 q = nullptr;
1085 if (parent)
1086 q = qobject_cast<QPrintDialog*> (parent->parent());
1087
1088 widget.setupUi(parent);
1089
1090 int currentPrinterIndex = 0;
1091 QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();
1092 if (ps) {
1093 const QStringList printers = ps->availablePrintDeviceIds();
1094 const QString defaultPrinter = ps->defaultPrintDeviceId();
1095
1096 widget.printers->addItems(printers);
1097
1098 const QString selectedPrinter = prn && !prn->printerName().isEmpty() ? prn->printerName() : defaultPrinter;
1099 const int idx = printers.indexOf(selectedPrinter);
1100
1101 if (idx >= 0)
1102 currentPrinterIndex = idx;
1103 }
1104 widget.properties->setEnabled(true);
1105
1106#if QT_CONFIG(filesystemmodel) && QT_CONFIG(completer)
1107 QFileSystemModel *fsm = new QFileSystemModel(widget.filename);
1108 fsm->setRootPath(QDir::homePath());
1109 widget.filename->setCompleter(new QCompleter(fsm, widget.filename));
1110#endif
1111 _q_printerChanged(currentPrinterIndex);
1112
1113 QObject::connect(widget.printers, SIGNAL(currentIndexChanged(int)),
1114 parent, SLOT(_q_printerChanged(int)));
1115 QObject::connect(widget.fileBrowser, SIGNAL(clicked()), parent, SLOT(_q_btnBrowseClicked()));
1116 QObject::connect(widget.properties, SIGNAL(clicked()), parent, SLOT(_q_btnPropertiesClicked()));
1117
1118 // disable features that QPrinter does not yet support.
1119 widget.preview->setVisible(false);
1120}
1121
1122void QUnixPrintWidgetPrivate::updateWidget()
1123{
1124 const bool printToFile = q == nullptr || q->testOption(QPrintDialog::PrintToFile);
1125 if (printToFile && !filePrintersAdded) {
1126 if (widget.printers->count())
1127 widget.printers->insertSeparator(widget.printers->count());
1128 widget.printers->addItem(QPrintDialog::tr("Print to File (PDF)"));
1129 filePrintersAdded = true;
1130 if (widget.printers->count() == 1)
1131 _q_printerChanged(0);
1132 }
1133 if (!printToFile && filePrintersAdded) {
1134 widget.printers->removeItem(widget.printers->count()-1);
1135 widget.printers->removeItem(widget.printers->count()-1);
1136 if (widget.printers->count())
1137 widget.printers->removeItem(widget.printers->count()-1); // remove separator
1138 filePrintersAdded = false;
1139 }
1140 if (printer && filePrintersAdded && (printer->outputFormat() != QPrinter::NativeFormat
1141 || printer->printerName().isEmpty()))
1142 {
1143 if (printer->outputFormat() == QPrinter::PdfFormat)
1144 widget.printers->setCurrentIndex(widget.printers->count() - 1);
1145 widget.filename->setEnabled(true);
1146 widget.lOutput->setEnabled(true);
1147 }
1148
1149 widget.filename->setVisible(printToFile);
1150 widget.lOutput->setVisible(printToFile);
1151 widget.fileBrowser->setVisible(printToFile);
1152
1153 if (q)
1154 widget.properties->setVisible(q->testOption(QAbstractPrintDialog::PrintShowPageSize));
1155}
1156
1157QUnixPrintWidgetPrivate::~QUnixPrintWidgetPrivate()
1158{
1159}
1160
1161void QUnixPrintWidgetPrivate::_q_printerChanged(int index)
1162{
1163 if (index < 0)
1164 return;
1165 const int printerCount = widget.printers->count();
1166 widget.filename->setEnabled(false);
1167 widget.lOutput->setEnabled(false);
1168
1169 // Reset properties dialog when printer is changed
1170 if (propertiesDialog){
1171 delete propertiesDialog;
1172 propertiesDialog = nullptr;
1173 }
1174
1175#if QT_CONFIG(cups)
1176 m_duplexPpdOption = nullptr;
1177#endif
1178
1179 if (filePrintersAdded) {
1180 Q_ASSERT(index != printerCount - 2); // separator
1181 if (index == printerCount - 1) { // PDF
1182 widget.location->setText(QPrintDialog::tr("Local file"));
1183 widget.type->setText(QPrintDialog::tr("Write PDF file"));
1184 widget.properties->setEnabled(true);
1185 widget.filename->setEnabled(true);
1186 QString filename = widget.filename->text();
1187 widget.filename->setText(filename);
1188 widget.lOutput->setEnabled(true);
1189 printer->setOutputFormat(QPrinter::PdfFormat);
1190 m_currentPrintDevice = QPrintDevice();
1191 if (optionsPane)
1192 optionsPane->selectPrinter(QPrinter::PdfFormat);
1193 return;
1194 }
1195 }
1196
1197 if (printer) {
1198 printer->setOutputFormat(QPrinter::NativeFormat);
1199
1200 QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();
1201 if (ps)
1202 m_currentPrintDevice = ps->createPrintDevice(widget.printers->itemText(index));
1203 else
1204 m_currentPrintDevice = QPrintDevice();
1205
1206 printer->setPrinterName(m_currentPrintDevice.id());
1207
1208 widget.location->setText(m_currentPrintDevice.location());
1209 widget.type->setText(m_currentPrintDevice.makeAndModel());
1210 if (optionsPane)
1211 optionsPane->selectPrinter(QPrinter::NativeFormat);
1212 }
1213
1214#if QT_CONFIG(cups)
1215 m_duplexPpdOption = QCUPSSupport::findPpdOption("Duplex", &m_currentPrintDevice);
1216#endif
1217}
1218
1219void QUnixPrintWidgetPrivate::setOptionsPane(QPrintDialogPrivate *pane)
1220{
1221 optionsPane = pane;
1222 if (optionsPane)
1223 optionsPane->selectPrinter(QPrinter::NativeFormat);
1224}
1225
1226void QUnixPrintWidgetPrivate::_q_btnBrowseClicked()
1227{
1228 QString filename = widget.filename->text();
1229#if QT_CONFIG(filedialog)
1230 filename = QFileDialog::getSaveFileName(parent, QPrintDialog::tr("Print To File ..."), filename,
1231 QString(), nullptr, QFileDialog::DontConfirmOverwrite);
1232#else
1233 filename.clear();
1234#endif
1235 if (!filename.isEmpty()) {
1236 widget.filename->setText(filename);
1237 widget.printers->setCurrentIndex(widget.printers->count() - 1); // the pdf one
1238 }
1239}
1240
1241#if QT_CONFIG(messagebox)
1242bool QUnixPrintWidgetPrivate::checkFields()
1243{
1244 if (widget.filename->isEnabled()) {
1245 QString file = widget.filename->text();
1246 QFile f(file);
1247 QFileInfo fi(f);
1248 bool exists = fi.exists();
1249 bool opened = false;
1250 if (exists && fi.isDir()) {
1251 QMessageBox::warning(q, q->windowTitle(),
1252 QPrintDialog::tr("%1 is a directory.\nPlease choose a different file name.").arg(file));
1253 return false;
1254 } else if ((exists && !fi.isWritable()) || !(opened = f.open(QFile::Append))) {
1255 QMessageBox::warning(q, q->windowTitle(),
1256 QPrintDialog::tr("File %1 is not writable.\nPlease choose a different file name.").arg(file));
1257 return false;
1258 } else if (exists) {
1259 int ret = QMessageBox::question(q, q->windowTitle(),
1260 QPrintDialog::tr("%1 already exists.\nDo you want to overwrite it?").arg(file),
1261 QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
1262 if (ret == QMessageBox::No)
1263 return false;
1264 }
1265 if (opened) {
1266 f.close();
1267 if (!exists)
1268 f.remove();
1269 }
1270 }
1271
1272#if QT_CONFIG(cups)
1273 if (propertiesDialog) {
1274 QCUPSSupport::PagesPerSheet pagesPerSheet = qvariant_cast<QCUPSSupport::PagesPerSheet>(propertiesDialog->widget.pageSetup->m_ui.pagesPerSheetCombo
1275 ->currentData());
1276
1277 QCUPSSupport::PageSet pageSet = qvariant_cast<QCUPSSupport::PageSet>(optionsPane->options.pageSetCombo->currentData());
1278
1279
1280 if (pagesPerSheet != QCUPSSupport::OnePagePerSheet
1281 && pageSet != QCUPSSupport::AllPages) {
1282 QMessageBox::warning(q, q->windowTitle(),
1283 QPrintDialog::tr("Options 'Pages Per Sheet' and 'Page Set' cannot be used together.\nPlease turn one of those options off."));
1284 return false;
1285 }
1286 }
1287#endif
1288
1289 // Every test passed. Accept the dialog.
1290 return true;
1291}
1292#endif // QT_CONFIG(messagebox)
1293
1294void QUnixPrintWidgetPrivate::setupPrinterProperties()
1295{
1296 delete propertiesDialog;
1297
1298 QPrinter::OutputFormat outputFormat;
1299 QString printerName;
1300
1301 if (q->testOption(QPrintDialog::PrintToFile)
1302 && (widget.printers->currentIndex() == widget.printers->count() - 1)) {// PDF
1303 outputFormat = QPrinter::PdfFormat;
1304 } else {
1305 outputFormat = QPrinter::NativeFormat;
1306 printerName = widget.printers->currentText();
1307 }
1308
1309 propertiesDialog = new QPrintPropertiesDialog(q->printer(), &m_currentPrintDevice, outputFormat, printerName, q);
1310}
1311
1312#if QT_CONFIG(cups)
1313void QUnixPrintWidgetPrivate::setPpdDuplex(QPrinter::DuplexMode mode)
1314{
1315 auto values = QStringList{} << QStringLiteral("Duplex");
1316 if (mode == QPrinter::DuplexNone) values << QStringLiteral("None");
1317 else if (mode == QPrinter::DuplexLongSide) values << QStringLiteral("DuplexNoTumble");
1318 else if (mode == QPrinter::DuplexShortSide) values << QStringLiteral("DuplexTumble");
1319
1320 m_currentPrintDevice.setProperty(PDPK_PpdOption, values);
1321}
1322#endif
1323
1324void QUnixPrintWidgetPrivate::_q_btnPropertiesClicked()
1325{
1326 if (!propertiesDialog)
1327 setupPrinterProperties();
1328 propertiesDialog->exec();
1329
1330#if QT_CONFIG(cups)
1331 // update the warning icon on the duplex options if needed
1332 optionsPane->updatePpdDuplexOption(optionsPane->options.noDuplex);
1333 optionsPane->updatePpdDuplexOption(optionsPane->options.duplexLong);
1334 optionsPane->updatePpdDuplexOption(optionsPane->options.duplexShort);
1335#endif
1336}
1337
1338void QUnixPrintWidgetPrivate::setupPrinter()
1339{
1340 const int printerCount = widget.printers->count();
1341 const int index = widget.printers->currentIndex();
1342
1343 if (filePrintersAdded && index == printerCount - 1) { // PDF
1344 printer->setPrinterName(QString());
1345 Q_ASSERT(index != printerCount - 2); // separator
1346 printer->setOutputFormat(QPrinter::PdfFormat);
1347 QString path = widget.filename->text();
1348 if (QDir::isRelativePath(path))
1349 path = QDir::homePath() + QDir::separator() + path;
1350 printer->setOutputFileName(path);
1351 }
1352 else {
1353 printer->setPrinterName(widget.printers->currentText());
1354 printer->setOutputFileName(QString());
1355 }
1356
1357 if (!propertiesDialog)
1358 setupPrinterProperties();
1359
1360 propertiesDialog->setupPrinter();
1361}
1362
1363/*! \internal
1364*/
1365QUnixPrintWidget::QUnixPrintWidget(QPrinter *printer, QWidget *parent)
1366 : QWidget(parent), d(new QUnixPrintWidgetPrivate(this, printer))
1367{
1368 if (printer == nullptr)
1369 return;
1370 if (printer->outputFileName().isEmpty()) {
1371 QString home = QDir::homePath();
1372 QString cur = QDir::currentPath();
1373 if (!home.endsWith(u'/'))
1374 home += u'/';
1375 if (!cur.startsWith(home))
1376 cur = home;
1377 else if (!cur.endsWith(u'/'))
1378 cur += u'/';
1379 if (QGuiApplication::platformName() == "xcb"_L1) {
1380 if (printer->docName().isEmpty()) {
1381 cur += "print.pdf"_L1;
1382 } else {
1383#if QT_CONFIG(regularexpression)
1384 const QRegularExpression re(QStringLiteral("(.*)\\.\\S+"));
1385 auto match = re.match(printer->docName());
1386 if (match.hasMatch())
1387 cur += match.captured(1);
1388 else
1389#endif
1390 cur += printer->docName();
1391 cur += ".pdf"_L1;
1392 }
1393 } // xcb
1394
1395 d->widget.filename->setText(cur);
1396 }
1397 else
1398 d->widget.filename->setText(printer->outputFileName());
1399 const QString printerName = printer->printerName();
1400 if (!printerName.isEmpty()) {
1401 const int i = d->widget.printers->findText(printerName);
1402 if (i >= 0)
1403 d->widget.printers->setCurrentIndex(i);
1404 }
1405 // PDF printer not added to the dialog yet, we'll handle those cases in QUnixPrintWidgetPrivate::updateWidget
1406}
1407
1408/*! \internal
1409*/
1410QUnixPrintWidget::~QUnixPrintWidget()
1411{
1412 delete d;
1413}
1414
1415/*! \internal
1416
1417 Updates the printer with the states held in the QUnixPrintWidget.
1418*/
1419void QUnixPrintWidget::updatePrinter()
1420{
1421 d->setupPrinter();
1422}
1423
1424#if QT_CONFIG(cups)
1425
1426////////////////////////////////////////////////////////////////////////////////
1427////////////////////////////////////////////////////////////////////////////////
1428
1429#endif // QT_CONFIG(cups)
1430#endif // defined (Q_OS_UNIX)
1431
1432QT_END_NAMESPACE
1433
1434#include "moc_qprintdialog.cpp"
1435#include "qprintdialog_unix.moc"
QUnixPrintWidget * top
void selectPrinter(const QPrinter::OutputFormat outputFormat)
virtual void setTabs(const QList< QWidget * > &tabs) override
QDialogButtonBox * buttons
Ui::QPrintSettingsOutput options
QPrinter::OutputFormat printerOutputFormat
void showEvent(QShowEvent *event) override
\reimp
QUnixPrintWidgetPrivate(QUnixPrintWidget *q, QPrinter *prn)
void _q_printerChanged(int index)
QPrintPropertiesDialog * propertiesDialog
QUnixPrintWidget *const parent
void setOptionsPane(QPrintDialogPrivate *pane)
static void _q_pdu_initResources()