Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
4#include "qplatformdefs.h"
5#include <QtPrintSupport/private/qtprintsupportglobal_p.h>
6
7#include "private/qabstractprintdialog_p.h"
8#if QT_CONFIG(messagebox)
9#include <QtWidgets/qmessagebox.h>
10#endif
11#include "qprintdialog.h"
12#if QT_CONFIG(filedialog)
13#include "qfiledialog.h"
14#endif
15#include <QtCore/qdebug.h>
16#include <QtCore/qdir.h>
17#include <QtCore/qglobal.h>
18#include <QtCore/qstringconverter.h>
19#include <QtGui/qevent.h>
20#if QT_CONFIG(filesystemmodel)
21#include <QtGui/qfilesystemmodel.h>
22#endif
23#include <QtWidgets/qstyleditemdelegate.h>
24#include <QtWidgets/qformlayout.h>
25#include <QtPrintSupport/qprinter.h>
26
27#include <qpa/qplatformprintplugin.h>
28#include <qpa/qplatformprintersupport.h>
29
30#include <private/qprintdevice_p.h>
31
32#include <QtWidgets/qdialogbuttonbox.h>
33
34#if QT_CONFIG(regularexpression)
35#include <qregularexpression.h>
36#endif
37
38#if QT_CONFIG(completer)
39#include <private/qcompleter_p.h>
40#endif
41#include "ui_qprintpropertieswidget.h"
42#include "ui_qprintsettingsoutput.h"
43#include "ui_qprintwidget.h"
44
45#if QT_CONFIG(cups)
46Q_DECLARE_METATYPE(const ppd_option_t *)
47#include <private/qcups_p.h>
48#if QT_CONFIG(cupsjobwidget)
49#include "qcupsjobwidget_p.h"
50#endif
51#endif
52
53/*
54
55Print dialog class declarations
56
57 QPrintDialog: The main Print Dialog, nothing really held here.
58
59 QUnixPrintWidget:
60 QUnixPrintWidgetPrivate: The real Unix Print Dialog implementation.
61
62 Directly includes the upper half of the Print Dialog
63 containing the Printer Selection widgets and
64 Properties button.
65
66 Embeds the Properties pop-up dialog from
67 QPrintPropertiesDialog
68
69 Embeds the lower half from separate widget class
70 QPrintDialogPrivate
71
72 Layout in qprintwidget.ui
73
74 QPrintDialogPrivate: The lower half of the Print Dialog containing the
75 Copies and Options tabs that expands when the
76 Options button is selected.
77
78 Layout in qprintsettingsoutput.ui
79
80 QPrintPropertiesDialog: Dialog displayed when clicking on Properties button to
81 allow editing of Page and Advanced tabs.
82
83 Layout in qprintpropertieswidget.ui
84*/
85
87{
88 Q_INIT_RESOURCE(qprintdialog);
89}
90
92
93using namespace Qt::StringLiterals;
94
96{
98public:
99 QPrintPropertiesDialog(QPrinter *printer, QPrintDevice *currentPrintDevice,
100 QPrinter::OutputFormat outputFormat, const QString &printerName,
103
104 void setupPrinter() const;
105
106private slots:
107 void reject() override;
108 void accept() override;
109
110private:
111 void showEvent(QShowEvent *event) override;
112
114#if QT_CONFIG(cups)
115 QPrinter *m_printer;
116#endif
117 Ui::QPrintPropertiesWidget widget;
119#if QT_CONFIG(cupsjobwidget)
120 QCupsJobWidget *m_jobOptions;
121#endif
122
123#if QT_CONFIG(cups)
124 bool createAdvancedOptionsWidget();
125 void setPrinterAdvancedCupsOptions() const;
126 void revertAdvancedOptionsToSavedValues() const;
127 void advancedOptionsUpdateSavedValues() const;
128 bool anyPpdOptionConflict() const;
129 bool anyAdvancedOptionConflict() const;
130
131 QPrintDevice *m_currentPrintDevice;
132
133 QStringDecoder toUnicode;
134 QList<QComboBox*> m_advancedOptionsCombos;
135#endif
136};
137
139
141{
143
144public:
145 explicit QUnixPrintWidget(QPrinter *printer, QWidget *parent = nullptr);
148
149private:
150 friend class QPrintDialog;
154 Q_PRIVATE_SLOT(d, void _q_printerChanged(int))
155 Q_PRIVATE_SLOT(d, void _q_btnBrowseClicked())
156 Q_PRIVATE_SLOT(d, void _q_btnPropertiesClicked())
157};
158
160{
161public:
164
169// slots
173
176 Ui::QPrintWidget widget;
180
182
183#if QT_CONFIG(cups)
184 void setPpdDuplex(QPrinter::DuplexMode mode);
185 ppd_option_t *m_duplexPpdOption;
186#endif
187
188private:
189 QPrintDialogPrivate *optionsPane;
190 bool filePrintersAdded;
191};
192
194{
195 Q_DECLARE_PUBLIC(QPrintDialog)
197public:
200
201 void init();
202
203 void selectPrinter(const QPrinter::OutputFormat outputFormat);
204
205 void _q_togglePageSetCombo(bool);
206#if QT_CONFIG(messagebox)
207 void _q_checkFields();
208#endif
209 void _q_collapseOrExpandDialog();
210
211#if QT_CONFIG(cups)
212 void updatePpdDuplexOption(QRadioButton *radio);
213#endif
214 void setupPrinter();
215 void updateWidgets();
216
217 virtual void setTabs(const QList<QWidget*> &tabs) override;
218
219 Ui::QPrintSettingsOutput options;
225private:
226 void setExplicitDuplexMode(QPrint::DuplexMode duplexMode);
227 // duplex mode explicitly set by user, QPrint::DuplexAuto otherwise
228 QPrint::DuplexMode explicitDuplexMode;
229};
230
233
234/*
235
236 QPrintPropertiesDialog
237
238 Dialog displayed when clicking on Properties button to allow editing of Page
239 and Advanced tabs.
240
241*/
242
244 QPrinter::OutputFormat outputFormat, const QString &printerName,
246 : QDialog(parent)
247#if QT_CONFIG(cups)
248 , m_printer(printer)
249#endif
250{
251 setWindowTitle(tr("Printer Properties"));
252 QVBoxLayout *lay = new QVBoxLayout(this);
253 QWidget *content = new QWidget(this);
254 widget.setupUi(content);
256 lay->addWidget(content);
257 lay->addWidget(m_buttons);
258
261
262 widget.pageSetup->setPrinter(printer, currentPrintDevice, outputFormat, printerName);
263
264#if QT_CONFIG(cupsjobwidget)
265 m_jobOptions = new QCupsJobWidget(printer, currentPrintDevice);
266 widget.tabs->insertTab(1, m_jobOptions, tr("Job Options"));
267#endif
268
269 const int advancedTabIndex = widget.tabs->indexOf(widget.cupsPropertiesPage);
270#if QT_CONFIG(cups)
271 m_currentPrintDevice = currentPrintDevice;
272 const bool anyWidgetCreated = createAdvancedOptionsWidget();
273
274 widget.tabs->setTabEnabled(advancedTabIndex, anyWidgetCreated);
275
276 connect(widget.pageSetup, &QPageSetupWidget::ppdOptionChanged, this, [this] {
277 widget.conflictsLabel->setVisible(anyPpdOptionConflict());
278 });
279
280#else
281 Q_UNUSED(currentPrintDevice);
282 widget.tabs->setTabEnabled(advancedTabIndex, false);
283#endif
284}
285
289
291{
292#if QT_CONFIG(cups)
294#endif
295
296 widget.pageSetup->setupPrinter();
297#if QT_CONFIG(cupsjobwidget)
298 m_jobOptions->setupPrinter();
299#endif
300
301#if QT_CONFIG(cups)
302 // Set Color by default, that will change if the "ColorModel" property is available
303 m_printer->setColorMode(QPrinter::Color);
304
305 setPrinterAdvancedCupsOptions();
306#endif
307}
308
310{
311 widget.pageSetup->revertToSavedValues();
312
313#if QT_CONFIG(cupsjobwidget)
314 m_jobOptions->revertToSavedValues();
315#endif
316
317#if QT_CONFIG(cups)
318 revertAdvancedOptionsToSavedValues();
319#endif
321}
322
324{
325#if QT_CONFIG(cups) && QT_CONFIG(messagebox)
326 if (widget.pageSetup->hasPpdConflict()) {
327 widget.tabs->setCurrentWidget(widget.tabPage);
328 const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Page Setup Conflicts"),
329 tr("There are conflicts in page setup options. Do you want to fix them?"),
331 if (answer != QMessageBox::No)
332 return;
333 } else if (anyAdvancedOptionConflict()) {
334 widget.tabs->setCurrentWidget(widget.cupsPropertiesPage);
335 const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Advanced Option Conflicts"),
336 tr("There are conflicts in some advanced options. Do you want to fix them?"),
338 if (answer != QMessageBox::No)
339 return;
340 }
341 advancedOptionsUpdateSavedValues();
342#endif
343
344#if QT_CONFIG(cupsjobwidget)
345 m_jobOptions->updateSavedValues();
346#endif
347
348 widget.pageSetup->updateSavedValues();
349
351}
352
354{
355#if QT_CONFIG(cups)
356 widget.conflictsLabel->setVisible(anyPpdOptionConflict());
357#endif
359}
360
361#if QT_CONFIG(cups)
362
363// Used to store the ppd_option_t for each QComboBox that represents an advanced option
364static const char *ppdOptionProperty = "_q_ppd_option";
365
366// Used to store the originally selected choice index for each QComboBox that represents an advanced option
367static const char *ppdOriginallySelectedChoiceProperty = "_q_ppd_originally_selected_choice";
368
369// Used to store the warning label pointer for each QComboBox that represents an advanced option
370static const char *warningLabelProperty = "_q_warning_label";
371
372static bool isBlacklistedGroup(const ppd_group_t *group) noexcept
373{
374 return qstrcmp(group->name, "InstallableOptions") == 0;
375};
376
377static bool isBlacklistedOption(const char *keyword) noexcept
378{
379 // We already let the user set these options elsewhere
380 const char *cupsOptionBlacklist[] = {
381 "Collate",
382 "Copies",
383 "OutputOrder",
384 "PageRegion",
385 "PageSize",
386 "Duplex" // handled by the main dialog
387 };
388 auto equals = [](const char *keyword) {
389 return [keyword](const char *candidate) {
390 return qstrcmp(keyword, candidate) == 0;
391 };
392 };
393 return std::any_of(std::begin(cupsOptionBlacklist), std::end(cupsOptionBlacklist), equals(keyword));
394};
395
396bool QPrintPropertiesDialog::createAdvancedOptionsWidget()
397{
398 bool anyWidgetCreated = false;
399
400 ppd_file_t *ppd = qvariant_cast<ppd_file_t*>(m_currentPrintDevice->property(PDPK_PpdFile));
401
402 if (ppd) {
403 toUnicode = QStringDecoder(ppd->lang_encoding, QStringDecoder::Flag::Stateless);
404 if (!toUnicode.isValid()) {
405 qWarning() << "QPrinSupport: Cups uses unsupported encoding" << ppd->lang_encoding;
407 }
408
409 QWidget *holdingWidget = new QWidget();
410 QVBoxLayout *layout = new QVBoxLayout(holdingWidget);
411
412 for (int i = 0; i < ppd->num_groups; ++i) {
413 const ppd_group_t *group = &ppd->groups[i];
414
415 if (!isBlacklistedGroup(group)) {
416 QFormLayout *groupLayout = new QFormLayout();
417
418 for (int i = 0; i < group->num_options; ++i) {
419 const ppd_option_t *option = &group->options[i];
420
421 if (!isBlacklistedOption(option->keyword)) {
422 QComboBox *choicesCb = new QComboBox();
423
424 const auto setPpdOptionFromCombo = [this, choicesCb, option] {
425 // We can't use choicesCb->currentIndex() to know the index of the option in the choices[] array
426 // because some of them may not be present in the list because they conflict with the
427 // installable options so use the index passed on addItem
428 const int selectedChoiceIndex = choicesCb->currentData().toInt();
429 const auto values = QStringList{} << QString::fromLatin1(option->keyword)
430 << QString::fromLatin1(option->choices[selectedChoiceIndex].choice);
431 m_currentPrintDevice->setProperty(PDPK_PpdOption, values);
432 widget.conflictsLabel->setVisible(anyPpdOptionConflict());
433 };
434
435 bool foundMarkedChoice = false;
436 bool markedChoiceNotAvailable = false;
437 for (int i = 0; i < option->num_choices; ++i) {
438 const ppd_choice_t *choice = &option->choices[i];
439 const auto values = QStringList{} << QString::fromLatin1(option->keyword) << QString::fromLatin1(choice->choice);
440 const bool choiceIsInstallableConflict = m_currentPrintDevice->isFeatureAvailable(PDPK_PpdChoiceIsInstallableConflict, values);
441 if (choiceIsInstallableConflict && static_cast<int>(choice->marked) == 1) {
442 markedChoiceNotAvailable = true;
443 } else if (!choiceIsInstallableConflict) {
444 choicesCb->addItem(toUnicode(choice->text), i);
445 if (static_cast<int>(choice->marked) == 1) {
446 choicesCb->setCurrentIndex(choicesCb->count() - 1);
447 choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, QVariant(i));
448 foundMarkedChoice = true;
449 } else if (!foundMarkedChoice && qstrcmp(choice->choice, option->defchoice) == 0) {
450 choicesCb->setCurrentIndex(choicesCb->count() - 1);
451 choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, QVariant(i));
452 }
453 }
454 }
455
456 if (markedChoiceNotAvailable) {
457 // If the user default option is not available because of it conflicting with
458 // the installed options, we need to set the internal ppd value to the value
459 // being shown in the combo
460 setPpdOptionFromCombo();
461 }
462
463 if (choicesCb->count() > 1) {
464
465 connect(choicesCb, &QComboBox::currentIndexChanged, this, setPpdOptionFromCombo);
466
467 // We need an extra label at the end to show the conflict warning
468 QWidget *choicesCbWithLabel = new QWidget();
469 QHBoxLayout *choicesCbWithLabelLayout = new QHBoxLayout(choicesCbWithLabel);
470 choicesCbWithLabelLayout->setContentsMargins(0, 0, 0, 0);
471 QLabel *warningLabel = new QLabel();
472 choicesCbWithLabelLayout->addWidget(choicesCb);
473 choicesCbWithLabelLayout->addWidget(warningLabel);
474
475 QLabel *optionLabel = new QLabel(toUnicode(option->text));
476 groupLayout->addRow(optionLabel, choicesCbWithLabel);
477 anyWidgetCreated = true;
478 choicesCb->setProperty(ppdOptionProperty, QVariant::fromValue(option));
479 choicesCb->setProperty(warningLabelProperty, QVariant::fromValue(warningLabel));
480 m_advancedOptionsCombos << choicesCb;
481 } else {
482 delete choicesCb;
483 }
484 }
485 }
486
487 if (groupLayout->rowCount() > 0) {
488 QGroupBox *groupBox = new QGroupBox(toUnicode(group->text));
489 groupBox->setLayout(groupLayout);
491 } else {
492 delete groupLayout;
493 }
494 }
495 }
496
497 layout->addStretch();
498 widget.scrollArea->setWidget(holdingWidget);
499 }
500
501 return anyWidgetCreated;
502}
503
504void QPrintPropertiesDialog::setPrinterAdvancedCupsOptions() const
505{
506 for (const QComboBox *choicesCb : m_advancedOptionsCombos) {
507 const ppd_option_t *option = qvariant_cast<const ppd_option_t *>(choicesCb->property(ppdOptionProperty));
508
509 // We can't use choicesCb->currentIndex() to know the index of the option in the choices[] array
510 // because some of them may not be present in the list because they conflict with the
511 // installable options so use the index passed on addItem
512 const int selectedChoiceIndex = choicesCb->currentData().toInt();
513 const char *selectedChoice = option->choices[selectedChoiceIndex].choice;
514
515 if (qstrcmp(option->keyword, "ColorModel") == 0)
516 m_printer->setColorMode(qstrcmp(selectedChoice, "Gray") == 0 ? QPrinter::GrayScale : QPrinter::Color);
517
518 if (qstrcmp(option->defchoice, selectedChoice) != 0)
519 QCUPSSupport::setCupsOption(m_printer, QString::fromLatin1(option->keyword), QString::fromLatin1(selectedChoice));
520 }
521}
522
523void QPrintPropertiesDialog::revertAdvancedOptionsToSavedValues() const
524{
525 for (QComboBox *choicesCb : m_advancedOptionsCombos) {
526 const int originallySelectedChoice = qvariant_cast<int>(choicesCb->property(ppdOriginallySelectedChoiceProperty));
527 const int newComboIndexToSelect = choicesCb->findData(originallySelectedChoice);
528 choicesCb->setCurrentIndex(newComboIndexToSelect);
529 // The currentIndexChanged lambda takes care of resetting the ppd option
530 }
531 widget.conflictsLabel->setVisible(anyPpdOptionConflict());
532}
533
534void QPrintPropertiesDialog::advancedOptionsUpdateSavedValues() const
535{
536 for (QComboBox *choicesCb : m_advancedOptionsCombos)
537 choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, choicesCb->currentData());
538}
539
540bool QPrintPropertiesDialog::anyPpdOptionConflict() const
541{
542 // we need to execute both since besides returning true/false they update the warning icons
543 const bool pageSetupConflicts = widget.pageSetup->hasPpdConflict();
544 const bool advancedOptionConflicts = anyAdvancedOptionConflict();
545 return pageSetupConflicts || advancedOptionConflicts;
546}
547
548bool QPrintPropertiesDialog::anyAdvancedOptionConflict() const
549{
550 const QIcon warning = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr);
551
552 bool anyConflicted = false;
553
554 for (const QComboBox *choicesCb : m_advancedOptionsCombos) {
555 const ppd_option_t *option = qvariant_cast<const ppd_option_t *>(choicesCb->property(ppdOptionProperty));
556 QLabel *warningLabel = qvariant_cast<QLabel *>(choicesCb->property(warningLabelProperty));
557 if (option->conflicted) {
558 anyConflicted = true;
559 const int pixmap_size = choicesCb->sizeHint().height() * .75;
560 warningLabel->setPixmap(warning.pixmap(pixmap_size, pixmap_size));
561 } else {
562 warningLabel->setPixmap(QPixmap());
563 }
564 }
565
566 return anyConflicted;
567}
568
569#endif
570
571
574
575/*
576
577 QPrintDialogPrivate
578
579 The lower half of the Print Dialog containing the Copies and Options
580 tabs that expands when the Options button is selected.
581
582*/
584 : top(nullptr), bottom(nullptr), buttons(nullptr), collapseButton(nullptr),
585 explicitDuplexMode(QPrint::DuplexAuto)
586{
588}
589
593
595{
596 Q_Q(QPrintDialog);
597
598 top = new QUnixPrintWidget(q->printer(), q);
599 bottom = new QWidget(q);
600 options.setupUi(bottom);
601 options.color->setIconSize(QSize(32, 32));
602 options.color->setIcon(QIcon(":/qt-project.org/dialogs/qprintdialog/images/status-color.png"_L1));
603 options.grayscale->setIconSize(QSize(32, 32));
604 options.grayscale->setIcon(QIcon(":/qt-project.org/dialogs/qprintdialog/images/status-gray-scale.png"_L1));
605
606#if QT_CONFIG(cups)
607 // Add Page Set widget if CUPS is available
608 options.pageSetCombo->addItem(tr("All Pages"), QVariant::fromValue(QCUPSSupport::AllPages));
609 options.pageSetCombo->addItem(tr("Odd Pages"), QVariant::fromValue(QCUPSSupport::OddPages));
610 options.pageSetCombo->addItem(tr("Even Pages"), QVariant::fromValue(QCUPSSupport::EvenPages));
611#else
612 delete options.pagesRadioButton;
613 delete options.pagesLineEdit;
614 options.pagesRadioButton = nullptr;
615 options.pagesLineEdit = nullptr;
616#endif
617
618 top->d->setOptionsPane(this);
619
621 collapseButton = new QPushButton(QPrintDialog::tr("&Options >>"), buttons);
623 bottom->setVisible(false);
624
626 printButton->setText(QPrintDialog::tr("&Print"));
627 printButton->setDefault(true);
628
629 QVBoxLayout *lay = new QVBoxLayout(q);
630 lay->addWidget(top);
631 lay->addWidget(bottom);
632 lay->addWidget(buttons);
633
634#if !QT_CONFIG(messagebox)
635 QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(accept()));
636#else
637 QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(_q_checkFields()));
638#endif
639 QObject::connect(buttons, SIGNAL(rejected()), q, SLOT(reject()));
640
641 QObject::connect(options.printSelection, SIGNAL(toggled(bool)),
643
644 QObject::connect(options.printCurrentPage, SIGNAL(toggled(bool)),
646
648
649 QObject::connect(options.noDuplex, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexNone); });
650 QObject::connect(options.duplexLong, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexLongSide); });
651 QObject::connect(options.duplexShort, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexShortSide); });
652
653#if QT_CONFIG(cups)
654 QObject::connect(options.noDuplex, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.noDuplex); });
655 QObject::connect(options.duplexLong, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexLong); });
656 QObject::connect(options.duplexShort, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexShort); });
657#endif
658}
659
660// initialize printer options
662{
663 Q_Q(QPrintDialog);
664 QPrinter *p = q->printer();
665 printerOutputFormat = outputFormat;
666
667 // printer supports duplex mode?
668 const auto supportedDuplexMode = top->d->m_currentPrintDevice.supportedDuplexModes();
669 options.duplexLong->setEnabled(supportedDuplexMode.contains(QPrint::DuplexLongSide));
670 options.duplexShort->setEnabled(supportedDuplexMode.contains(QPrint::DuplexShortSide));
671
672 if (p->colorMode() == QPrinter::Color)
673 options.color->setChecked(true);
674 else
675 options.grayscale->setChecked(true);
676
677 // duplex priorities to be as follows:
678 // 1) a user-selected duplex value in the dialog has highest priority
679 // 2) duplex value set in the QPrinter
680 QPrint::DuplexMode duplex;
681 if (explicitDuplexMode != QPrint::DuplexAuto && supportedDuplexMode.contains(explicitDuplexMode))
682 duplex = explicitDuplexMode;
683 else
684 duplex = static_cast<QPrint::DuplexMode>(p->duplex());
685 switch (duplex) {
687 options.noDuplex->setChecked(true); break;
690 options.duplexLong->setChecked(true); break;
692 options.duplexShort->setChecked(true); break;
693 }
694 options.copies->setValue(p->copyCount());
695 options.collate->setChecked(p->collateCopies());
696 options.reverse->setChecked(p->pageOrder() == QPrinter::LastPageFirst);
697
698 if (outputFormat == QPrinter::PdfFormat || options.printSelection->isChecked()
699 || options.printCurrentPage->isChecked())
700
701 options.pageSetCombo->setEnabled(false);
702 else
703 options.pageSetCombo->setEnabled(true);
704
705#if QT_CONFIG(cups)
706 // Disable complex page ranges widget when printing to pdf
707 // It doesn't work since it relies on cups to do the heavy lifting and cups
708 // is not used when printing to PDF
709 options.pagesRadioButton->setEnabled(outputFormat != QPrinter::PdfFormat);
710
711 // Disable color options on main dialog if not printing to file, it will be handled by CUPS advanced dialog
712 options.colorMode->setVisible(outputFormat == QPrinter::PdfFormat);
713#endif
714}
715
716#if QT_CONFIG(cups)
717
718void QPrintDialogPrivate::updatePpdDuplexOption(QRadioButton *radio)
719{
720 const bool checked = radio->isChecked();
721 if (checked) {
722 if (radio == options.noDuplex) top->d->setPpdDuplex(QPrinter::DuplexNone);
723 else if (radio == options.duplexLong) top->d->setPpdDuplex(QPrinter::DuplexLongSide);
724 else if (radio == options.duplexShort) top->d->setPpdDuplex(QPrinter::DuplexShortSide);
725 }
726 const bool conflict = checked && top->d->m_duplexPpdOption && top->d->m_duplexPpdOption->conflicted;
727 radio->setIcon(conflict ? QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr) : QIcon());
728}
729
730#endif
731
732void QPrintDialogPrivate::setExplicitDuplexMode(const QPrint::DuplexMode duplexMode)
733{
734 explicitDuplexMode = duplexMode;
735}
736
738{
739 // First setup the requested OutputFormat, Printer and Page Size first
740 top->d->setupPrinter();
741
742 // Then setup Print Job options
743 Q_Q(QPrintDialog);
744 QPrinter* p = q->printer();
745
746 if (options.duplex->isEnabled()) {
747 if (options.noDuplex->isChecked())
749 else if (options.duplexLong->isChecked())
750 p->setDuplex(QPrinter::DuplexLongSide);
751 else
752 p->setDuplex(QPrinter::DuplexShortSide);
753 }
754
755#if QT_CONFIG(cups)
756 // When printing to a device the colorMode will be set by the advanced panel
757 if (p->outputFormat() == QPrinter::PdfFormat)
758#endif
759 p->setColorMode(options.color->isChecked() ? QPrinter::Color : QPrinter::GrayScale);
760
761 p->setPageOrder(options.reverse->isChecked() ? QPrinter::LastPageFirst : QPrinter::FirstPageFirst);
762
763 // print range
764 if (options.printAll->isChecked()) {
765 p->setPrintRange(QPrinter::AllPages);
766 p->setPageRanges(QPageRanges());
767 } else if (options.printSelection->isChecked()) {
768 p->setPrintRange(QPrinter::Selection);
769 p->setPageRanges(QPageRanges());
770 } else if (options.printCurrentPage->isChecked()) {
771 p->setPrintRange(QPrinter::CurrentPage);
772 p->setPageRanges(QPageRanges());
773 } else if (options.printRange->isChecked()) {
774 if (q->testOption(QPrintDialog::PrintPageRange)) {
775 p->setPrintRange(QPrinter::PageRange);
776 p->setFromTo(options.from->value(), qMax(options.from->value(), options.to->value()));
777 } else {
778 // This case happens when CUPS server-side page range is enabled
779 // Setting the range to the printer occurs below
780 p->setPrintRange(QPrinter::AllPages);
781 p->setPageRanges(QPageRanges());
782 }
783 }
784
785#if QT_CONFIG(cups)
786 if (options.pagesRadioButton->isChecked()) {
787 const QPageRanges ranges = QPageRanges::fromString(options.pagesLineEdit->text());
788 if (!ranges.isEmpty()) {
789 p->setPrintRange(QPrinter::PageRange);
790 p->setPageRanges(ranges);
791 }
792
793 // server-side page filtering
795 }
796
797 // page set
798 if (p->printRange() == QPrinter::AllPages || p->printRange() == QPrinter::PageRange) {
799 //If the application is selecting pages and the first page number is even then need to adjust the odd-even accordingly
800 QCUPSSupport::PageSet pageSet = qvariant_cast<QCUPSSupport::PageSet>(options.pageSetCombo->itemData(options.pageSetCombo->currentIndex()));
801 if (q->testOption(QPrintDialog::PrintPageRange)
802 && p->printRange() == QPrinter::PageRange
803 && (q->fromPage() % 2 == 0)) {
804
805 switch (pageSet) {
807 break;
810 break;
813 break;
814 }
815 } else if (pageSet != QCUPSSupport::AllPages) {
816 QCUPSSupport::setPageSet(p, pageSet);
817 }
818
819 // server-side page range, since we set the page range on the printer to 0-0/AllPages above,
820 // we need to take the values directly from the widget as q->fromPage() will return 0
821 if (!q->testOption(QPrintDialog::PrintPageRange) && options.printRange->isChecked())
822 QCUPSSupport::setPageRange(p, options.from->value(), qMax(options.from->value(), options.to->value()));
823 }
824#endif
825
826 // copies
827 p->setCopyCount(options.copies->value());
828 p->setCollateCopies(options.collate->isChecked());
829}
830
832{
834 return;
835
836 options.pageSetCombo->setDisabled(checked);
837}
838
840{
841 int collapseHeight = 0;
842 Q_Q(QPrintDialog);
843 QWidget *widgetToHide = bottom;
844 if (widgetToHide->isVisible()) {
845 collapseButton->setText(QPrintDialog::tr("&Options >>"));
846 collapseHeight = widgetToHide->y() + widgetToHide->height() - (top->y() + top->height());
847 }
848 else
849 collapseButton->setText(QPrintDialog::tr("&Options <<"));
850 widgetToHide->setVisible(! widgetToHide->isVisible());
851 if (! widgetToHide->isVisible()) { // make it shrink
852 q->layout()->activate();
853 q->resize( QSize(q->width(), q->height() - collapseHeight) );
854 }
855}
856
857#if QT_CONFIG(messagebox)
858void QPrintDialogPrivate::_q_checkFields()
859{
860 Q_Q(QPrintDialog);
861 if (top->d->checkFields())
862 q->accept();
863}
864#endif // QT_CONFIG(messagebox)
865
866
868{
869 Q_Q(QPrintDialog);
870 options.gbPrintRange->setVisible(q->testOption(QPrintDialog::PrintPageRange) ||
871 q->testOption(QPrintDialog::PrintSelection) ||
872 q->testOption(QPrintDialog::PrintCurrentPage));
873
874 options.printRange->setEnabled(q->testOption(QPrintDialog::PrintPageRange));
875 options.printSelection->setVisible(q->testOption(QPrintDialog::PrintSelection));
876 options.printCurrentPage->setVisible(q->testOption(QPrintDialog::PrintCurrentPage));
877 options.collate->setVisible(q->testOption(QPrintDialog::PrintCollateCopies));
878
879#if QT_CONFIG(cups)
880 // Don't display Page Set if only Selection or Current Page are enabled
881 if (!q->testOption(QPrintDialog::PrintPageRange)
882 && (q->testOption(QPrintDialog::PrintSelection) || q->testOption(QPrintDialog::PrintCurrentPage))) {
883 options.pageSetCombo->setVisible(false);
884 options.pageSetLabel->setVisible(false);
885 } else {
886 options.pageSetCombo->setVisible(true);
887 options.pageSetLabel->setVisible(true);
888 }
889
890 if (!q->testOption(QPrintDialog::PrintPageRange)) {
891 // If we can do CUPS server side pages selection,
892 // display the page range widgets
893 options.gbPrintRange->setVisible(true);
894 options.printRange->setEnabled(true);
895 }
896#endif
897
898 switch (q->printRange()) {
900 options.printAll->setChecked(true);
901 options.pageSetCombo->setEnabled(true);
902 break;
904 options.printSelection->setChecked(true);
905 options.pageSetCombo->setEnabled(false);
906 break;
908 options.printRange->setChecked(true);
909 options.pageSetCombo->setEnabled(true);
910 break;
912 if (q->testOption(QPrintDialog::PrintCurrentPage)) {
913 options.printCurrentPage->setChecked(true);
914 options.pageSetCombo->setEnabled(false);
915 }
916 break;
917 default:
918 break;
919 }
920 const int minPage = qMax(1, qMin(q->minPage() , q->maxPage()));
921 const int maxPage = qMax(1, q->maxPage() == INT_MAX ? 9999 : q->maxPage());
922
923 options.from->setMinimum(minPage);
924 options.to->setMinimum(minPage);
925 options.from->setMaximum(maxPage);
926 options.to->setMaximum(maxPage);
927
928 options.from->setValue(q->fromPage());
929 options.to->setValue(q->toPage());
930 top->d->updateWidget();
931}
932
933void QPrintDialogPrivate::setTabs(const QList<QWidget*> &tabWidgets)
934{
935 QList<QWidget*>::ConstIterator iter = tabWidgets.begin();
936 while(iter != tabWidgets.constEnd()) {
937 QWidget *tab = *iter;
938 options.tabs->addTab(tab, tab->windowTitle());
939 ++iter;
940 }
941}
942
945
946/*
947
948 QPrintDialog
949
950 The main Print Dialog.
951
952*/
953
955 : QAbstractPrintDialog(*(new QPrintDialogPrivate), printer, parent)
956{
957 Q_D(QPrintDialog);
958 d->init();
959}
960
966{
967 Q_D(QPrintDialog);
968 d->init();
969}
970
972{
973}
974
975void QPrintDialog::setVisible(bool visible)
976{
977 Q_D(QPrintDialog);
978
979 if (visible)
980 d->updateWidgets();
981
983}
984
986{
988}
989
991{
992 Q_D(QPrintDialog);
993#if QT_CONFIG(cups) && QT_CONFIG(messagebox)
994 if (d->options.pagesRadioButton->isChecked() && printer()->pageRanges().isEmpty()) {
995 QMessageBox::critical(this, tr("Invalid Pages Definition"),
996 tr("%1 does not follow the correct syntax. Please use ',' to separate "
997 "ranges and pages, '-' to define ranges and make sure ranges do "
998 "not intersect with each other.").arg(d->options.pagesLineEdit->text()),
1000 return;
1001 }
1002 if (d->top->d->m_duplexPpdOption && d->top->d->m_duplexPpdOption->conflicted) {
1003 const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Duplex Settings Conflicts"),
1004 tr("There are conflicts in duplex settings. Do you want to fix them?"),
1006 if (answer != QMessageBox::No)
1007 return;
1008 }
1009#endif
1010 d->setupPrinter();
1012}
1013
1016
1017/*
1018
1019 QUnixPrintWidget && QUnixPrintWidgetPrivate
1020
1021 The upper half of the Print Dialog containing the Printer Selection widgets
1022
1023*/
1024
1025#if defined (Q_OS_UNIX)
1026
1030 : parent(p), propertiesDialog(nullptr), printer(prn),
1031#if QT_CONFIG(cups)
1032 m_duplexPpdOption(nullptr),
1033#endif
1034 optionsPane(nullptr), filePrintersAdded(false)
1035{
1036 q = nullptr;
1037 if (parent)
1038 q = qobject_cast<QPrintDialog*> (parent->parent());
1039
1041
1042 int currentPrinterIndex = 0;
1044 if (ps) {
1045 const QStringList printers = ps->availablePrintDeviceIds();
1046 const QString defaultPrinter = ps->defaultPrintDeviceId();
1047
1048 widget.printers->addItems(printers);
1049
1050 const QString selectedPrinter = prn && !prn->printerName().isEmpty() ? prn->printerName() : defaultPrinter;
1051 const int idx = printers.indexOf(selectedPrinter);
1052
1053 if (idx >= 0)
1054 currentPrinterIndex = idx;
1055 }
1056 widget.properties->setEnabled(true);
1057
1058#if QT_CONFIG(filesystemmodel) && QT_CONFIG(completer)
1059 QFileSystemModel *fsm = new QFileSystemModel(widget.filename);
1060 fsm->setRootPath(QDir::homePath());
1061 widget.filename->setCompleter(new QCompleter(fsm, widget.filename));
1062#endif
1063 _q_printerChanged(currentPrinterIndex);
1064
1065 QObject::connect(widget.printers, SIGNAL(currentIndexChanged(int)),
1066 parent, SLOT(_q_printerChanged(int)));
1067 QObject::connect(widget.fileBrowser, SIGNAL(clicked()), parent, SLOT(_q_btnBrowseClicked()));
1068 QObject::connect(widget.properties, SIGNAL(clicked()), parent, SLOT(_q_btnPropertiesClicked()));
1069
1070 // disable features that QPrinter does not yet support.
1071 widget.preview->setVisible(false);
1072}
1073
1075{
1076 const bool printToFile = q == nullptr || q->testOption(QPrintDialog::PrintToFile);
1077 if (printToFile && !filePrintersAdded) {
1078 if (widget.printers->count())
1079 widget.printers->insertSeparator(widget.printers->count());
1080 widget.printers->addItem(QPrintDialog::tr("Print to File (PDF)"));
1081 filePrintersAdded = true;
1082 if (widget.printers->count() == 1)
1084 }
1085 if (!printToFile && filePrintersAdded) {
1086 widget.printers->removeItem(widget.printers->count()-1);
1087 widget.printers->removeItem(widget.printers->count()-1);
1088 if (widget.printers->count())
1089 widget.printers->removeItem(widget.printers->count()-1); // remove separator
1090 filePrintersAdded = false;
1091 }
1092 if (printer && filePrintersAdded && (printer->outputFormat() != QPrinter::NativeFormat
1093 || printer->printerName().isEmpty()))
1094 {
1096 widget.printers->setCurrentIndex(widget.printers->count() - 1);
1097 widget.filename->setEnabled(true);
1098 widget.lOutput->setEnabled(true);
1099 }
1100
1101 widget.filename->setVisible(printToFile);
1102 widget.lOutput->setVisible(printToFile);
1103 widget.fileBrowser->setVisible(printToFile);
1104
1105 if (q)
1106 widget.properties->setVisible(q->testOption(QAbstractPrintDialog::PrintShowPageSize));
1107}
1108
1110{
1111}
1112
1114{
1115 if (index < 0)
1116 return;
1117 const int printerCount = widget.printers->count();
1118 widget.filename->setEnabled(false);
1119 widget.lOutput->setEnabled(false);
1120
1121 // Reset properties dialog when printer is changed
1122 if (propertiesDialog){
1123 delete propertiesDialog;
1124 propertiesDialog = nullptr;
1125 }
1126
1127#if QT_CONFIG(cups)
1128 m_duplexPpdOption = nullptr;
1129#endif
1130
1131 if (filePrintersAdded) {
1132 Q_ASSERT(index != printerCount - 2); // separator
1133 if (index == printerCount - 1) { // PDF
1134 widget.location->setText(QPrintDialog::tr("Local file"));
1135 widget.type->setText(QPrintDialog::tr("Write PDF file"));
1136 widget.properties->setEnabled(true);
1137 widget.filename->setEnabled(true);
1138 QString filename = widget.filename->text();
1139 widget.filename->setText(filename);
1140 widget.lOutput->setEnabled(true);
1143 if (optionsPane)
1144 optionsPane->selectPrinter(QPrinter::PdfFormat);
1145 return;
1146 }
1147 }
1148
1149 if (printer) {
1151
1153 if (ps)
1154 m_currentPrintDevice = ps->createPrintDevice(widget.printers->itemText(index));
1155 else
1157
1159
1160 widget.location->setText(m_currentPrintDevice.location());
1161 widget.type->setText(m_currentPrintDevice.makeAndModel());
1162 if (optionsPane)
1164 }
1165
1166#if QT_CONFIG(cups)
1167 m_duplexPpdOption = QCUPSSupport::findPpdOption("Duplex", &m_currentPrintDevice);
1168#endif
1169}
1170
1172{
1173 optionsPane = pane;
1174 if (optionsPane)
1176}
1177
1179{
1180 QString filename = widget.filename->text();
1181#if QT_CONFIG(filedialog)
1182 filename = QFileDialog::getSaveFileName(parent, QPrintDialog::tr("Print To File ..."), filename,
1184#else
1185 filename.clear();
1186#endif
1187 if (!filename.isEmpty()) {
1188 widget.filename->setText(filename);
1189 widget.printers->setCurrentIndex(widget.printers->count() - 1); // the pdf one
1190 }
1191}
1192
1193#if QT_CONFIG(messagebox)
1195{
1196 if (widget.filename->isEnabled()) {
1197 QString file = widget.filename->text();
1198 QFile f(file);
1199 QFileInfo fi(f);
1200 bool exists = fi.exists();
1201 bool opened = false;
1202 if (exists && fi.isDir()) {
1203 QMessageBox::warning(q, q->windowTitle(),
1204 QPrintDialog::tr("%1 is a directory.\nPlease choose a different file name.").arg(file));
1205 return false;
1206 } else if ((exists && !fi.isWritable()) || !(opened = f.open(QFile::Append))) {
1207 QMessageBox::warning(q, q->windowTitle(),
1208 QPrintDialog::tr("File %1 is not writable.\nPlease choose a different file name.").arg(file));
1209 return false;
1210 } else if (exists) {
1211 int ret = QMessageBox::question(q, q->windowTitle(),
1212 QPrintDialog::tr("%1 already exists.\nDo you want to overwrite it?").arg(file),
1214 if (ret == QMessageBox::No)
1215 return false;
1216 }
1217 if (opened) {
1218 f.close();
1219 if (!exists)
1220 f.remove();
1221 }
1222 }
1223
1224#if QT_CONFIG(cups)
1225 if (propertiesDialog) {
1226 QCUPSSupport::PagesPerSheet pagesPerSheet = qvariant_cast<QCUPSSupport::PagesPerSheet>(propertiesDialog->widget.pageSetup->m_ui.pagesPerSheetCombo
1227 ->currentData());
1228
1229 QCUPSSupport::PageSet pageSet = qvariant_cast<QCUPSSupport::PageSet>(optionsPane->options.pageSetCombo->currentData());
1230
1231
1232 if (pagesPerSheet != QCUPSSupport::OnePagePerSheet
1233 && pageSet != QCUPSSupport::AllPages) {
1234 QMessageBox::warning(q, q->windowTitle(),
1235 QPrintDialog::tr("Options 'Pages Per Sheet' and 'Page Set' cannot be used together.\nPlease turn one of those options off."));
1236 return false;
1237 }
1238 }
1239#endif
1240
1241 // Every test passed. Accept the dialog.
1242 return true;
1243}
1244#endif // QT_CONFIG(messagebox)
1245
1247{
1248 delete propertiesDialog;
1249
1250 QPrinter::OutputFormat outputFormat;
1251 QString printerName;
1252
1253 if (q->testOption(QPrintDialog::PrintToFile)
1254 && (widget.printers->currentIndex() == widget.printers->count() - 1)) {// PDF
1255 outputFormat = QPrinter::PdfFormat;
1256 } else {
1257 outputFormat = QPrinter::NativeFormat;
1258 printerName = widget.printers->currentText();
1259 }
1260
1261 propertiesDialog = new QPrintPropertiesDialog(q->printer(), &m_currentPrintDevice, outputFormat, printerName, q);
1262}
1263
1264#if QT_CONFIG(cups)
1265void QUnixPrintWidgetPrivate::setPpdDuplex(QPrinter::DuplexMode mode)
1266{
1267 auto values = QStringList{} << QStringLiteral("Duplex");
1269 else if (mode == QPrinter::DuplexLongSide) values << QStringLiteral("DuplexNoTumble");
1270 else if (mode == QPrinter::DuplexShortSide) values << QStringLiteral("DuplexTumble");
1271
1273}
1274#endif
1275
1277{
1278 if (!propertiesDialog)
1281
1282#if QT_CONFIG(cups)
1283 // update the warning icon on the duplex options if needed
1284 optionsPane->updatePpdDuplexOption(optionsPane->options.noDuplex);
1285 optionsPane->updatePpdDuplexOption(optionsPane->options.duplexLong);
1286 optionsPane->updatePpdDuplexOption(optionsPane->options.duplexShort);
1287#endif
1288}
1289
1291{
1292 const int printerCount = widget.printers->count();
1293 const int index = widget.printers->currentIndex();
1294
1295 if (filePrintersAdded && index == printerCount - 1) { // PDF
1297 Q_ASSERT(index != printerCount - 2); // separator
1299 QString path = widget.filename->text();
1303 }
1304 else {
1305 printer->setPrinterName(widget.printers->currentText());
1307 }
1308
1309 if (!propertiesDialog)
1311
1313}
1314
1318 : QWidget(parent), d(new QUnixPrintWidgetPrivate(this, printer))
1319{
1320 if (printer == nullptr)
1321 return;
1322 if (printer->outputFileName().isEmpty()) {
1323 QString home = QDir::homePath();
1324 QString cur = QDir::currentPath();
1325 if (!home.endsWith(u'/'))
1326 home += u'/';
1327 if (!cur.startsWith(home))
1328 cur = home;
1329 else if (!cur.endsWith(u'/'))
1330 cur += u'/';
1331 if (QGuiApplication::platformName() == "xcb"_L1) {
1332 if (printer->docName().isEmpty()) {
1333 cur += "print.pdf"_L1;
1334 } else {
1335#if QT_CONFIG(regularexpression)
1336 const QRegularExpression re(QStringLiteral("(.*)\\.\\S+"));
1337 auto match = re.match(printer->docName());
1338 if (match.hasMatch())
1339 cur += match.captured(1);
1340 else
1341#endif
1342 cur += printer->docName();
1343 cur += ".pdf"_L1;
1344 }
1345 } // xcb
1346
1347 d->widget.filename->setText(cur);
1348 }
1349 else
1350 d->widget.filename->setText(printer->outputFileName());
1351 const QString printerName = printer->printerName();
1352 if (!printerName.isEmpty()) {
1353 const int i = d->widget.printers->findText(printerName);
1354 if (i >= 0)
1355 d->widget.printers->setCurrentIndex(i);
1356 }
1357 // PDF printer not added to the dialog yet, we'll handle those cases in QUnixPrintWidgetPrivate::updateWidget
1358}
1359
1363{
1364 delete d;
1365}
1366
1372{
1373 d->setupPrinter();
1374}
1375
1376#if QT_CONFIG(cups)
1377
1380
1381#endif // QT_CONFIG(cups)
1382#endif // defined (Q_OS_UNIX)
1383
1385
1386#include "moc_qprintdialog.cpp"
1387#include "qprintdialog_unix.moc"
void setIcon(const QIcon &icon)
void clicked(bool checked=false)
This signal is emitted when the button is activated (i.e., pressed down then released while the mouse...
void toggled(bool checked)
This signal is emitted whenever a checkable button changes its state.
void setText(const QString &text)
bool isChecked() const
The QAbstractPrintDialog class provides a base implementation for print dialogs used to configure pri...
QPrinter * printer() const
Returns the printer that this printer dialog operates on.
static QStyle * style()
Returns the application's style object.
@ OnePagePerSheet
Definition qcups_p.h:80
static void setPageSet(QPrinter *printer, const PageSet pageSet)
Definition qcups.cpp:215
static void setCupsOption(QPrinter *printer, const QString &option, const QString &value)
static void clearCupsOptions(QPrinter *printer)
Definition qcups.cpp:57
static ppd_option_t * findPpdOption(const char *optionName, QPrintDevice *printDevice)
Definition qcups.cpp:125
static void setPageRange(QPrinter *printer, int pageFrom, int pageTo)
Definition qcups.cpp:246
The QComboBox widget combines a button with a dropdown list.
Definition qcombobox.h:24
void currentIndexChanged(int index)
The QCompleter class provides completions based on an item model.
Definition qcompleter.h:24
The QDialogButtonBox class is a widget that presents buttons in a layout that is appropriate to the c...
void addButton(QAbstractButton *button, ButtonRole role)
Adds the given button to the button box with the specified role.
QPushButton * button(StandardButton which) const
Returns the QPushButton corresponding to the standard button which, or \nullptr if the standard butto...
The QDialog class is the base class of dialog windows.
Definition qdialog.h:19
virtual void reject()
Hides the modal dialog and sets the result code to Rejected.
Definition qdialog.cpp:639
virtual int exec()
Shows the dialog as a \l{QDialog::Modal Dialogs}{modal dialog}, blocking until the user closes it.
Definition qdialog.cpp:543
void showEvent(QShowEvent *) override
\reimp
Definition qdialog.cpp:853
void setVisible(bool visible) override
\reimp
Definition qdialog.cpp:744
virtual void accept()
Hides the modal dialog and sets the result code to Accepted.
Definition qdialog.cpp:628
static bool isRelativePath(const QString &path)
Returns true if path is relative; returns false if it is absolute.
Definition qdir.cpp:2412
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
Definition qdir.h:209
static QString homePath()
Returns the absolute path of the user's home directory.
Definition qdir.cpp:2103
static QString currentPath()
Returns the absolute path of the application's current directory.
Definition qdir.cpp:2054
static QString getSaveFileName(QWidget *parent=nullptr, const QString &caption=QString(), const QString &dir=QString(), const QString &filter=QString(), QString *selectedFilter=nullptr, Options options=Options())
This is a convenience static function that returns a file name selected by the user.
@ DontConfirmOverwrite
Definition qfiledialog.h:51
The QFileSystemModel class provides a data model for the local filesystem.
\inmodule QtCore
Definition qfile.h:93
The QFormLayout class manages forms of input widgets and their associated labels.
Definition qformlayout.h:18
The QGroupBox widget provides a group box frame with a title.
Definition qgroupbox.h:17
QString platformName
The name of the underlying platform plugin.
The QHBoxLayout class lines up widgets horizontally.
Definition qboxlayout.h:78
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:20
The QLabel widget provides a text or image display.
Definition qlabel.h:20
void addWidget(QWidget *w)
Adds widget w to this layout in a manner specific to the layout.
Definition qlayout.cpp:186
static StandardButton warning(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons=Ok, StandardButton defaultButton=NoButton)
static StandardButton critical(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons=Ok, StandardButton defaultButton=NoButton)
static StandardButton question(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons=StandardButtons(Yes|No), StandardButton defaultButton=NoButton)
QObject * parent
Definition qobject.h:73
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
friend class QWidget
Definition qobject.h:382
The QPageRanges class represents a collection of page ranges.
Definition qpageranges.h:21
bool isEmpty() const
Returns true if the ranges are empty; otherwise returns false.
static QPageRanges fromString(const QString &ranges)
Constructs and returns a QPageRanges object populated with the ranges from the string representation.
QString toString() const
Returns the string representation of the page ranges.
QPagedPaintDevicePrivate * d
static QPlatformPrinterSupport * get()
The QPlatformPrinterSupport class provides an abstraction for print support.
virtual QString defaultPrintDeviceId() const
virtual QPrintDevice createPrintDevice(const QString &id)
virtual QStringList availablePrintDeviceIds() const
QString makeAndModel() const
bool setProperty(PrintDevicePropertyKey key, const QVariant &value)
QString location() const
QString id() const
QUnixPrintWidget * top
void selectPrinter(const QPrinter::OutputFormat outputFormat)
virtual void setTabs(const QList< QWidget * > &tabs) override
Ui::QPrintSettingsOutput options
QPrinter::OutputFormat printerOutputFormat
QDialogButtonBox * buttons
The QPrintDialog class provides a dialog for specifying the printer's configuration.
int exec() override
\reimp
~QPrintDialog()
Destroys the print dialog.
QPrintDialog(QPrinter *printer, QWidget *parent=nullptr)
Constructs a new modal printer dialog for the given printer with the given parent.
QPrintPropertiesDialog(QPrinter *printer, QPrintDevice *currentPrintDevice, QPrinter::OutputFormat outputFormat, const QString &printerName, QAbstractPrintDialog *parent)
void showEvent(QShowEvent *event) override
\reimp
\reentrant
Definition qprinter.h:28
@ DuplexLongSide
Definition qprinter.h:87
@ DuplexNone
Definition qprinter.h:85
@ DuplexShortSide
Definition qprinter.h:88
OutputFormat
The OutputFormat enum is used to describe the format QPrinter should use for printing.
Definition qprinter.h:69
@ NativeFormat
Definition qprinter.h:69
@ PdfFormat
Definition qprinter.h:69
void setOutputFormat(OutputFormat format)
Definition qprinter.cpp:549
@ GrayScale
Definition qprinter.h:42
QString docName() const
Returns the document name.
Definition qprinter.cpp:772
void setDuplex(DuplexMode duplex)
QString outputFileName() const
Returns the name of the output file.
Definition qprinter.cpp:692
void setOutputFileName(const QString &)
Sets the name of the output file to fileName.
Definition qprinter.cpp:717
QString printerName() const
Returns the printer name.
Definition qprinter.cpp:621
@ LastPageFirst
Definition qprinter.h:40
@ FirstPageFirst
Definition qprinter.h:39
@ CurrentPage
Definition qprinter.h:72
@ Selection
Definition qprinter.h:72
@ PageRange
Definition qprinter.h:72
@ AllPages
Definition qprinter.h:72
OutputFormat outputFormat() const
Definition qprinter.cpp:570
void setPrinterName(const QString &)
Sets the printer name to name.
Definition qprinter.cpp:638
The QPushButton widget provides a command button.
Definition qpushbutton.h:20
The QRadioButton widget provides a radio button with a text label.
\inmodule QtCore \reentrant
The QShowEvent class provides an event that is sent when a widget is shown.
Definition qevent.h:578
\inmodule QtCore
Definition qsize.h:25
\inmodule QtCore
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4517
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1252
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5506
@ SP_MessageBoxWarning
Definition qstyle.h:727
QUnixPrintWidgetPrivate(QUnixPrintWidget *q, QPrinter *prn)
QPrintPropertiesDialog * propertiesDialog
void _q_printerChanged(int index)
QUnixPrintWidget *const parent
void setOptionsPane(QPrintDialogPrivate *pane)
QUnixPrintWidget(QPrinter *printer, QWidget *parent=nullptr)
The QVBoxLayout class lines up widgets vertically.
Definition qboxlayout.h:91
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
void setLayout(QLayout *)
Sets the layout manager for this widget to layout.
void setEnabled(bool)
Definition qwidget.cpp:3358
QLayout * layout() const
Returns the layout manager that is installed on this widget, or \nullptr if no layout manager is inst...
setupUi(QWidget *widget)
\macro QWIDGETSIZE_MAX
virtual void setVisible(bool visible)
Definition qwidget.cpp:8255
friend class QPixmap
Definition qwidget.h:748
void setWindowTitle(const QString &)
Definition qwidget.cpp:6105
QString windowTitle
the window title (caption)
Definition qwidget.h:151
bool visible
whether the widget is visible
Definition qwidget.h:144
QPushButton
[1]
#define this
Definition dialogs.cpp:9
QOpenGLWidget * widget
[1]
DuplexMode
Definition qprint_p.h:64
@ DuplexLongSide
Definition qprint_p.h:67
@ DuplexShortSide
Definition qprint_p.h:68
@ DuplexNone
Definition qprint_p.h:65
@ DuplexAuto
Definition qprint_p.h:66
Combined button and popup list for selecting options.
@ Horizontal
Definition qnamespace.h:99
Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2)
#define Q_DECLARE_TR_FUNCTIONS(context)
#define PDPK_PpdFile
Definition qcups_p.h:37
#define PDPK_PpdChoiceIsInstallableConflict
Definition qcups_p.h:43
#define PDPK_PpdOption
Definition qcups_p.h:38
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
#define qWarning
Definition qlogging.h:166
return ret
#define Q_DECLARE_METATYPE(TYPE)
Definition qmetatype.h:1525
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
Qt::MouseButtons m_buttons
Definition qnsview.mm:102
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLenum GLsizei GLsizei GLint * values
[15]
GLenum mode
GLuint index
[2]
GLdouble GLdouble GLdouble GLdouble top
GLfloat GLfloat f
GLboolean GLuint group
GLint GLint bottom
struct _cl_event * event
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLsizei const GLchar *const * path
GLfloat GLfloat p
[1]
GLuint GLenum option
static void _q_pdu_initResources()
QDebug warning(QAnyStringView fileName, int lineNumber)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
#define QStringLiteral(str)
#define QT_CONFIG(feature)
#define tr(X)
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define Q_OBJECT
#define slots
#define Q_PRIVATE_SLOT(d, signature)
#define Q_UNUSED(x)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
#define Q_INIT_RESOURCE(name)
Definition qtresource.h:14
if(qFloatDistance(a, b)<(1<< 7))
[0]
QFile file
[0]
QObject::connect nullptr
args<< 1<< 2;QJSValue threeAgain=fun.call(args);QString fileName="helloworld.qs";QFile scriptFile(fileName);if(!scriptFile.open(QIODevice::ReadOnly)) QTextStream stream(&scriptFile);QString contents=stream.readAll();scriptFile.close();myEngine.evaluate(contents, fileName);myEngine.globalObject().setProperty("myNumber", 123);...QJSValue myNumberPlusOne=myEngine.evaluate("myNumber + 1");QJSValue result=myEngine.evaluate(...);if(result.isError()) qDebug()<< "Uncaught exception at line"<< result.property("lineNumber").toInt()<< ":"<< result.toString();QPushButton *button=new QPushButton;QJSValue scriptButton=myEngine.newQObject(button);myEngine.globalObject().setProperty("button", scriptButton);myEngine.evaluate("button.checkable = true");qDebug()<< scriptButton.property("checkable").toBool();scriptButton.property("show").call();QJSEngine engine;QObject *myQObject=new QObject();myQObject- setProperty)("dynamicProperty", 3)