1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qplatformdefs.h"
44 #ifndef QT_NO_PRINTDIALOG
46 #include "private/qabstractprintdialog_p.h"
47 #include <QtWidgets/qmessagebox.h>
48 #include "qprintdialog.h"
49 #include "qfiledialog.h"
50 #include <QtCore/qdir.h>
51 #include <QtGui/qevent.h>
52 #include <QtWidgets/qfilesystemmodel.h>
53 #include <QtWidgets/qstyleditemdelegate.h>
54 #include <QtPrintSupport/qprinter.h>
55 #include <private/qprintengine_pdf_p.h>
57 #include <QtWidgets/qdialogbuttonbox.h>
59 #include "private/qfscompleter_p.h"
60 #include "ui_qprintpropertieswidget.h"
61 #include "ui_qprintsettingsoutput.h"
62 #include "ui_qprintwidget.h"
64 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
65 # include <private/qcups_p.h>
67 # include <QtCore/qlibrary.h>
68 # include <private/qprintengine_pdf_p.h>
73 Print dialog class declarations
75 QPrintDialog: The main Print Dialog, nothing really held here.
78 QUnixPrintWidgetPrivate: The real Unix Print Dialog implementation.
80 Directly includes the upper half of the Print Dialog
81 containing the Printer Selection widgets and
84 Embeds the Properties pop-up dialog from
85 QPrintPropertiesDialog
87 Embeds the lower half from separate widget class
90 Layout in qprintwidget.ui
92 QPrintDialogPrivate: The lower half of the Print Dialog containing the
93 Copies and Options tabs that expands when the
94 Options button is selected.
96 Layout in qprintsettingsoutput.ui
98 QPrintPropertiesDialog: Dialog displayed when clicking on Properties button to
99 allow editing of Page and Advanced tabs.
101 Layout in qprintpropertieswidget.ui
103 QPPDOptionsModel: Holds the PPD Options for the printer.
105 QPPDOptionsEditor: Edits the PPD Options for the printer.
111 class QOptionTreeItem;
112 class QPPDOptionsModel;
114 class QPrintPropertiesDialog : public QDialog
118 QPrintPropertiesDialog(QAbstractPrintDialog *parent = 0);
119 ~QPrintPropertiesDialog();
121 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
122 void setCups(QCUPSSupport *cups) { m_cups = cups; }
123 void addItemToOptions(QOptionTreeItem *parent, QList<const ppd_option_t*>& options, QList<const char*>& markedOptions) const;
126 void selectPrinter();
127 void selectPdfPsPrinter(const QPrinter *p);
129 /// copy printer properties to the widget
130 void applyPrinterProperties(QPrinter *p);
131 void setupPrinter() const;
134 void showEvent(QShowEvent* event);
137 Ui::QPrintPropertiesWidget widget;
138 QDialogButtonBox *m_buttons;
139 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
140 QCUPSSupport *m_cups;
141 QPPDOptionsModel *m_cupsOptionsModel;
145 class QUnixPrintWidgetPrivate;
147 class QUnixPrintWidget : public QWidget
152 explicit QUnixPrintWidget(QPrinter *printer, QWidget *parent = 0);
154 void updatePrinter();
157 friend class QPrintDialogPrivate;
158 friend class QUnixPrintWidgetPrivate;
159 QUnixPrintWidgetPrivate *d;
160 Q_PRIVATE_SLOT(d, void _q_printerChanged(int))
161 Q_PRIVATE_SLOT(d, void _q_btnBrowseClicked())
162 Q_PRIVATE_SLOT(d, void _q_btnPropertiesClicked())
165 class QUnixPrintWidgetPrivate
168 QUnixPrintWidgetPrivate(QUnixPrintWidget *q);
169 ~QUnixPrintWidgetPrivate();
171 /// copy printer properties to the widget
172 void applyPrinterProperties(QPrinter *p);
175 void setOptionsPane(QPrintDialogPrivate *pane);
176 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
177 void setCupsProperties();
181 void _q_printerChanged(int index);
182 void _q_btnPropertiesClicked();
183 void _q_btnBrowseClicked();
185 QUnixPrintWidget * const parent;
186 QPrintPropertiesDialog *propertiesDialog;
187 Ui::QPrintWidget widget;
188 QAbstractPrintDialog * q;
193 QPrintDialogPrivate *optionsPane;
194 bool filePrintersAdded;
195 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
197 int cupsPrinterCount;
198 const cups_dest_t* cupsPrinters;
199 const ppd_file_t* cupsPPD;
203 class QPrintDialogPrivate : public QAbstractPrintDialogPrivate
205 Q_DECLARE_PUBLIC(QPrintDialog)
206 Q_DECLARE_TR_FUNCTIONS(QPrintDialog)
208 QPrintDialogPrivate();
209 ~QPrintDialogPrivate();
212 /// copy printer properties to the widget
213 void applyPrinterProperties(QPrinter *p);
215 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
216 void selectPrinter(QCUPSSupport *cups);
219 void _q_chbPrintLastFirstToggled(bool);
220 #ifndef QT_NO_MESSAGEBOX
221 void _q_checkFields();
223 void _q_collapseOrExpandDialog();
226 void updateWidgets();
228 virtual void setTabs(const QList<QWidget*> &tabs);
230 Ui::QPrintSettingsOutput options;
231 QUnixPrintWidget *top;
233 QDialogButtonBox *buttons;
234 QPushButton *collapseButton;
237 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
238 class QOptionTreeItem
241 enum ItemType { Root, Group, Option, Choice };
243 QOptionTreeItem(ItemType t, int i, const void* p, const char* desc, QOptionTreeItem* pi)
253 while (!childItems.isEmpty())
254 delete childItems.takeFirst();
260 const char* description;
262 const char* selDescription;
263 QOptionTreeItem* parentItem;
264 QList<QOptionTreeItem*> childItems;
267 class QPPDOptionsModel : public QAbstractItemModel
269 friend class QPPDOptionsEditor;
271 QPPDOptionsModel(QCUPSSupport *cups, QObject *parent = 0);
274 int columnCount(const QModelIndex& parent = QModelIndex()) const;
275 int rowCount(const QModelIndex& parent = QModelIndex()) const;
276 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
277 QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
278 QModelIndex parent(const QModelIndex& index) const;
279 Qt::ItemFlags flags(const QModelIndex& index) const;
280 QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
282 QOptionTreeItem* rootItem;
284 const ppd_file_t* ppd;
286 void parseGroups(QOptionTreeItem* parent);
287 void parseOptions(QOptionTreeItem* parent);
288 void parseChoices(QOptionTreeItem* parent);
291 class QPPDOptionsEditor : public QStyledItemDelegate
295 QPPDOptionsEditor(QObject* parent = 0) : QStyledItemDelegate(parent) {}
296 ~QPPDOptionsEditor() {}
298 QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
299 void setEditorData(QWidget* editor, const QModelIndex& index) const;
300 void setModelData( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
303 void cbChanged(int index);
309 ////////////////////////////////////////////////////////////////////////////////
310 ////////////////////////////////////////////////////////////////////////////////
314 QPrintPropertiesDialog
316 Dialog displayed when clicking on Properties button to allow editing of Page
321 QPrintPropertiesDialog::QPrintPropertiesDialog(QAbstractPrintDialog *parent)
323 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
324 , m_cups(0), m_cupsOptionsModel(0)
327 QVBoxLayout *lay = new QVBoxLayout(this);
328 this->setLayout(lay);
329 QWidget *content = new QWidget(this);
330 widget.setupUi(content);
331 m_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
332 lay->addWidget(content);
333 lay->addWidget(m_buttons);
335 connect(m_buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept()));
336 connect(m_buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject()));
339 QPrintPropertiesDialog::~QPrintPropertiesDialog()
341 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
342 delete m_cupsOptionsModel;
344 delete widget.cupsPropertiesPage;
348 void QPrintPropertiesDialog::applyPrinterProperties(QPrinter *p)
350 widget.pageSetup->setPrinter(p);
353 void QPrintPropertiesDialog::setupPrinter() const
355 widget.pageSetup->setupPrinter();
357 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
358 QPPDOptionsModel* model = static_cast<QPPDOptionsModel*>(widget.treeView->model());
360 QOptionTreeItem* rootItem = model->rootItem;
361 QList<const ppd_option_t*> options;
362 QList<const char*> markedOptions;
364 addItemToOptions(rootItem, options, markedOptions);
365 model->cups->saveOptions(options, markedOptions);
370 void QPrintPropertiesDialog::selectPrinter()
372 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
373 widget.pageSetup->selectPrinter(m_cups);
374 widget.treeView->setModel(0);
375 if (m_cups && QCUPSSupport::isAvailable()) {
377 if (m_cupsOptionsModel == 0) {
378 m_cupsOptionsModel = new QPPDOptionsModel(m_cups);
380 widget.treeView->setItemDelegate(new QPPDOptionsEditor(this));
383 m_cupsOptionsModel->parseItems();
386 if (m_cupsOptionsModel->rowCount() > 0) {
387 widget.treeView->setModel(m_cupsOptionsModel);
389 for (int i = 0; i < m_cupsOptionsModel->rowCount(); ++i)
390 widget.treeView->expand(m_cupsOptionsModel->index(i,0));
392 widget.tabs->setTabEnabled(1, true); // enable the advanced tab
394 widget.tabs->setTabEnabled(1, false);
400 widget.cupsPropertiesPage->setEnabled(false);
401 widget.pageSetup->selectPrinter(0);
405 void QPrintPropertiesDialog::selectPdfPsPrinter(const QPrinter *p)
407 widget.treeView->setModel(0);
408 widget.pageSetup->selectPdfPsPrinter(p);
409 widget.tabs->setTabEnabled(1, false); // disable the advanced tab
412 void QPrintPropertiesDialog::showEvent(QShowEvent* event)
414 widget.treeView->resizeColumnToContents(0);
418 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
419 void QPrintPropertiesDialog::addItemToOptions(QOptionTreeItem *parent, QList<const ppd_option_t*>& options, QList<const char*>& markedOptions) const
421 for (int i = 0; i < parent->childItems.count(); ++i) {
422 QOptionTreeItem *itm = parent->childItems.at(i);
423 if (itm->type == QOptionTreeItem::Option) {
424 const ppd_option_t* opt = reinterpret_cast<const ppd_option_t*>(itm->ptr);
426 if (qstrcmp(opt->defchoice, opt->choices[itm->selected].choice) != 0) {
427 markedOptions << opt->keyword << opt->choices[itm->selected].choice;
430 addItemToOptions(itm, options, markedOptions);
436 ////////////////////////////////////////////////////////////////////////////////
437 ////////////////////////////////////////////////////////////////////////////////
443 The lower half of the Print Dialog containing the Copies and Options
444 tabs that expands when the Options button is selected.
448 QPrintDialogPrivate::QPrintDialogPrivate()
449 : top(0), bottom(0), buttons(0), collapseButton(0)
453 QPrintDialogPrivate::~QPrintDialogPrivate()
457 void QPrintDialogPrivate::init()
461 top = new QUnixPrintWidget(0, q);
462 bottom = new QWidget(q);
463 options.setupUi(bottom);
464 options.color->setIconSize(QSize(32, 32));
465 options.color->setIcon(QIcon(QLatin1String(":/qt-project.org/dialogs/qprintdialog/images/status-color.png")));
466 options.grayscale->setIconSize(QSize(32, 32));
467 options.grayscale->setIcon(QIcon(QLatin1String(":/qt-project.org/dialogs/qprintdialog/images/status-gray-scale.png")));
468 top->d->setOptionsPane(this);
470 buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, q);
471 collapseButton = new QPushButton(QPrintDialog::tr("&Options >>"), buttons);
472 buttons->addButton(collapseButton, QDialogButtonBox::ResetRole);
473 bottom->setVisible(false);
475 QPushButton *printButton = buttons->button(QDialogButtonBox::Ok);
476 printButton->setText(QPrintDialog::tr("&Print"));
477 printButton->setDefault(true);
479 QVBoxLayout *lay = new QVBoxLayout(q);
482 lay->addWidget(bottom);
483 lay->addWidget(buttons);
485 QPrinter* p = q->printer();
487 applyPrinterProperties(p);
489 #ifdef QT_NO_MESSAGEBOX
490 QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(accept()));
492 QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(_q_checkFields()));
494 QObject::connect(buttons, SIGNAL(rejected()), q, SLOT(reject()));
496 QObject::connect(options.reverse, SIGNAL(toggled(bool)),
497 q, SLOT(_q_chbPrintLastFirstToggled(bool)));
499 QObject::connect(collapseButton, SIGNAL(released()), q, SLOT(_q_collapseOrExpandDialog()));
502 void QPrintDialogPrivate::applyPrinterProperties(QPrinter *p)
504 if (p->colorMode() == QPrinter::Color)
505 options.color->setChecked(true);
507 options.grayscale->setChecked(true);
509 switch(p->duplex()) {
510 case QPrinter::DuplexNone:
511 options.noDuplex->setChecked(true); break;
512 case QPrinter::DuplexLongSide:
513 case QPrinter::DuplexAuto:
514 options.duplexLong->setChecked(true); break;
515 case QPrinter::DuplexShortSide:
516 options.duplexShort->setChecked(true); break;
518 options.copies->setValue(p->copyCount());
519 options.collate->setChecked(p->collateCopies());
520 options.reverse->setChecked(p->pageOrder() == QPrinter::LastPageFirst);
521 top->d->applyPrinterProperties(p);
524 void QPrintDialogPrivate::_q_chbPrintLastFirstToggled(bool checked)
528 q->printer()->setPageOrder(QPrinter::LastPageFirst);
530 q->printer()->setPageOrder(QPrinter::FirstPageFirst);
533 void QPrintDialogPrivate::_q_collapseOrExpandDialog()
535 int collapseHeight = 0;
537 QWidget *widgetToHide = bottom;
538 if (widgetToHide->isVisible()) {
539 collapseButton->setText(QPrintDialog::tr("&Options >>"));
540 collapseHeight = widgetToHide->y() + widgetToHide->height() - (top->y() + top->height());
543 collapseButton->setText(QPrintDialog::tr("&Options <<"));
544 widgetToHide->setVisible(! widgetToHide->isVisible());
545 if (! widgetToHide->isVisible()) { // make it shrink
546 q->layout()->activate();
547 q->resize( QSize(q->width(), q->height() - collapseHeight) );
551 #ifndef QT_NO_MESSAGEBOX
552 void QPrintDialogPrivate::_q_checkFields()
555 if (top->d->checkFields())
558 #endif // QT_NO_MESSAGEBOX
560 void QPrintDialogPrivate::setupPrinter()
563 QPrinter* p = q->printer();
565 if (options.duplex->isEnabled()) {
566 if (options.noDuplex->isChecked())
567 p->setDuplex(QPrinter::DuplexNone);
568 else if (options.duplexLong->isChecked())
569 p->setDuplex(QPrinter::DuplexLongSide);
571 p->setDuplex(QPrinter::DuplexShortSide);
574 p->setColorMode( options.color->isChecked() ? QPrinter::Color : QPrinter::GrayScale );
577 if (options.printAll->isChecked()) {
578 p->setPrintRange(QPrinter::AllPages);
580 } else if (options.printSelection->isChecked()) {
581 p->setPrintRange(QPrinter::Selection);
583 } else if (options.printCurrentPage->isChecked()) {
584 p->setPrintRange(QPrinter::CurrentPage);
586 } else if (options.printRange->isChecked()) {
587 p->setPrintRange(QPrinter::PageRange);
588 p->setFromTo(options.from->value(), qMax(options.from->value(), options.to->value()));
592 p->setCopyCount(options.copies->value());
593 p->setCollateCopies(options.collate->isChecked());
595 top->d->setupPrinter();
598 void QPrintDialogPrivate::updateWidgets()
601 options.gbPrintRange->setVisible(q->isOptionEnabled(QPrintDialog::PrintPageRange) ||
602 q->isOptionEnabled(QPrintDialog::PrintSelection) ||
603 q->isOptionEnabled(QPrintDialog::PrintCurrentPage));
605 options.printRange->setEnabled(q->isOptionEnabled(QPrintDialog::PrintPageRange));
606 options.printSelection->setVisible(q->isOptionEnabled(QPrintDialog::PrintSelection));
607 options.printCurrentPage->setVisible(q->isOptionEnabled(QPrintDialog::PrintCurrentPage));
608 options.collate->setVisible(q->isOptionEnabled(QPrintDialog::PrintCollateCopies));
610 switch (q->printRange()) {
611 case QPrintDialog::AllPages:
612 options.printAll->setChecked(true);
614 case QPrintDialog::Selection:
615 options.printSelection->setChecked(true);
617 case QPrintDialog::PageRange:
618 options.printRange->setChecked(true);
620 case QPrintDialog::CurrentPage:
621 if (q->isOptionEnabled(QPrintDialog::PrintCurrentPage))
622 options.printCurrentPage->setChecked(true);
627 const int minPage = qMax(1, qMin(q->minPage() , q->maxPage()));
628 const int maxPage = qMax(1, q->maxPage() == INT_MAX ? 9999 : q->maxPage());
630 options.from->setMinimum(minPage);
631 options.to->setMinimum(minPage);
632 options.from->setMaximum(maxPage);
633 options.to->setMaximum(maxPage);
635 options.from->setValue(q->fromPage());
636 options.to->setValue(q->toPage());
637 top->d->updateWidget();
640 void QPrintDialogPrivate::setTabs(const QList<QWidget*> &tabWidgets)
642 while(options.tabs->count() > 2)
643 delete options.tabs->widget(2);
645 QList<QWidget*>::ConstIterator iter = tabWidgets.begin();
646 while(iter != tabWidgets.constEnd()) {
647 QWidget *tab = *iter;
648 options.tabs->addTab(tab, tab->windowTitle());
653 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
654 void QPrintDialogPrivate::selectPrinter(QCUPSSupport *cups)
656 options.duplex->setEnabled(cups && cups->ppdOption("Duplex"));
660 ////////////////////////////////////////////////////////////////////////////////
661 ////////////////////////////////////////////////////////////////////////////////
667 The main Print Dialog.
671 QPrintDialog::QPrintDialog(QPrinter *printer, QWidget *parent)
672 : QAbstractPrintDialog(*(new QPrintDialogPrivate), printer, parent)
679 Constructs a print dialog with the given \a parent.
681 QPrintDialog::QPrintDialog(QWidget *parent)
682 : QAbstractPrintDialog(*(new QPrintDialogPrivate), 0, parent)
688 QPrintDialog::~QPrintDialog()
692 void QPrintDialog::setVisible(bool visible)
699 QAbstractPrintDialog::setVisible(visible);
702 int QPrintDialog::exec()
704 return QDialog::exec();
707 void QPrintDialog::accept()
714 ////////////////////////////////////////////////////////////////////////////////
715 ////////////////////////////////////////////////////////////////////////////////
719 QUnixPrintWidget && QUnixPrintWidgetPrivate
721 The upper half of the Print Dialog containing the Printer Selection widgets
725 #if defined (Q_OS_UNIX)
729 QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p)
730 : parent(p), propertiesDialog(0), printer(0), optionsPane(0), filePrintersAdded(false)
731 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
732 , cups(0), cupsPrinterCount(0), cupsPrinters(0), cupsPPD(0)
737 q = qobject_cast<QAbstractPrintDialog*> (parent->parent());
739 widget.setupUi(parent);
741 int currentPrinterIndex = 0;
742 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
743 cups = new QCUPSSupport;
744 if (QCUPSSupport::isAvailable()) {
745 cupsPPD = cups->currentPPD();
746 cupsPrinterCount = cups->availablePrintersCount();
747 cupsPrinters = cups->availablePrinters();
749 for (int i = 0; i < cupsPrinterCount; ++i) {
750 QString printerName(QString::fromLocal8Bit(cupsPrinters[i].name));
751 if (cupsPrinters[i].instance)
752 printerName += QLatin1Char('/') + QString::fromLocal8Bit(cupsPrinters[i].instance);
754 widget.printers->addItem(printerName);
755 if (cupsPrinters[i].is_default)
756 widget.printers->setCurrentIndex(i);
758 // the model depends on valid ppd. so before enabling the
759 // properties button we make sure the ppd is in fact valid.
760 if (cupsPrinterCount && cups->currentPPD()) {
761 widget.properties->setEnabled(true);
763 currentPrinterIndex = cups->currentPrinterIndex();
767 #if !defined(QT_NO_FILESYSTEMMODEL) && !defined(QT_NO_COMPLETER)
768 QFileSystemModel *fsm = new QFileSystemModel(widget.filename);
769 fsm->setRootPath(QDir::homePath());
770 widget.filename->setCompleter(new QCompleter(fsm, widget.filename));
772 _q_printerChanged(currentPrinterIndex);
774 QObject::connect(widget.printers, SIGNAL(currentIndexChanged(int)),
775 parent, SLOT(_q_printerChanged(int)));
776 QObject::connect(widget.fileBrowser, SIGNAL(clicked()), parent, SLOT(_q_btnBrowseClicked()));
777 QObject::connect(widget.properties, SIGNAL(clicked()), parent, SLOT(_q_btnPropertiesClicked()));
779 // disable features that QPrinter does not yet support.
780 widget.preview->setVisible(false);
783 void QUnixPrintWidgetPrivate::updateWidget()
785 const bool printToFile = q == 0 || q->isOptionEnabled(QPrintDialog::PrintToFile);
786 if (printToFile && !filePrintersAdded) {
787 if (widget.printers->count())
788 widget.printers->insertSeparator(widget.printers->count());
789 widget.printers->addItem(QPrintDialog::tr("Print to File (PDF)"));
790 filePrintersAdded = true;
792 if (!printToFile && filePrintersAdded) {
793 widget.printers->removeItem(widget.printers->count()-1);
794 widget.printers->removeItem(widget.printers->count()-1);
795 if (widget.printers->count())
796 widget.printers->removeItem(widget.printers->count()-1); // remove separator
797 filePrintersAdded = false;
799 if (printer && filePrintersAdded && (printer->outputFormat() != QPrinter::NativeFormat
800 || printer->printerName().isEmpty()))
802 if (printer->outputFormat() == QPrinter::PdfFormat)
803 widget.printers->setCurrentIndex(widget.printers->count() - 1);
804 widget.filename->setEnabled(true);
805 widget.lOutput->setEnabled(true);
808 widget.filename->setVisible(printToFile);
809 widget.lOutput->setVisible(printToFile);
810 widget.fileBrowser->setVisible(printToFile);
812 widget.properties->setVisible(q->isOptionEnabled(QAbstractPrintDialog::PrintShowPageSize));
815 QUnixPrintWidgetPrivate::~QUnixPrintWidgetPrivate()
817 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
822 void QUnixPrintWidgetPrivate::_q_printerChanged(int index)
826 const int printerCount = widget.printers->count();
827 widget.filename->setEnabled(false);
828 widget.lOutput->setEnabled(false);
830 if (filePrintersAdded) {
831 Q_ASSERT(index != printerCount - 2); // separator
832 if (index == printerCount - 1) { // PDF
833 widget.location->setText(QPrintDialog::tr("Local file"));
834 widget.type->setText(QPrintDialog::tr("Write PDF file"));
835 widget.properties->setEnabled(true);
836 widget.filename->setEnabled(true);
837 QString filename = widget.filename->text();
838 QString suffix = QFileInfo(filename).suffix();
839 widget.filename->setText(filename);
840 widget.lOutput->setEnabled(true);
841 if (propertiesDialog)
842 propertiesDialog->selectPdfPsPrinter(printer);
843 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
845 optionsPane->selectPrinter(0);
851 widget.location->setText(QString());
852 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
853 if (QCUPSSupport::isAvailable()) {
854 cups->setCurrentPrinter(index);
856 const cups_option_t *opt = cups->printerOption(QString::fromLatin1("printer-location"));
859 location = QString::fromLocal8Bit(opt->value);
860 widget.location->setText(location);
862 cupsPPD = cups->currentPPD();
863 // set printer type line
866 type = QString::fromLocal8Bit(cupsPPD->manufacturer) + QLatin1String(" - ") + QString::fromLocal8Bit(cupsPPD->modelname);
867 widget.type->setText(type);
868 if (propertiesDialog)
869 propertiesDialog->selectPrinter();
871 optionsPane->selectPrinter(cups);
874 optionsPane->selectPrinter(0);
879 void QUnixPrintWidgetPrivate::setOptionsPane(QPrintDialogPrivate *pane)
883 _q_printerChanged(widget.printers->currentIndex());
886 void QUnixPrintWidgetPrivate::_q_btnBrowseClicked()
888 QString filename = widget.filename->text();
889 #ifndef QT_NO_FILEDIALOG
890 filename = QFileDialog::getSaveFileName(parent, QPrintDialog::tr("Print To File ..."), filename,
891 QString(), 0, QFileDialog::DontConfirmOverwrite);
895 if (!filename.isEmpty()) {
896 widget.filename->setText(filename);
897 widget.printers->setCurrentIndex(widget.printers->count() - 1); // the pdf one
901 void QUnixPrintWidgetPrivate::applyPrinterProperties(QPrinter *p)
906 if (p->outputFileName().isEmpty()) {
907 QString home = QDir::homePath();
908 QString cur = QDir::currentPath();
909 if (home.at(home.length()-1) != QLatin1Char('/'))
910 home += QLatin1Char('/');
911 if (cur.at(cur.length()-1) != QLatin1Char('/'))
912 cur += QLatin1Char('/');
913 if (cur.left(home.length()) != home)
916 if (p->docName().isEmpty()) {
917 cur += QLatin1String("print.pdf");
919 QRegExp re(QString::fromLatin1("(.*)\\.\\S+"));
920 if (re.exactMatch(p->docName()))
924 cur += QLatin1String(".pdf");
927 widget.filename->setText(cur);
930 widget.filename->setText( p->outputFileName() );
931 QString printer = p->printerName();
932 if (!printer.isEmpty()) {
933 for (int i = 0; i < widget.printers->count(); ++i) {
934 if (widget.printers->itemText(i) == printer) {
935 widget.printers->setCurrentIndex(i);
940 // PDF and PS printers are not added to the dialog yet, we'll handle those cases in QUnixPrintWidgetPrivate::updateWidget
942 if (propertiesDialog)
943 propertiesDialog->applyPrinterProperties(p);
946 #ifndef QT_NO_MESSAGEBOX
947 bool QUnixPrintWidgetPrivate::checkFields()
949 if (widget.filename->isEnabled()) {
950 QString file = widget.filename->text();
953 bool exists = fi.exists();
955 if (exists && fi.isDir()) {
956 QMessageBox::warning(q, q->windowTitle(),
957 QPrintDialog::tr("%1 is a directory.\nPlease choose a different file name.").arg(file));
959 } else if ((exists && !fi.isWritable()) || !(opened = f.open(QFile::Append))) {
960 QMessageBox::warning(q, q->windowTitle(),
961 QPrintDialog::tr("File %1 is not writable.\nPlease choose a different file name.").arg(file));
964 int ret = QMessageBox::question(q, q->windowTitle(),
965 QPrintDialog::tr("%1 already exists.\nDo you want to overwrite it?").arg(file),
966 QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
967 if (ret == QMessageBox::No)
977 // Every test passed. Accept the dialog.
980 #endif // QT_NO_MESSAGEBOX
982 void QUnixPrintWidgetPrivate::_q_btnPropertiesClicked()
984 if (!propertiesDialog) {
985 propertiesDialog = new QPrintPropertiesDialog(q);
986 propertiesDialog->setResult(QDialog::Rejected);
989 if (propertiesDialog->result() == QDialog::Rejected) {
990 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
991 propertiesDialog->setCups(cups);
993 propertiesDialog->applyPrinterProperties(q->printer());
995 if (q->isOptionEnabled(QPrintDialog::PrintToFile)
996 && (widget.printers->currentIndex() == widget.printers->count() - 1)) // PDF
997 propertiesDialog->selectPdfPsPrinter(q->printer());
999 propertiesDialog->selectPrinter();
1001 propertiesDialog->exec();
1004 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
1005 void QUnixPrintWidgetPrivate::setCupsProperties()
1007 if (cups && QCUPSSupport::isAvailable() && cups->pageSizes()) {
1008 QPrintEngine *engine = printer->printEngine();
1009 const ppd_option_t* pageSizes = cups->pageSizes();
1010 QByteArray cupsPageSize;
1011 for (int i = 0; i < pageSizes->num_choices; ++i) {
1012 if (static_cast<int>(pageSizes->choices[i].marked) == 1)
1013 cupsPageSize = pageSizes->choices[i].choice;
1015 engine->setProperty(PPK_CupsStringPageSize, QString::fromLatin1(cupsPageSize));
1016 engine->setProperty(PPK_CupsOptions, cups->options());
1018 QRect pageRect = cups->pageRect(cupsPageSize);
1019 engine->setProperty(PPK_CupsPageRect, pageRect);
1021 QRect paperRect = cups->paperRect(cupsPageSize);
1022 engine->setProperty(PPK_CupsPaperRect, paperRect);
1024 for (int ps = 0; ps < QPrinter::NPageSize; ++ps) {
1025 QPdf::PaperSize size = QPdf::paperSize(QPrinter::PaperSize(ps));
1026 if (size.width == paperRect.width() && size.height == paperRect.height())
1027 printer->setPaperSize(static_cast<QPrinter::PaperSize>(ps));
1033 void QUnixPrintWidgetPrivate::setupPrinter()
1035 const int printerCount = widget.printers->count();
1036 const int index = widget.printers->currentIndex();
1038 if (filePrintersAdded && index == printerCount - 1) { // PDF
1039 printer->setPrinterName(QString());
1040 Q_ASSERT(index != printerCount - 2); // separator
1041 printer->setOutputFormat(QPrinter::PdfFormat);
1042 QString path = widget.filename->text();
1043 if (QDir::isRelativePath(path))
1044 path = QDir::homePath() + QDir::separator() + path;
1045 printer->setOutputFileName(path);
1048 printer->setPrinterName(widget.printers->currentText());
1049 printer->setOutputFileName(QString());
1052 if (propertiesDialog && propertiesDialog->result() == QDialog::Accepted)
1053 propertiesDialog->setupPrinter();
1054 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
1055 if (!propertiesDialog)
1056 setCupsProperties();
1062 QUnixPrintWidget::QUnixPrintWidget(QPrinter *printer, QWidget *parent)
1063 : QWidget(parent), d(new QUnixPrintWidgetPrivate(this))
1065 d->applyPrinterProperties(printer);
1070 QUnixPrintWidget::~QUnixPrintWidget()
1077 Updates the printer with the states held in the QUnixPrintWidget.
1079 void QUnixPrintWidget::updatePrinter()
1084 ////////////////////////////////////////////////////////////////////////////////
1085 ////////////////////////////////////////////////////////////////////////////////
1091 Holds the PPD Options for the printer.
1095 #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
1097 QPPDOptionsModel::QPPDOptionsModel(QCUPSSupport *c, QObject *parent)
1098 : QAbstractItemModel(parent), rootItem(0), cups(c), ppd(c->currentPPD())
1103 QPPDOptionsModel::~QPPDOptionsModel()
1107 int QPPDOptionsModel::columnCount(const QModelIndex&) const
1112 int QPPDOptionsModel::rowCount(const QModelIndex& parent) const
1114 QOptionTreeItem* itm;
1115 if (!parent.isValid())
1118 itm = reinterpret_cast<QOptionTreeItem*>(parent.internalPointer());
1120 if (itm->type == QOptionTreeItem::Option)
1123 return itm->childItems.count();
1126 QVariant QPPDOptionsModel::data(const QModelIndex& index, int role) const
1129 case Qt::FontRole: {
1130 QOptionTreeItem* itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
1131 if (itm && itm->type == QOptionTreeItem::Group){
1132 QFont font = QApplication::font();
1134 return QVariant(font);
1140 case Qt::DisplayRole: {
1141 QOptionTreeItem* itm;
1142 if (!index.isValid())
1145 itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
1147 if (index.column() == 0)
1148 return cups->unicodeString(itm->description);
1149 else if (itm->type == QOptionTreeItem::Option && itm->selected > -1)
1150 return cups->unicodeString(itm->selDescription);
1159 if (role != Qt::DisplayRole)
1163 QModelIndex QPPDOptionsModel::index(int row, int column, const QModelIndex& parent) const
1165 QOptionTreeItem* itm;
1166 if (!parent.isValid())
1169 itm = reinterpret_cast<QOptionTreeItem*>(parent.internalPointer());
1171 return createIndex(row, column, itm->childItems.at(row));
1175 QModelIndex QPPDOptionsModel::parent(const QModelIndex& index) const
1177 if (!index.isValid())
1178 return QModelIndex();
1180 QOptionTreeItem* itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
1182 if (itm->parentItem && itm->parentItem != rootItem)
1183 return createIndex(itm->parentItem->index, 0, itm->parentItem);
1185 return QModelIndex();
1188 Qt::ItemFlags QPPDOptionsModel::flags(const QModelIndex& index) const
1190 if (!index.isValid() || reinterpret_cast<QOptionTreeItem*>(index.internalPointer())->type == QOptionTreeItem::Group)
1191 return Qt::ItemIsEnabled;
1193 if (index.column() == 1)
1194 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
1196 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
1199 void QPPDOptionsModel::parseItems()
1201 emit layoutAboutToBeChanged();
1202 ppd = cups->currentPPD();
1204 rootItem = new QOptionTreeItem(QOptionTreeItem::Root, 0, ppd, "Root Item", 0);
1205 parseGroups(rootItem);
1206 emit layoutChanged();
1209 void QPPDOptionsModel::parseGroups(QOptionTreeItem* parent)
1211 if (parent->type == QOptionTreeItem::Root) {
1213 const ppd_file_t* ppdFile = reinterpret_cast<const ppd_file_t*>(parent->ptr);
1216 for (int i = 0; i < ppdFile->num_groups; ++i) {
1217 QOptionTreeItem* group = new QOptionTreeItem(QOptionTreeItem::Group, i, &ppdFile->groups[i], ppdFile->groups[i].text, parent);
1218 parent->childItems.append(group);
1219 parseGroups(group); // parse possible subgroups
1220 parseOptions(group); // parse options
1223 } else if (parent->type == QOptionTreeItem::Group) {
1225 const ppd_group_t* group = reinterpret_cast<const ppd_group_t*>(parent->ptr);
1228 for (int i = 0; i < group->num_subgroups; ++i) {
1229 QOptionTreeItem* subgroup = new QOptionTreeItem(QOptionTreeItem::Group, i, &group->subgroups[i], group->subgroups[i].text, parent);
1230 parent->childItems.append(subgroup);
1231 parseGroups(subgroup); // parse possible subgroups
1232 parseOptions(subgroup); // parse options
1238 void QPPDOptionsModel::parseOptions(QOptionTreeItem* parent)
1240 const ppd_group_t* group = reinterpret_cast<const ppd_group_t*>(parent->ptr);
1241 for (int i = 0; i < group->num_options; ++i) {
1242 QOptionTreeItem* opt = new QOptionTreeItem(QOptionTreeItem::Option, i, &group->options[i], group->options[i].text, parent);
1243 parent->childItems.append(opt);
1248 void QPPDOptionsModel::parseChoices(QOptionTreeItem* parent)
1250 const ppd_option_t* option = reinterpret_cast<const ppd_option_t*>(parent->ptr);
1251 bool marked = false;
1252 for (int i = 0; i < option->num_choices; ++i) {
1253 QOptionTreeItem* choice = new QOptionTreeItem(QOptionTreeItem::Choice, i, &option->choices[i], option->choices[i].text, parent);
1254 if (static_cast<int>(option->choices[i].marked) == 1) {
1255 parent->selected = i;
1256 parent->selDescription = option->choices[i].text;
1258 } else if (!marked && qstrcmp(option->choices[i].choice, option->defchoice) == 0) {
1259 parent->selected = i;
1260 parent->selDescription = option->choices[i].text;
1262 parent->childItems.append(choice);
1266 QVariant QPPDOptionsModel::headerData(int section, Qt::Orientation, int role) const
1268 if (role != Qt::DisplayRole)
1273 return QVariant(QApplication::translate("QPPDOptionsModel", "Name"));
1275 return QVariant(QApplication::translate("QPPDOptionsModel", "Value"));
1281 ////////////////////////////////////////////////////////////////////////////////
1282 ////////////////////////////////////////////////////////////////////////////////
1288 Edits the PPD Options for the printer.
1292 QWidget* QPPDOptionsEditor::createEditor(QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& index) const
1294 if (index.column() == 1 && reinterpret_cast<QOptionTreeItem*>(index.internalPointer())->type == QOptionTreeItem::Option)
1295 return new QComboBox(parent);
1300 void QPPDOptionsEditor::setEditorData(QWidget* editor, const QModelIndex& index) const
1302 if (index.column() != 1)
1305 QComboBox* cb = static_cast<QComboBox*>(editor);
1306 QOptionTreeItem* itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
1308 if (itm->selected == -1)
1309 cb->addItem(QString());
1311 for (int i = 0; i < itm->childItems.count(); ++i)
1312 cb->addItem(QString::fromLocal8Bit(itm->childItems.at(i)->description));
1314 if (itm->selected > -1)
1315 cb->setCurrentIndex(itm->selected);
1317 connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(cbChanged(int)));
1320 void QPPDOptionsEditor::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
1322 QComboBox* cb = static_cast<QComboBox*>(editor);
1323 QOptionTreeItem* itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
1325 if (itm->selected == cb->currentIndex())
1328 const ppd_option_t* opt = reinterpret_cast<const ppd_option_t*>(itm->ptr);
1329 QPPDOptionsModel* m = static_cast<QPPDOptionsModel*>(model);
1331 if (m->cups->markOption(opt->keyword, opt->choices[cb->currentIndex()].choice) == 0) {
1332 itm->selected = cb->currentIndex();
1333 itm->selDescription = reinterpret_cast<const ppd_option_t*>(itm->ptr)->choices[itm->selected].text;
1337 void QPPDOptionsEditor::cbChanged(int)
1340 emit commitData(static_cast<QWidget*>(sender()));
1344 ////////////////////////////////////////////////////////////////////////////////
1345 ////////////////////////////////////////////////////////////////////////////////
1347 #endif // !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
1348 #endif // defined (Q_OS_UNIX)
1352 #include "moc_qprintdialog.cpp"
1353 #include "qprintdialog_unix.moc"
1355 #include "qrc_qprintdialog.cpp"
1358 #endif // QT_NO_PRINTDIALOG