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#if QT_CONFIG(accessibility)
501 customValueEdit->setAccessibleName(
502 tr("Custom value for %1").arg(optionText));
503#endif
504 choicesCbWithLabelLayout->addWidget(customValueEdit);
505 choicesCb->setProperty(customValueLineEditProperty,
506 QVariant::fromValue(customValueEdit));
507 // ensure line edit is shown/hidden as needed
508 setPpdOptionFromCombo();
509 }
510 choicesCbWithLabelLayout->addWidget(warningLabel);
511
512 QLabel *optionLabel = new QLabel(optionText);
513 optionLabel->setBuddy(choicesCb);
514 groupLayout->addRow(optionLabel, choicesCbWithLabel);
515 anyWidgetCreated = true;
516 choicesCb->setProperty(ppdOptionProperty, QVariant::fromValue(option));
517 choicesCb->setProperty(warningLabelProperty, QVariant::fromValue(warningLabel));
518 m_advancedOptionsCombos << choicesCb;
519 } else {
520 delete choicesCb;
521 }
522 }
523 }
524
525 if (groupLayout->rowCount() > 0) {
526 QGroupBox *groupBox = new QGroupBox(toUnicode(group->text));
527 groupBox->setLayout(groupLayout);
528 layout->addWidget(groupBox);
529 } else {
530 delete groupLayout;
531 }
532 }
533 }
534
535 layout->addStretch();
536 widget.scrollArea->setWidget(holdingWidget);
537 }
538
539 return anyWidgetCreated;
540}
541
542void QPrintPropertiesDialog::setPrinterAdvancedCupsOptions() const
543{
544 for (const QComboBox *choicesCb : m_advancedOptionsCombos) {
545 const ppd_option_t *option = qvariant_cast<const ppd_option_t *>(choicesCb->property(ppdOptionProperty));
546
547 // We can't use choicesCb->currentIndex() to know the index of the option in the choices[] array
548 // because some of them may not be present in the list because they conflict with the
549 // installable options so use the index passed on addItem
550 const int selectedChoiceIndex = choicesCb->currentData().toInt();
551 QString selectedChoice = QString::fromLatin1(option->choices[selectedChoiceIndex].choice);
552
553 if (selectedChoice == u"Custom") {
554 if (auto *customValueEdit = qvariant_cast<QLineEdit *>(
555 choicesCb->property(customValueLineEditProperty))) {
556 const QString &customValue = customValueEdit->text();
557 if (!customValue.isEmpty())
558 selectedChoice = u"Custom." + customValue;
559 }
560 }
561
562 if (qstrcmp(option->keyword, "ColorModel") == 0)
563 m_printer->setColorMode(selectedChoice == u"Gray" ? QPrinter::GrayScale
564 : QPrinter::Color);
565
566 if (qstrcmp(option->defchoice, selectedChoice.toLatin1().constData()) != 0)
567 QCUPSSupport::setCupsOption(m_printer, QString::fromLatin1(option->keyword),
568 selectedChoice);
569 }
570}
571
572void QPrintPropertiesDialog::revertAdvancedOptionsToSavedValues() const
573{
574 for (QComboBox *choicesCb : m_advancedOptionsCombos) {
575 const int originallySelectedChoice = qvariant_cast<int>(choicesCb->property(ppdOriginallySelectedChoiceProperty));
576 const int newComboIndexToSelect = choicesCb->findData(originallySelectedChoice);
577 choicesCb->setCurrentIndex(newComboIndexToSelect);
578 // The currentIndexChanged lambda takes care of resetting the ppd option
579 }
580 widget.conflictsLabel->setVisible(anyPpdOptionConflict());
581}
582
583void QPrintPropertiesDialog::advancedOptionsUpdateSavedValues() const
584{
585 for (QComboBox *choicesCb : m_advancedOptionsCombos)
586 choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, choicesCb->currentData());
587}
588
589bool QPrintPropertiesDialog::anyPpdOptionConflict() const
590{
591 // we need to execute both since besides returning true/false they update the warning icons
592 const bool pageSetupConflicts = widget.pageSetup->hasPpdConflict();
593 const bool advancedOptionConflicts = anyAdvancedOptionConflict();
594 return pageSetupConflicts || advancedOptionConflicts;
595}
596
597bool QPrintPropertiesDialog::anyAdvancedOptionConflict() const
598{
599 const QIcon warning = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr);
600
601 bool anyConflicted = false;
602
603 for (const QComboBox *choicesCb : m_advancedOptionsCombos) {
604 const ppd_option_t *option = qvariant_cast<const ppd_option_t *>(choicesCb->property(ppdOptionProperty));
605 QLabel *warningLabel = qvariant_cast<QLabel *>(choicesCb->property(warningLabelProperty));
606 if (option->conflicted) {
607 anyConflicted = true;
608 const int pixmap_size = choicesCb->sizeHint().height() * .75;
609 warningLabel->setPixmap(warning.pixmap(pixmap_size, pixmap_size));
610 } else {
611 warningLabel->setPixmap(QPixmap());
612 }
613 }
614
615 return anyConflicted;
616}
617
618#endif
619
620
621////////////////////////////////////////////////////////////////////////////////
622////////////////////////////////////////////////////////////////////////////////
623
624/*
625
626 QPrintDialogPrivate
627
628 The lower half of the Print Dialog containing the Copies and Options
629 tabs that expands when the Options button is selected.
630
631*/
632QPrintDialogPrivate::QPrintDialogPrivate()
633 : top(nullptr), bottom(nullptr), buttons(nullptr), collapseButton(nullptr),
634 explicitDuplexMode(QPrint::DuplexAuto)
635{
637}
638
642
644{
645 Q_Q(QPrintDialog);
646
647 top = new QUnixPrintWidget(q->printer(), q);
648 bottom = new QWidget(q);
649 options.setupUi(bottom);
650 options.color->setIconSize(QSize(32, 32));
651 options.color->setIcon(QIcon(":/qt-project.org/dialogs/qprintdialog/images/status-color.png"_L1));
652 options.grayscale->setIconSize(QSize(32, 32));
653 options.grayscale->setIcon(QIcon(":/qt-project.org/dialogs/qprintdialog/images/status-gray-scale.png"_L1));
654
655#if QT_CONFIG(cups)
656 // Add Page Set widget if CUPS is available
657 options.pageSetCombo->addItem(tr("All Pages"), QVariant::fromValue(QCUPSSupport::AllPages));
658 options.pageSetCombo->addItem(tr("Odd Pages"), QVariant::fromValue(QCUPSSupport::OddPages));
659 options.pageSetCombo->addItem(tr("Even Pages"), QVariant::fromValue(QCUPSSupport::EvenPages));
660#else
661 delete options.pagesRadioButton;
662 delete options.pagesLineEdit;
663 options.pagesRadioButton = nullptr;
664 options.pagesLineEdit = nullptr;
665#endif
666
668
669 buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, q);
670 collapseButton = new QPushButton(QPrintDialog::tr("&Options >>"), buttons);
671 buttons->addButton(collapseButton, QDialogButtonBox::ResetRole);
672 bottom->setVisible(false);
673
674 QPushButton *printButton = buttons->button(QDialogButtonBox::Ok);
675 printButton->setText(QPrintDialog::tr("&Print"));
676 printButton->setDefault(true);
677
678 QVBoxLayout *lay = new QVBoxLayout(q);
679 lay->addWidget(top);
680 lay->addWidget(bottom);
681 lay->addWidget(buttons);
682
683#if !QT_CONFIG(messagebox)
684 QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(accept()));
685#else
686 QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(_q_checkFields()));
687#endif
688 QObject::connect(buttons, SIGNAL(rejected()), q, SLOT(reject()));
689
690 QObject::connect(options.printSelection, SIGNAL(toggled(bool)),
691 q, SLOT(_q_togglePageSetCombo(bool)));
692
693 QObject::connect(options.printCurrentPage, SIGNAL(toggled(bool)),
694 q, SLOT(_q_togglePageSetCombo(bool)));
695
696 QObject::connect(collapseButton, SIGNAL(released()), q, SLOT(_q_collapseOrExpandDialog()));
697
698 QObject::connect(options.noDuplex, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexNone); });
699 QObject::connect(options.duplexLong, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexLongSide); });
700 QObject::connect(options.duplexShort, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexShortSide); });
701
702#if QT_CONFIG(cups)
703 QObject::connect(options.noDuplex, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.noDuplex); });
704 QObject::connect(options.duplexLong, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexLong); });
705 QObject::connect(options.duplexShort, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexShort); });
706#endif
707}
708
709// initialize printer options
710void QPrintDialogPrivate::selectPrinter(const QPrinter::OutputFormat outputFormat)
711{
712 Q_Q(QPrintDialog);
713 QPrinter *p = q->printer();
714 printerOutputFormat = outputFormat;
715
716 // printer supports duplex mode?
717 const auto supportedDuplexMode = top->d->m_currentPrintDevice.supportedDuplexModes();
718 options.duplexLong->setEnabled(supportedDuplexMode.contains(QPrint::DuplexLongSide));
719 options.duplexShort->setEnabled(supportedDuplexMode.contains(QPrint::DuplexShortSide));
720
721 if (p->colorMode() == QPrinter::Color)
722 options.color->setChecked(true);
723 else
724 options.grayscale->setChecked(true);
725
726 // duplex priorities to be as follows:
727 // 1) a user-selected duplex value in the dialog has highest priority
728 // 2) duplex value set in the QPrinter
729 QPrint::DuplexMode duplex;
730 if (explicitDuplexMode != QPrint::DuplexAuto && supportedDuplexMode.contains(explicitDuplexMode))
731 duplex = explicitDuplexMode;
732 else
733 duplex = static_cast<QPrint::DuplexMode>(p->duplex());
734 switch (duplex) {
735 case QPrint::DuplexNone:
736 options.noDuplex->setChecked(true); break;
737 case QPrint::DuplexLongSide:
738 case QPrint::DuplexAuto:
739 options.duplexLong->setChecked(true); break;
740 case QPrint::DuplexShortSide:
741 options.duplexShort->setChecked(true); break;
742 }
743 options.copies->setValue(p->copyCount());
744 options.collate->setChecked(p->collateCopies());
745 options.reverse->setChecked(p->pageOrder() == QPrinter::LastPageFirst);
746
747 if (outputFormat == QPrinter::PdfFormat || options.printSelection->isChecked()
748 || options.printCurrentPage->isChecked())
749
750 options.pageSetCombo->setEnabled(false);
751 else
752 options.pageSetCombo->setEnabled(true);
753
754#if QT_CONFIG(cups)
755 // Disable complex page ranges widget when printing to pdf
756 // It doesn't work since it relies on cups to do the heavy lifting and cups
757 // is not used when printing to PDF
758 options.pagesRadioButton->setEnabled(outputFormat != QPrinter::PdfFormat);
759
760 // Disable color options on main dialog if not printing to file, it will be handled by CUPS advanced dialog
761 options.colorMode->setVisible(outputFormat == QPrinter::PdfFormat);
762#endif
763}
764
765#if QT_CONFIG(cups)
766
767void QPrintDialogPrivate::updatePpdDuplexOption(QRadioButton *radio)
768{
769 const bool checked = radio->isChecked();
770 if (checked) {
771 if (radio == options.noDuplex) top->d->setPpdDuplex(QPrinter::DuplexNone);
772 else if (radio == options.duplexLong) top->d->setPpdDuplex(QPrinter::DuplexLongSide);
773 else if (radio == options.duplexShort) top->d->setPpdDuplex(QPrinter::DuplexShortSide);
774 }
775 const bool conflict = checked && top->d->m_duplexPpdOption && top->d->m_duplexPpdOption->conflicted;
776 radio->setIcon(conflict ? QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr) : QIcon());
777}
778
779#endif
780
781void QPrintDialogPrivate::setExplicitDuplexMode(const QPrint::DuplexMode duplexMode)
782{
783 explicitDuplexMode = duplexMode;
784}
785
787{
788 // First setup the requested OutputFormat, Printer and Page Size first
790
791 // Then setup Print Job options
792 Q_Q(QPrintDialog);
793 QPrinter* p = q->printer();
794
795 if (options.duplex->isEnabled()) {
796 if (options.noDuplex->isChecked())
797 p->setDuplex(QPrinter::DuplexNone);
798 else if (options.duplexLong->isChecked())
799 p->setDuplex(QPrinter::DuplexLongSide);
800 else
801 p->setDuplex(QPrinter::DuplexShortSide);
802 }
803
804#if QT_CONFIG(cups)
805 // When printing to a device the colorMode will be set by the advanced panel
806 if (p->outputFormat() == QPrinter::PdfFormat)
807#endif
808 p->setColorMode(options.color->isChecked() ? QPrinter::Color : QPrinter::GrayScale);
809
810 p->setPageOrder(options.reverse->isChecked() ? QPrinter::LastPageFirst : QPrinter::FirstPageFirst);
811
812 // print range
813 if (options.printAll->isChecked()) {
814 p->setPrintRange(QPrinter::AllPages);
815 p->setPageRanges(QPageRanges());
816 } else if (options.printSelection->isChecked()) {
817 p->setPrintRange(QPrinter::Selection);
818 p->setPageRanges(QPageRanges());
819 } else if (options.printCurrentPage->isChecked()) {
820 p->setPrintRange(QPrinter::CurrentPage);
821 p->setPageRanges(QPageRanges());
822 } else if (options.printRange->isChecked()) {
823 if (q->testOption(QPrintDialog::PrintPageRange)) {
824 p->setPrintRange(QPrinter::PageRange);
825 p->setFromTo(options.from->value(), qMax(options.from->value(), options.to->value()));
826 } else {
827 // This case happens when CUPS server-side page range is enabled
828 // Setting the range to the printer occurs below
829 p->setPrintRange(QPrinter::AllPages);
830 p->setPageRanges(QPageRanges());
831 }
832 }
833
834#if QT_CONFIG(cups)
835 if (options.pagesRadioButton->isChecked()) {
836 const QPageRanges ranges = QPageRanges::fromString(options.pagesLineEdit->text());
837 p->setPrintRange(QPrinter::AllPages);
838 p->setPageRanges(QPageRanges());
839
840 // server-side page filtering
841 QCUPSSupport::setPageRange(p, ranges.toString());
842 }
843
844 // page set
845 if (p->printRange() == QPrinter::AllPages || p->printRange() == QPrinter::PageRange) {
846 //If the application is selecting pages and the first page number is even then need to adjust the odd-even accordingly
847 QCUPSSupport::PageSet pageSet = qvariant_cast<QCUPSSupport::PageSet>(options.pageSetCombo->itemData(options.pageSetCombo->currentIndex()));
848 if (q->testOption(QPrintDialog::PrintPageRange)
849 && p->printRange() == QPrinter::PageRange
850 && (q->fromPage() % 2 == 0)) {
851
852 switch (pageSet) {
853 case QCUPSSupport::AllPages:
854 break;
855 case QCUPSSupport::OddPages:
856 QCUPSSupport::setPageSet(p, QCUPSSupport::EvenPages);
857 break;
858 case QCUPSSupport::EvenPages:
859 QCUPSSupport::setPageSet(p, QCUPSSupport::OddPages);
860 break;
861 }
862 } else if (pageSet != QCUPSSupport::AllPages) {
863 QCUPSSupport::setPageSet(p, pageSet);
864 }
865
866 // server-side page range, since we set the page range on the printer to 0-0/AllPages above,
867 // we need to take the values directly from the widget as q->fromPage() will return 0
868 if (!q->testOption(QPrintDialog::PrintPageRange) && options.printRange->isChecked())
869 QCUPSSupport::setPageRange(p, options.from->value(), qMax(options.from->value(), options.to->value()));
870 }
871#endif
872
873 // copies
874 p->setCopyCount(options.copies->value());
875 p->setCollateCopies(options.collate->isChecked());
876}
877
879{
880 if (printerOutputFormat == QPrinter::PdfFormat)
881 return;
882
883 options.pageSetCombo->setDisabled(checked);
884}
885
887{
888 int collapseHeight = 0;
889 Q_Q(QPrintDialog);
890 QWidget *widgetToHide = bottom;
891 if (widgetToHide->isVisible()) {
892 collapseButton->setText(QPrintDialog::tr("&Options >>"));
893 collapseHeight = widgetToHide->y() + widgetToHide->height() - (top->y() + top->height());
894 }
895 else
896 collapseButton->setText(QPrintDialog::tr("&Options <<"));
897 widgetToHide->setVisible(! widgetToHide->isVisible());
898 if (! widgetToHide->isVisible()) { // make it shrink
899 q->layout()->activate();
900 q->resize( QSize(q->width(), q->height() - collapseHeight) );
901 }
902}
903
904#if QT_CONFIG(messagebox)
905void QPrintDialogPrivate::_q_checkFields()
906{
907 Q_Q(QPrintDialog);
908 if (top->d->checkFields())
909 q->accept();
910}
911#endif // QT_CONFIG(messagebox)
912
913
915{
916 Q_Q(QPrintDialog);
917 options.gbPrintRange->setVisible(q->testOption(QPrintDialog::PrintPageRange) ||
918 q->testOption(QPrintDialog::PrintSelection) ||
919 q->testOption(QPrintDialog::PrintCurrentPage));
920
921 options.printRange->setEnabled(q->testOption(QPrintDialog::PrintPageRange));
922 options.printSelection->setVisible(q->testOption(QPrintDialog::PrintSelection));
923 options.printCurrentPage->setVisible(q->testOption(QPrintDialog::PrintCurrentPage));
924 options.collate->setVisible(q->testOption(QPrintDialog::PrintCollateCopies));
925
926#if QT_CONFIG(cups)
927 // Don't display Page Set if only Selection or Current Page are enabled
928 if (!q->testOption(QPrintDialog::PrintPageRange)
929 && (q->testOption(QPrintDialog::PrintSelection) || q->testOption(QPrintDialog::PrintCurrentPage))) {
930 options.pageSetCombo->setVisible(false);
931 options.pageSetLabel->setVisible(false);
932 } else {
933 options.pageSetCombo->setVisible(true);
934 options.pageSetLabel->setVisible(true);
935 }
936
937 if (!q->testOption(QPrintDialog::PrintPageRange)) {
938 // If we can do CUPS server side pages selection,
939 // display the page range widgets
940 options.gbPrintRange->setVisible(true);
941 options.printRange->setEnabled(true);
942 }
943#endif
944
945 switch (q->printRange()) {
946 case QPrintDialog::AllPages:
947 options.printAll->setChecked(true);
948 options.pageSetCombo->setEnabled(true);
949 break;
950 case QPrintDialog::Selection:
951 options.printSelection->setChecked(true);
952 options.pageSetCombo->setEnabled(false);
953 break;
954 case QPrintDialog::PageRange:
955 options.printRange->setChecked(true);
956 options.pageSetCombo->setEnabled(true);
957 break;
958 case QPrintDialog::CurrentPage:
959 if (q->testOption(QPrintDialog::PrintCurrentPage)) {
960 options.printCurrentPage->setChecked(true);
961 options.pageSetCombo->setEnabled(false);
962 }
963 break;
964 default:
965 break;
966 }
967 const int minPage = qMax(1, qMin(q->minPage() , q->maxPage()));
968 const int maxPage = qMax(1, q->maxPage() == INT_MAX ? 9999 : q->maxPage());
969
970 options.from->setMinimum(minPage);
971 options.to->setMinimum(minPage);
972 options.from->setMaximum(maxPage);
973 options.to->setMaximum(maxPage);
974
975 options.from->setValue(q->fromPage());
976 options.to->setValue(q->toPage());
978}
979
980void QPrintDialogPrivate::setTabs(const QList<QWidget*> &tabWidgets)
981{
982 QList<QWidget*>::ConstIterator iter = tabWidgets.begin();
983 while(iter != tabWidgets.constEnd()) {
984 QWidget *tab = *iter;
985 options.tabs->addTab(tab, tab->windowTitle());
986 ++iter;
987 }
988}
989
990////////////////////////////////////////////////////////////////////////////////
991////////////////////////////////////////////////////////////////////////////////
992
993/*
994
995 QPrintDialog
996
997 The main Print Dialog.
998
999*/
1000
1001QPrintDialog::QPrintDialog(QPrinter *printer, QWidget *parent)
1002 : QAbstractPrintDialog(*(new QPrintDialogPrivate), printer, parent)
1003{
1004 Q_D(QPrintDialog);
1005 d->init();
1006}
1007
1008/*!
1009 Constructs a print dialog with the given \a parent.
1010*/
1011QPrintDialog::QPrintDialog(QWidget *parent)
1012 : QAbstractPrintDialog(*(new QPrintDialogPrivate), nullptr, parent)
1013{
1014 Q_D(QPrintDialog);
1015 d->init();
1016}
1017
1018QPrintDialog::~QPrintDialog()
1019{
1020}
1021
1022void QPrintDialog::setVisible(bool visible)
1023{
1024 Q_D(QPrintDialog);
1025
1026 if (visible)
1027 d->updateWidgets();
1028
1029 QAbstractPrintDialog::setVisible(visible);
1030}
1031
1032int QPrintDialog::exec()
1033{
1034 return QAbstractPrintDialog::exec();
1035}
1036
1037void QPrintDialog::accept()
1038{
1039 Q_D(QPrintDialog);
1040#if QT_CONFIG(cups) && QT_CONFIG(messagebox)
1041 if (d->options.pagesRadioButton->isChecked()) {
1042 const QString rangesText = d->options.pagesLineEdit->text();
1043 if (rangesText.isEmpty() || QPageRanges::fromString(rangesText).isEmpty()) {
1044 QMessageBox::critical(this, tr("Invalid Pages Definition"),
1045 tr("%1 does not follow the correct syntax. Please use ',' to separate "
1046 "ranges and pages, '-' to define ranges and make sure ranges do "
1047 "not intersect with each other.").arg(rangesText),
1048 QMessageBox::Ok, QMessageBox::Ok);
1049 return;
1050 }
1051 }
1052 if (d->top->d->m_duplexPpdOption && d->top->d->m_duplexPpdOption->conflicted) {
1053 const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Duplex Settings Conflicts"),
1054 tr("There are conflicts in duplex settings. Do you want to fix them?"),
1055 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
1056 if (answer != QMessageBox::No)
1057 return;
1058 }
1059#endif
1060 d->setupPrinter();
1061 QDialog::accept();
1062}
1063
1064////////////////////////////////////////////////////////////////////////////////
1065////////////////////////////////////////////////////////////////////////////////
1066
1067/*
1068
1069 QUnixPrintWidget && QUnixPrintWidgetPrivate
1070
1071 The upper half of the Print Dialog containing the Printer Selection widgets
1072
1073*/
1074
1075#if defined (Q_OS_UNIX)
1076
1077/*! \internal
1078*/
1079QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p, QPrinter *prn)
1080 : parent(p), propertiesDialog(nullptr), printer(prn),
1081#if QT_CONFIG(cups)
1082 m_duplexPpdOption(nullptr),
1083#endif
1084 optionsPane(nullptr), filePrintersAdded(false)
1085{
1086 q = nullptr;
1087 if (parent)
1088 q = qobject_cast<QPrintDialog*> (parent->parent());
1089
1090 widget.setupUi(parent);
1091
1092 int currentPrinterIndex = 0;
1093 QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();
1094 if (ps) {
1095 const QStringList printers = ps->availablePrintDeviceIds();
1096 const QString defaultPrinter = ps->defaultPrintDeviceId();
1097
1098 widget.printers->addItems(printers);
1099
1100 const QString selectedPrinter = prn && !prn->printerName().isEmpty() ? prn->printerName() : defaultPrinter;
1101 const int idx = printers.indexOf(selectedPrinter);
1102
1103 if (idx >= 0)
1104 currentPrinterIndex = idx;
1105 }
1106 widget.properties->setEnabled(true);
1107
1108#if QT_CONFIG(filesystemmodel) && QT_CONFIG(completer)
1109 QFileSystemModel *fsm = new QFileSystemModel(widget.filename);
1110 fsm->setRootPath(QDir::homePath());
1111 widget.filename->setCompleter(new QCompleter(fsm, widget.filename));
1112#endif
1113 _q_printerChanged(currentPrinterIndex);
1114
1115 QObject::connect(widget.printers, SIGNAL(currentIndexChanged(int)),
1116 parent, SLOT(_q_printerChanged(int)));
1117 QObject::connect(widget.fileBrowser, SIGNAL(clicked()), parent, SLOT(_q_btnBrowseClicked()));
1118 QObject::connect(widget.properties, SIGNAL(clicked()), parent, SLOT(_q_btnPropertiesClicked()));
1119
1120 // disable features that QPrinter does not yet support.
1121 widget.preview->setVisible(false);
1122}
1123
1124void QUnixPrintWidgetPrivate::updateWidget()
1125{
1126 const bool printToFile = q == nullptr || q->testOption(QPrintDialog::PrintToFile);
1127 if (printToFile && !filePrintersAdded) {
1128 if (widget.printers->count())
1129 widget.printers->insertSeparator(widget.printers->count());
1130 widget.printers->addItem(QPrintDialog::tr("Print to File (PDF)"));
1131 filePrintersAdded = true;
1132 if (widget.printers->count() == 1)
1133 _q_printerChanged(0);
1134 }
1135 if (!printToFile && filePrintersAdded) {
1136 widget.printers->removeItem(widget.printers->count()-1);
1137 widget.printers->removeItem(widget.printers->count()-1);
1138 if (widget.printers->count())
1139 widget.printers->removeItem(widget.printers->count()-1); // remove separator
1140 filePrintersAdded = false;
1141 }
1142 if (printer && filePrintersAdded && (printer->outputFormat() != QPrinter::NativeFormat
1143 || printer->printerName().isEmpty()))
1144 {
1145 if (printer->outputFormat() == QPrinter::PdfFormat)
1146 widget.printers->setCurrentIndex(widget.printers->count() - 1);
1147 widget.filename->setEnabled(true);
1148 widget.lOutput->setEnabled(true);
1149 }
1150
1151 widget.filename->setVisible(printToFile);
1152 widget.lOutput->setVisible(printToFile);
1153 widget.fileBrowser->setVisible(printToFile);
1154
1155 if (q)
1156 widget.properties->setVisible(q->testOption(QAbstractPrintDialog::PrintShowPageSize));
1157}
1158
1159QUnixPrintWidgetPrivate::~QUnixPrintWidgetPrivate()
1160{
1161}
1162
1163void QUnixPrintWidgetPrivate::_q_printerChanged(int index)
1164{
1165 if (index < 0)
1166 return;
1167 const int printerCount = widget.printers->count();
1168 widget.filename->setEnabled(false);
1169 widget.lOutput->setEnabled(false);
1170
1171 // Reset properties dialog when printer is changed
1172 if (propertiesDialog){
1173 delete propertiesDialog;
1174 propertiesDialog = nullptr;
1175 }
1176
1177#if QT_CONFIG(cups)
1178 m_duplexPpdOption = nullptr;
1179#endif
1180
1181 if (filePrintersAdded) {
1182 Q_ASSERT(index != printerCount - 2); // separator
1183 if (index == printerCount - 1) { // PDF
1184 widget.location->setText(QPrintDialog::tr("Local file"));
1185 widget.type->setText(QPrintDialog::tr("Write PDF file"));
1186 widget.properties->setEnabled(true);
1187 widget.filename->setEnabled(true);
1188 QString filename = widget.filename->text();
1189 widget.filename->setText(filename);
1190 widget.lOutput->setEnabled(true);
1191 printer->setOutputFormat(QPrinter::PdfFormat);
1192 m_currentPrintDevice = QPrintDevice();
1193 if (optionsPane)
1194 optionsPane->selectPrinter(QPrinter::PdfFormat);
1195 return;
1196 }
1197 }
1198
1199 if (printer) {
1200 printer->setOutputFormat(QPrinter::NativeFormat);
1201
1202 QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();
1203 if (ps)
1204 m_currentPrintDevice = ps->createPrintDevice(widget.printers->itemText(index));
1205 else
1206 m_currentPrintDevice = QPrintDevice();
1207
1208 printer->setPrinterName(m_currentPrintDevice.id());
1209
1210 widget.location->setText(m_currentPrintDevice.location());
1211 widget.type->setText(m_currentPrintDevice.makeAndModel());
1212 if (optionsPane)
1213 optionsPane->selectPrinter(QPrinter::NativeFormat);
1214 }
1215
1216#if QT_CONFIG(cups)
1217 m_duplexPpdOption = QCUPSSupport::findPpdOption("Duplex", &m_currentPrintDevice);
1218#endif
1219}
1220
1221void QUnixPrintWidgetPrivate::setOptionsPane(QPrintDialogPrivate *pane)
1222{
1223 optionsPane = pane;
1224 if (optionsPane)
1225 optionsPane->selectPrinter(QPrinter::NativeFormat);
1226}
1227
1228void QUnixPrintWidgetPrivate::_q_btnBrowseClicked()
1229{
1230 QString filename = widget.filename->text();
1231#if QT_CONFIG(filedialog)
1232 filename = QFileDialog::getSaveFileName(parent, QPrintDialog::tr("Print To File ..."), filename,
1233 QString(), nullptr, QFileDialog::DontConfirmOverwrite);
1234#else
1235 filename.clear();
1236#endif
1237 if (!filename.isEmpty()) {
1238 widget.filename->setText(filename);
1239 widget.printers->setCurrentIndex(widget.printers->count() - 1); // the pdf one
1240 }
1241}
1242
1243#if QT_CONFIG(messagebox)
1244bool QUnixPrintWidgetPrivate::checkFields()
1245{
1246 if (widget.filename->isEnabled()) {
1247 QString file = widget.filename->text();
1248 QFile f(file);
1249 QFileInfo fi(f);
1250 bool exists = fi.exists();
1251 bool opened = false;
1252 if (exists && fi.isDir()) {
1253 QMessageBox::warning(q, q->windowTitle(),
1254 QPrintDialog::tr("%1 is a directory.\nPlease choose a different file name.").arg(file));
1255 return false;
1256 } else if ((exists && !fi.isWritable()) || !(opened = f.open(QFile::Append))) {
1257 QMessageBox::warning(q, q->windowTitle(),
1258 QPrintDialog::tr("File %1 is not writable.\nPlease choose a different file name.").arg(file));
1259 return false;
1260 } else if (exists) {
1261 int ret = QMessageBox::question(q, q->windowTitle(),
1262 QPrintDialog::tr("%1 already exists.\nDo you want to overwrite it?").arg(file),
1263 QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
1264 if (ret == QMessageBox::No)
1265 return false;
1266 }
1267 if (opened) {
1268 f.close();
1269 if (!exists)
1270 f.remove();
1271 }
1272 }
1273
1274#if QT_CONFIG(cups)
1275 if (propertiesDialog) {
1276 QCUPSSupport::PagesPerSheet pagesPerSheet = qvariant_cast<QCUPSSupport::PagesPerSheet>(propertiesDialog->widget.pageSetup->m_ui.pagesPerSheetCombo
1277 ->currentData());
1278
1279 QCUPSSupport::PageSet pageSet = qvariant_cast<QCUPSSupport::PageSet>(optionsPane->options.pageSetCombo->currentData());
1280
1281
1282 if (pagesPerSheet != QCUPSSupport::OnePagePerSheet
1283 && pageSet != QCUPSSupport::AllPages) {
1284 QMessageBox::warning(q, q->windowTitle(),
1285 QPrintDialog::tr("Options 'Pages Per Sheet' and 'Page Set' cannot be used together.\nPlease turn one of those options off."));
1286 return false;
1287 }
1288 }
1289#endif
1290
1291 // Every test passed. Accept the dialog.
1292 return true;
1293}
1294#endif // QT_CONFIG(messagebox)
1295
1296void QUnixPrintWidgetPrivate::setupPrinterProperties()
1297{
1298 delete propertiesDialog;
1299
1300 QPrinter::OutputFormat outputFormat;
1301 QString printerName;
1302
1303 if (q->testOption(QPrintDialog::PrintToFile)
1304 && (widget.printers->currentIndex() == widget.printers->count() - 1)) {// PDF
1305 outputFormat = QPrinter::PdfFormat;
1306 } else {
1307 outputFormat = QPrinter::NativeFormat;
1308 printerName = widget.printers->currentText();
1309 }
1310
1311 propertiesDialog = new QPrintPropertiesDialog(q->printer(), &m_currentPrintDevice, outputFormat, printerName, q);
1312}
1313
1314#if QT_CONFIG(cups)
1315void QUnixPrintWidgetPrivate::setPpdDuplex(QPrinter::DuplexMode mode)
1316{
1317 auto values = QStringList{} << QStringLiteral("Duplex");
1318 if (mode == QPrinter::DuplexNone) values << QStringLiteral("None");
1319 else if (mode == QPrinter::DuplexLongSide) values << QStringLiteral("DuplexNoTumble");
1320 else if (mode == QPrinter::DuplexShortSide) values << QStringLiteral("DuplexTumble");
1321
1322 m_currentPrintDevice.setProperty(PDPK_PpdOption, values);
1323}
1324#endif
1325
1326void QUnixPrintWidgetPrivate::_q_btnPropertiesClicked()
1327{
1328 if (!propertiesDialog)
1329 setupPrinterProperties();
1330 propertiesDialog->exec();
1331
1332#if QT_CONFIG(cups)
1333 // update the warning icon on the duplex options if needed
1334 optionsPane->updatePpdDuplexOption(optionsPane->options.noDuplex);
1335 optionsPane->updatePpdDuplexOption(optionsPane->options.duplexLong);
1336 optionsPane->updatePpdDuplexOption(optionsPane->options.duplexShort);
1337#endif
1338}
1339
1340void QUnixPrintWidgetPrivate::setupPrinter()
1341{
1342 const int printerCount = widget.printers->count();
1343 const int index = widget.printers->currentIndex();
1344
1345 if (filePrintersAdded && index == printerCount - 1) { // PDF
1346 printer->setPrinterName(QString());
1347 Q_ASSERT(index != printerCount - 2); // separator
1348 printer->setOutputFormat(QPrinter::PdfFormat);
1349 QString path = widget.filename->text();
1350 if (QDir::isRelativePath(path))
1351 path = QDir::homePath() + QDir::separator() + path;
1352 printer->setOutputFileName(path);
1353 }
1354 else {
1355 printer->setPrinterName(widget.printers->currentText());
1356 printer->setOutputFileName(QString());
1357 }
1358
1359 if (!propertiesDialog)
1360 setupPrinterProperties();
1361
1362 propertiesDialog->setupPrinter();
1363}
1364
1365/*! \internal
1366*/
1367QUnixPrintWidget::QUnixPrintWidget(QPrinter *printer, QWidget *parent)
1368 : QWidget(parent), d(new QUnixPrintWidgetPrivate(this, printer))
1369{
1370 if (printer == nullptr)
1371 return;
1372 if (printer->outputFileName().isEmpty()) {
1373 QString home = QDir::homePath();
1374 QString cur = QDir::currentPath();
1375 if (!home.endsWith(u'/'))
1376 home += u'/';
1377 if (!cur.startsWith(home))
1378 cur = home;
1379 else if (!cur.endsWith(u'/'))
1380 cur += u'/';
1381 if (QGuiApplication::platformName() == "xcb"_L1) {
1382 if (printer->docName().isEmpty()) {
1383 cur += "print.pdf"_L1;
1384 } else {
1385#if QT_CONFIG(regularexpression)
1386 const QRegularExpression re(QStringLiteral("(.*)\\.\\S+"));
1387 auto match = re.match(printer->docName());
1388 if (match.hasMatch())
1389 cur += match.captured(1);
1390 else
1391#endif
1392 cur += printer->docName();
1393 cur += ".pdf"_L1;
1394 }
1395 } // xcb
1396
1397 d->widget.filename->setText(cur);
1398 }
1399 else
1400 d->widget.filename->setText(printer->outputFileName());
1401 const QString printerName = printer->printerName();
1402 if (!printerName.isEmpty()) {
1403 const int i = d->widget.printers->findText(printerName);
1404 if (i >= 0)
1405 d->widget.printers->setCurrentIndex(i);
1406 }
1407 // PDF printer not added to the dialog yet, we'll handle those cases in QUnixPrintWidgetPrivate::updateWidget
1408}
1409
1410/*! \internal
1411*/
1412QUnixPrintWidget::~QUnixPrintWidget()
1413{
1414 delete d;
1415}
1416
1417/*! \internal
1418
1419 Updates the printer with the states held in the QUnixPrintWidget.
1420*/
1421void QUnixPrintWidget::updatePrinter()
1422{
1423 d->setupPrinter();
1424}
1425
1426#if QT_CONFIG(cups)
1427
1428////////////////////////////////////////////////////////////////////////////////
1429////////////////////////////////////////////////////////////////////////////////
1430
1431#endif // QT_CONFIG(cups)
1432#endif // defined (Q_OS_UNIX)
1433
1434QT_END_NAMESPACE
1435
1436#include "moc_qprintdialog.cpp"
1437#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()