1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qpagesetupdialog.h"
41 
42 #include "qpagesetupdialog_unix_p.h"
43 
44 #include <private/qpagesetupdialog_p.h>
45 #include <private/qprintdevice_p.h>
46 #if QT_CONFIG(cups)
47 #include <private/qcups_p.h>
48 #endif
49 
50 #include "qpainter.h"
51 #include "qprintdialog.h"
52 #include "qtextcodec.h"
53 #include "qdialogbuttonbox.h"
54 #include <ui_qpagesetupwidget.h>
55 
56 #include <QtPrintSupport/qprinter.h>
57 
58 #include <qpa/qplatformprintplugin.h>
59 #include <qpa/qplatformprintersupport.h>
60 
61 QT_BEGIN_NAMESPACE
62 
63 extern QMarginsF qt_convertMargins(const QMarginsF &margins, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits);
64 
65 // Disabled until we have support for papersources on unix
66 // #define PSD_ENABLE_PAPERSOURCE
67 
68 #ifdef PSD_ENABLE_PAPERSOURCE
69 static const char *paperSourceNames[] = {
70     "Only One",
71     "Lower",
72     "Middle",
73     "Manual",
74     "Envelope",
75     "Envelope manual",
76     "Auto",
77     "Tractor",
78     "Small format",
79     "Large format",
80     "Large capacity",
81     "Cassette",
82     "Form source",
83     0
84 };
85 
86 struct PaperSourceNames
87 {
PaperSourceNamesPaperSourceNames88     PaperSourceNames(const char *nam, QPrinter::PaperSource ps)
89         : paperSource(ps), name(nam) {}
90     QPrinter::PaperSource paperSource;
91     const char *name;
92 };
93 #endif
94 
95 
96 // QPagePreview
97 // - Private widget to display preview of page layout
98 // - Embedded in QPageSetupWidget
99 
100 class QPagePreview : public QWidget
101 {
102 public:
QPagePreview(QWidget * parent)103     QPagePreview(QWidget *parent) : QWidget(parent)
104     {
105         setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
106         setMinimumSize(50, 50);
107     }
108 
setPageLayout(const QPageLayout & layout)109     void setPageLayout(const QPageLayout &layout)
110     {
111         m_pageLayout = layout;
112         update();
113     }
114 
setPagePreviewLayout(int columns,int rows)115     void setPagePreviewLayout(int columns, int rows)
116     {
117       m_pagePreviewColumns = columns;
118       m_pagePreviewRows = rows;
119       update();
120     }
121 
122 protected:
paintEvent(QPaintEvent *)123     void paintEvent(QPaintEvent *) override
124     {
125         QSize pageSize = m_pageLayout.fullRectPoints().size();
126         QSizeF scaledSize = pageSize.scaled(width() - 10, height() - 10, Qt::KeepAspectRatio);
127         QRect pageRect = QRect(QPoint(0,0), scaledSize.toSize());
128         pageRect.moveCenter(rect().center());
129         qreal width_factor = scaledSize.width() / pageSize.width();
130         qreal height_factor = scaledSize.height() / pageSize.height();
131         QMarginsF margins = m_pageLayout.margins(QPageLayout::Point);
132         int left = qRound(margins.left() * width_factor);
133         int top = qRound(margins.top() * height_factor);
134         int right = qRound(margins.right() * width_factor);
135         int bottom = qRound(margins.bottom() * height_factor);
136         QRect marginRect(pageRect.x() + left, pageRect.y() + top,
137                          pageRect.width() - (left + right + 1), pageRect.height() - (top + bottom + 1));
138 
139         QPainter p(this);
140         QColor shadow(palette().mid().color());
141         for (int i=1; i<6; ++i) {
142             shadow.setAlpha(180-i*30);
143             QRect offset(pageRect.adjusted(i, i, i, i));
144             p.setPen(shadow);
145             p.drawLine(offset.left(), offset.bottom(), offset.right(), offset.bottom());
146             p.drawLine(offset.right(), offset.top(), offset.right(), offset.bottom()-1);
147         }
148         p.fillRect(pageRect, palette().light());
149 
150         if (marginRect.isValid()) {
151             p.setPen(QPen(palette().color(QPalette::Dark), 0, Qt::DotLine));
152             p.drawRect(marginRect);
153 
154             marginRect.adjust(2, 2, -1, -1);
155             p.setClipRect(marginRect);
156             QFont font;
157             font.setPointSizeF(font.pointSizeF()*0.25);
158             p.setFont(font);
159             p.setPen(palette().color(QPalette::Dark));
160             QString text(QLatin1String("Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi."));
161             for (int i=0; i<3; ++i)
162                 text += text;
163 
164             const int spacing = pageRect.width() * 0.1;
165             const int textWidth = (marginRect.width() - (spacing * (m_pagePreviewColumns-1))) / m_pagePreviewColumns;
166             const int textHeight = (marginRect.height() - (spacing * (m_pagePreviewRows-1))) / m_pagePreviewRows;
167 
168             for (int x = 0 ; x < m_pagePreviewColumns; ++x) {
169                 for (int y = 0 ; y < m_pagePreviewRows; ++y) {
170                     QRect textRect(marginRect.left() + x * (textWidth + spacing),
171                                    marginRect.top() + y * (textHeight + spacing),
172                                    textWidth, textHeight);
173                     p.drawText(textRect, Qt::TextWordWrap|Qt::AlignVCenter, text);
174                 }
175             }
176         }
177     }
178 
179 private:
180     // Page Layout
181     QPageLayout m_pageLayout;
182     // Pages Per Sheet / n-up layout
183     int m_pagePreviewColumns, m_pagePreviewRows;
184 };
185 
186 
187 // QUnixPageSetupDialogPrivate
188 // - Linux / Cups implementation of QPageSetupDialogPrivate
189 // - Embeds QPageSetupWidget
190 
191 class QUnixPageSetupDialogPrivate : public QPageSetupDialogPrivate
192 {
193     Q_DECLARE_PUBLIC(QPageSetupDialog)
194 
195 public:
196     QUnixPageSetupDialogPrivate(QPrinter *printer);
197     ~QUnixPageSetupDialogPrivate();
198     void init();
199 
200     QPageSetupWidget *widget;
201 };
202 
QUnixPageSetupDialogPrivate(QPrinter * printer)203 QUnixPageSetupDialogPrivate::QUnixPageSetupDialogPrivate(QPrinter *printer) : QPageSetupDialogPrivate(printer)
204 {
205 }
206 
~QUnixPageSetupDialogPrivate()207 QUnixPageSetupDialogPrivate::~QUnixPageSetupDialogPrivate()
208 {
209 }
210 
init()211 void QUnixPageSetupDialogPrivate::init()
212 {
213     Q_Q(QPageSetupDialog);
214 
215     widget = new QPageSetupWidget(q);
216     widget->setPrinter(printer, nullptr, printer->outputFormat(), printer->printerName());
217 
218     QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok
219                                                      | QDialogButtonBox::Cancel,
220                                                      Qt::Horizontal, q);
221     QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(accept()));
222     QObject::connect(buttons, SIGNAL(rejected()), q, SLOT(reject()));
223 
224     QVBoxLayout *lay = new QVBoxLayout(q);
225     lay->addWidget(widget);
226     lay->addWidget(buttons);
227 }
228 
229 // QPageSetupWidget
230 // - Private widget implementation for Linux / CUPS
231 // - Embeds QPagePreview
232 // - TODO Could be made public as a stand-alone widget?
233 
QPageSetupWidget(QWidget * parent)234 QPageSetupWidget::QPageSetupWidget(QWidget *parent)
235     : QWidget(parent),
236       m_pagePreview(nullptr),
237       m_printer(nullptr),
238       m_printDevice(nullptr),
239 #if QT_CONFIG(cups)
240       m_pageSizePpdOption(nullptr),
241 #endif
242       m_outputFormat(QPrinter::PdfFormat),
243       m_units(QPageLayout::Point),
244       m_savedUnits(QPageLayout::Point),
245       m_savedPagesPerSheet(-1),
246       m_savedPagesPerSheetLayout(-1),
247       m_blockSignals(false),
248       m_realCustomPageSizeIndex(-1)
249 {
250     m_ui.setupUi(this);
251 
252     if (!QMetaType::hasRegisteredComparators<QPageSize>())
253         QMetaType::registerEqualsComparator<QPageSize>();
254 
255     QVBoxLayout *lay = new QVBoxLayout(m_ui.preview);
256     m_pagePreview = new QPagePreview(m_ui.preview);
257     m_pagePreview->setPagePreviewLayout(1, 1);
258 
259     lay->addWidget(m_pagePreview);
260 
261     setAttribute(Qt::WA_WState_Polished, false);
262 
263 #ifdef PSD_ENABLE_PAPERSOURCE
264     for (int i=0; paperSourceNames[i]; ++i)
265         m_ui.paperSource->insertItem(paperSourceNames[i]);
266 #else
267     m_ui.paperSourceLabel->setVisible(false);
268     m_ui.paperSource->setVisible(false);
269 #endif
270 
271     m_ui.reverseLandscape->setVisible(false);
272     m_ui.reversePortrait->setVisible(false);
273 
274     initUnits();
275     initPagesPerSheet();
276 
277     connect(m_ui.unitCombo, QOverload<int>::of(&QComboBox::activated), this, &QPageSetupWidget::unitChanged);
278 
279     connect(m_ui.pageSizeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QPageSetupWidget::pageSizeChanged);
280     connect(m_ui.pageWidth, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QPageSetupWidget::pageSizeChanged);
281     connect(m_ui.pageHeight, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QPageSetupWidget::pageSizeChanged);
282 
283     connect(m_ui.leftMargin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QPageSetupWidget::leftMarginChanged);
284     connect(m_ui.topMargin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QPageSetupWidget::topMarginChanged);
285     connect(m_ui.rightMargin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QPageSetupWidget::rightMarginChanged);
286     connect(m_ui.bottomMargin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QPageSetupWidget::bottomMarginChanged);
287 
288     connect(m_ui.portrait, &QRadioButton::clicked, this, &QPageSetupWidget::pageOrientationChanged);
289     connect(m_ui.landscape, &QRadioButton::clicked, this, &QPageSetupWidget::pageOrientationChanged);
290 
291     connect(m_ui.pagesPerSheetCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QPageSetupWidget::pagesPerSheetChanged);
292 }
293 
294 // Init the Units combo box
initUnits()295 void QPageSetupWidget::initUnits()
296 {
297     m_ui.unitCombo->addItem(tr("Millimeters (mm)"), QVariant::fromValue(QPageLayout::Millimeter));
298     m_ui.unitCombo->addItem(tr("Inches (in)"), QVariant::fromValue(QPageLayout::Inch));
299     m_ui.unitCombo->addItem(tr("Points (pt)"), QVariant::fromValue(QPageLayout::Point));
300     m_ui.unitCombo->addItem(tr("Pica (P̸)"), QVariant::fromValue(QPageLayout::Pica));
301     m_ui.unitCombo->addItem(tr("Didot (DD)"), QVariant::fromValue(QPageLayout::Didot));
302     m_ui.unitCombo->addItem(tr("Cicero (CC)"), QVariant::fromValue(QPageLayout::Cicero));
303 
304     // Initailly default to locale measurement system, mm if metric, in otherwise
305     m_ui.unitCombo->setCurrentIndex(QLocale().measurementSystem() != QLocale::MetricSystem);
306 }
307 
308 // Init the Pages Per Sheet (n-up) combo boxes if using CUPS
initPagesPerSheet()309 void QPageSetupWidget::initPagesPerSheet()
310 {
311 #if QT_CONFIG(cups)
312     m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Left to Right, Top to Bottom"),
313                                            QVariant::fromValue(QCUPSSupport::LeftToRightTopToBottom));
314     m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Left to Right, Bottom to Top"),
315                                            QVariant::fromValue(QCUPSSupport::LeftToRightBottomToTop));
316     m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Right to Left, Bottom to Top"),
317                                            QVariant::fromValue(QCUPSSupport::RightToLeftBottomToTop));
318     m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Right to Left, Top to Bottom"),
319                                            QVariant::fromValue(QCUPSSupport::RightToLeftTopToBottom));
320     m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Bottom to Top, Left to Right"),
321                                            QVariant::fromValue(QCUPSSupport::BottomToTopLeftToRight));
322     m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Bottom to Top, Right to Left"),
323                                            QVariant::fromValue(QCUPSSupport::BottomToTopRightToLeft));
324     m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Top to Bottom, Left to Right"),
325                                            QVariant::fromValue(QCUPSSupport::TopToBottomLeftToRight));
326     m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Top to Bottom, Right to Left"),
327                                            QVariant::fromValue(QCUPSSupport::TopToBottomRightToLeft));
328 
329     m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("1 (1x1)"),
330                                      QVariant::fromValue(QCUPSSupport::OnePagePerSheet));
331     m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("2 (2x1)"),
332                                      QVariant::fromValue(QCUPSSupport::TwoPagesPerSheet));
333     m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("4 (2x2)"),
334                                      QVariant::fromValue(QCUPSSupport::FourPagesPerSheet));
335     m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("6 (2x3)"),
336                                      QVariant::fromValue(QCUPSSupport::SixPagesPerSheet));
337     m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("9 (3x3)"),
338                                      QVariant::fromValue(QCUPSSupport::NinePagesPerSheet));
339     m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("16 (4x4)"),
340                                      QVariant::fromValue(QCUPSSupport::SixteenPagesPerSheet));
341 
342     // Set to QCUPSSupport::OnePagePerSheet
343     m_ui.pagesPerSheetCombo->setCurrentIndex(0);
344     // Set to QCUPSSupport::LeftToRightTopToBottom
345     m_ui.pagesPerSheetLayoutCombo->setCurrentIndex(0);
346 #else
347     // Disable if CUPS wasn't found
348     m_ui.pagesPerSheetButtonGroup->hide();
349 #endif
350 }
351 
initPageSizes()352 void QPageSetupWidget::initPageSizes()
353 {
354     m_blockSignals = true;
355 
356     m_ui.pageSizeCombo->clear();
357 
358     m_realCustomPageSizeIndex = -1;
359 
360     if (m_outputFormat == QPrinter::NativeFormat && !m_printerName.isEmpty()) {
361         QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();
362         if (ps) {
363             QPrintDevice printDevice = ps->createPrintDevice(m_printerName);
364             const QPageSize defaultSize = printDevice.defaultPageSize();
365             const auto pageSizes = printDevice.supportedPageSizes();
366             for (const QPageSize &pageSize : pageSizes)
367                 m_ui.pageSizeCombo->addItem(pageSize.name(), QVariant::fromValue(pageSize));
368             if (m_ui.pageSizeCombo->count() > 0) {
369                 if (printDevice.supportsCustomPageSizes()) {
370                     m_ui.pageSizeCombo->addItem(tr("Custom"));
371                     m_realCustomPageSizeIndex = m_ui.pageSizeCombo->count() - 1;
372                 }
373                 m_blockSignals = false;
374 
375                 // If the defaultSize is index 0, setCurrentIndex won't emit the currentIndexChanged
376                 // signal; workaround the issue by initially setting the currentIndex to -1
377                 m_ui.pageSizeCombo->setCurrentIndex(-1);
378                 m_ui.pageSizeCombo->setCurrentIndex(m_ui.pageSizeCombo->findData(QVariant::fromValue(defaultSize)));
379                 return;
380             }
381         }
382     }
383 
384     // If PdfFormat or no available printer page sizes, populate with all page sizes
385     for (int id = 0; id < QPageSize::LastPageSize; ++id) {
386         if (QPageSize::PageSizeId(id) == QPageSize::Custom) {
387             m_ui.pageSizeCombo->addItem(tr("Custom"));
388             m_realCustomPageSizeIndex = m_ui.pageSizeCombo->count() - 1;
389         } else {
390             QPageSize pageSize = QPageSize(QPageSize::PageSizeId(id));
391             m_ui.pageSizeCombo->addItem(pageSize.name(), QVariant::fromValue(pageSize));
392         }
393     }
394 
395     m_blockSignals = false;
396 }
397 
398 // Set the dialog to use the given QPrinter
399 // Usually only called on first creation
setPrinter(QPrinter * printer,QPrintDevice * printDevice,QPrinter::OutputFormat outputFormat,const QString & printerName)400 void QPageSetupWidget::setPrinter(QPrinter *printer, QPrintDevice *printDevice,
401                                   QPrinter::OutputFormat outputFormat, const QString &printerName)
402 {
403     m_printer = printer;
404     m_printDevice = printDevice;
405 
406 #if QT_CONFIG(cups)
407     // find the PageSize cups option
408     m_pageSizePpdOption = m_printDevice ? QCUPSSupport::findPpdOption("PageSize", m_printDevice) : nullptr;
409 #endif
410 
411     // Initialize the layout to the current QPrinter layout
412     m_pageLayout = m_printer->pageLayout();
413 
414     // Assume if margins are Points then is by default, so set to locale default units
415     if (m_pageLayout.units() == QPageLayout::Point) {
416         if (QLocale().measurementSystem() == QLocale::MetricSystem)
417             m_pageLayout.setUnits(QPageLayout::Millimeter);
418         else
419             m_pageLayout.setUnits(QPageLayout::Inch);
420     }
421     m_units = m_pageLayout.units();
422     m_pagePreview->setPageLayout(m_pageLayout);
423 
424     m_outputFormat = outputFormat;
425     m_printerName = printerName;
426     initPageSizes();
427     updateWidget();
428     updateSavedValues();
429 
430     if (m_ui.pageSizeCombo->currentIndex() == -1) {
431         // This can happen in raw printers that since they don't have a default
432         // page size none will get selected so just default to the first size (A4)
433         m_ui.pageSizeCombo->setCurrentIndex(0);
434     }
435 }
436 
437 // Update the widget with the current settings
438 // TODO Break up into more intelligent chunks?
updateWidget()439 void QPageSetupWidget::updateWidget()
440 {
441     m_blockSignals = true;
442 
443     QString suffix;
444     switch (m_units) {
445     case QPageLayout::Millimeter:
446         //: Unit 'Millimeter'
447         suffix = tr("mm");
448         break;
449     case QPageLayout::Point:
450         //: Unit 'Points'
451         suffix = tr("pt");
452         break;
453     case QPageLayout::Inch:
454         //: Unit 'Inch'
455         suffix = tr("in");
456         break;
457     case QPageLayout::Pica:
458         //: Unit 'Pica'
459         suffix = tr("P̸");
460         break;
461     case QPageLayout::Didot:
462         //: Unit 'Didot'
463         suffix = tr("DD");
464         break;
465     case QPageLayout::Cicero:
466         //: Unit 'Cicero'
467         suffix = tr("CC");
468         break;
469     }
470 
471     m_ui.unitCombo->setCurrentIndex(m_ui.unitCombo->findData(QVariant::fromValue(m_units)));
472 
473     const bool isCustom = m_ui.pageSizeCombo->currentIndex() == m_realCustomPageSizeIndex && m_realCustomPageSizeIndex != -1;
474     if (!isCustom)
475         m_ui.pageSizeCombo->setCurrentIndex(m_ui.pageSizeCombo->findData(QVariant::fromValue(m_pageLayout.pageSize())));
476 
477     QMarginsF min;
478     QMarginsF max;
479 
480     if (m_pageLayout.mode() == QPageLayout::FullPageMode) {
481         min = QMarginsF(0.0, 0.0, 0.0, 0.0);
482         max = QMarginsF(9999.9999, 9999.9999, 9999.9999, 9999.9999);
483     } else {
484         min = m_pageLayout.minimumMargins();
485         max = m_pageLayout.maximumMargins();
486     }
487 
488     m_ui.leftMargin->setSuffix(suffix);
489     m_ui.leftMargin->setMinimum(min.left());
490     m_ui.leftMargin->setMaximum(max.left());
491     m_ui.leftMargin->setValue(m_pageLayout.margins().left());
492 
493     m_ui.rightMargin->setSuffix(suffix);
494     m_ui.rightMargin->setMinimum(min.right());
495     m_ui.rightMargin->setMaximum(max.right());
496     m_ui.rightMargin->setValue(m_pageLayout.margins().right());
497 
498     m_ui.topMargin->setSuffix(suffix);
499     m_ui.topMargin->setMinimum(min.top());
500     m_ui.topMargin->setMaximum(max.top());
501     m_ui.topMargin->setValue(m_pageLayout.margins().top());
502 
503     m_ui.bottomMargin->setSuffix(suffix);
504     m_ui.bottomMargin->setMinimum(min.bottom());
505     m_ui.bottomMargin->setMaximum(max.bottom());
506     m_ui.bottomMargin->setValue(m_pageLayout.margins().bottom());
507 
508     m_ui.pageWidth->setSuffix(suffix);
509     m_ui.pageWidth->setValue(m_pageLayout.fullRect(m_units).width());
510     m_ui.pageWidth->setEnabled(isCustom);
511     m_ui.widthLabel->setEnabled(isCustom);
512 
513     m_ui.pageHeight->setSuffix(suffix);
514     m_ui.pageHeight->setValue(m_pageLayout.fullRect(m_units).height());
515     m_ui.pageHeight->setEnabled(isCustom);
516     m_ui.heightLabel->setEnabled(isCustom);
517 
518     m_ui.portrait->setChecked(m_pageLayout.orientation() == QPageLayout::Portrait);
519     m_ui.landscape->setChecked(m_pageLayout.orientation() == QPageLayout::Landscape);
520 
521     m_ui.pagesPerSheetButtonGroup->setEnabled(m_outputFormat == QPrinter::NativeFormat);
522 
523 #ifdef PSD_ENABLE_PAPERSOURCE
524     m_ui.paperSource->setCurrentItem(printer->paperSource());
525 #endif
526 
527     m_blockSignals = false;
528 }
529 
530 // Set the dialog chosen options on the QPrinter
531 // Normally only called when the QPrintDialog or QPageSetupDialog OK button is pressed
setupPrinter() const532 void QPageSetupWidget::setupPrinter() const
533 {
534     m_printer->setPageLayout(m_pageLayout);
535 #if QT_CONFIG(cups)
536     QCUPSSupport::PagesPerSheet pagesPerSheet = qvariant_cast<QCUPSSupport::PagesPerSheet>(m_ui.pagesPerSheetCombo->currentData()
537 );
538     QCUPSSupport::PagesPerSheetLayout pagesPerSheetLayout = qvariant_cast<QCUPSSupport::PagesPerSheetLayout>(m_ui.pagesPerSheetLayoutCombo->currentData()
539 );
540     QCUPSSupport::setPagesPerSheetLayout(m_printer, pagesPerSheet, pagesPerSheetLayout);
541 #endif
542 #ifdef PSD_ENABLE_PAPERSOURCE
543     m_printer->setPaperSource((QPrinter::PaperSource)m_ui.paperSource->currentIndex());
544 #endif
545 }
546 
updateSavedValues()547 void QPageSetupWidget::updateSavedValues()
548 {
549     m_savedUnits = m_units;
550     m_savedPageLayout = m_pageLayout;
551     m_savedPagesPerSheet = m_ui.pagesPerSheetCombo->currentIndex();
552     m_savedPagesPerSheetLayout = m_ui.pagesPerSheetLayoutCombo->currentIndex();
553 }
554 
revertToSavedValues()555 void QPageSetupWidget::revertToSavedValues()
556 {
557     m_units = m_savedUnits;
558     m_pageLayout = m_savedPageLayout;
559     m_pagePreview->setPageLayout(m_pageLayout);
560 
561     updateWidget();
562 
563     m_ui.pagesPerSheetCombo->setCurrentIndex(m_savedPagesPerSheet);
564     m_ui.pagesPerSheetLayoutCombo->setCurrentIndex(m_savedPagesPerSheetLayout);
565 }
566 
567 #if QT_CONFIG(cups)
hasPpdConflict() const568 bool QPageSetupWidget::hasPpdConflict() const
569 {
570     if (m_pageSizePpdOption) {
571         if (m_pageSizePpdOption->conflicted) {
572             const QIcon warning = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr);
573             const int pixmap_size = m_ui.pageSizeCombo->sizeHint().height() * .75;
574             m_ui.pageSizeWarningLabel->setPixmap(warning.pixmap(pixmap_size, pixmap_size));
575         } else {
576             m_ui.pageSizeWarningLabel->setPixmap(QPixmap());
577         }
578         return m_pageSizePpdOption->conflicted;
579     }
580 
581     return false;
582 }
583 #endif
584 
585 // Updates size/preview after the combobox has been changed.
pageSizeChanged()586 void QPageSetupWidget::pageSizeChanged()
587 {
588     QPageSize pageSize;
589     if (m_ui.pageSizeCombo->currentIndex() != m_realCustomPageSizeIndex) {
590         pageSize = qvariant_cast<QPageSize>(m_ui.pageSizeCombo->currentData());
591 
592 #if QT_CONFIG(cups)
593         if (m_pageSizePpdOption) {
594             ppd_file_t *ppd = qvariant_cast<ppd_file_t*>(m_printDevice->property(PDPK_PpdFile));
595             QTextCodec *cupsCodec = QTextCodec::codecForName(ppd->lang_encoding);
596             for (int i = 0; i < m_pageSizePpdOption->num_choices; ++i) {
597                 const ppd_choice_t *choice = &m_pageSizePpdOption->choices[i];
598                 if (cupsCodec->toUnicode(choice->text) == m_ui.pageSizeCombo->currentText()) {
599                     const auto values = QStringList{} << QString::fromLatin1(m_pageSizePpdOption->keyword)
600                                                       << QString::fromLatin1(choice->choice);
601                     m_printDevice->setProperty(PDPK_PpdOption, values);
602                     emit ppdOptionChanged();
603                     break;
604                 }
605             }
606         }
607 #endif
608 
609     } else {
610         QSizeF customSize;
611         if (m_pageLayout.orientation() == QPageLayout::Landscape)
612             customSize = QSizeF(m_ui.pageHeight->value(), m_ui.pageWidth->value());
613         else
614             customSize = QSizeF(m_ui.pageWidth->value(), m_ui.pageHeight->value());
615         pageSize = QPageSize(customSize, QPageSize::Unit(m_units));
616 
617 #if QT_CONFIG(cups)
618         if (m_pageSizePpdOption) {
619             const auto values = QStringList{} << QString::fromLatin1(m_pageSizePpdOption->keyword)
620                                               << QStringLiteral("Custom");
621             m_printDevice->setProperty(PDPK_PpdOption, values);
622             emit ppdOptionChanged();
623         }
624 #endif
625     }
626 
627     // We always need to update the m_pageSizePpdOption when the page size changes
628     // even if it's from inside updateWidget, so do not move up
629     if (m_blockSignals)
630         return;
631 
632     const QMarginsF printable = m_printDevice ? m_printDevice->printableMargins(pageSize, m_pageLayout.orientation(), m_printer->resolution())
633                                               : QMarginsF();
634     m_pageLayout.setPageSize(pageSize, qt_convertMargins(printable, QPageLayout::Point, m_pageLayout.units()));
635     m_pagePreview->setPageLayout(m_pageLayout);
636 
637     updateWidget();
638 }
639 
pageOrientationChanged()640 void QPageSetupWidget::pageOrientationChanged()
641 {
642     if (m_blockSignals)
643         return;
644     m_pageLayout.setOrientation(m_ui.portrait->isChecked() ? QPageLayout::Portrait : QPageLayout::Landscape);
645     m_pagePreview->setPageLayout(m_pageLayout);
646     updateWidget();
647 }
648 
pagesPerSheetChanged()649 void QPageSetupWidget::pagesPerSheetChanged()
650 {
651 #if QT_CONFIG(cups)
652     switch (m_ui.pagesPerSheetCombo->currentData().toInt()) {
653     case QCUPSSupport::OnePagePerSheet:
654         m_pagePreview->setPagePreviewLayout(1, 1);
655         break;
656     case QCUPSSupport::TwoPagesPerSheet:
657         m_pagePreview->setPagePreviewLayout(1, 2);
658         break;
659     case QCUPSSupport::FourPagesPerSheet:
660         m_pagePreview->setPagePreviewLayout(2, 2);
661         break;
662     case QCUPSSupport::SixPagesPerSheet:
663         m_pagePreview->setPagePreviewLayout(3, 2);
664         break;
665     case QCUPSSupport::NinePagesPerSheet:
666         m_pagePreview->setPagePreviewLayout(3, 3);
667         break;
668     case QCUPSSupport::SixteenPagesPerSheet:
669         m_pagePreview->setPagePreviewLayout(4, 4);
670         break;
671     }
672 #endif
673 }
674 
unitChanged()675 void QPageSetupWidget::unitChanged()
676 {
677     if (m_blockSignals)
678         return;
679     m_units = qvariant_cast<QPageLayout::Unit>(m_ui.unitCombo->currentData());
680     m_pageLayout.setUnits(m_units);
681     updateWidget();
682 }
683 
topMarginChanged(double newValue)684 void QPageSetupWidget::topMarginChanged(double newValue)
685 {
686     if (m_blockSignals)
687         return;
688     m_pageLayout.setTopMargin(newValue);
689     m_pagePreview->setPageLayout(m_pageLayout);
690 }
691 
bottomMarginChanged(double newValue)692 void QPageSetupWidget::bottomMarginChanged(double newValue)
693 {
694     if (m_blockSignals)
695         return;
696     m_pageLayout.setBottomMargin(newValue);
697     m_pagePreview->setPageLayout(m_pageLayout);
698 }
699 
leftMarginChanged(double newValue)700 void QPageSetupWidget::leftMarginChanged(double newValue)
701 {
702     if (m_blockSignals)
703         return;
704     m_pageLayout.setLeftMargin(newValue);
705     m_pagePreview->setPageLayout(m_pageLayout);
706 }
707 
rightMarginChanged(double newValue)708 void QPageSetupWidget::rightMarginChanged(double newValue)
709 {
710     if (m_blockSignals)
711         return;
712     m_pageLayout.setRightMargin(newValue);
713     m_pagePreview->setPageLayout(m_pageLayout);
714 }
715 
716 // QPageSetupDialog
717 // - Public Linux / CUPS class implementation
718 
QPageSetupDialog(QPrinter * printer,QWidget * parent)719 QPageSetupDialog::QPageSetupDialog(QPrinter *printer, QWidget *parent)
720     : QDialog(*(new QUnixPageSetupDialogPrivate(printer)), parent)
721 {
722     Q_D(QPageSetupDialog);
723     setWindowTitle(QCoreApplication::translate("QPrintPreviewDialog", "Page Setup"));
724     static_cast<QUnixPageSetupDialogPrivate *>(d)->init();
725 }
726 
QPageSetupDialog(QWidget * parent)727 QPageSetupDialog::QPageSetupDialog(QWidget *parent)
728     : QDialog(*(new QUnixPageSetupDialogPrivate(nullptr)), parent)
729 {
730     Q_D(QPageSetupDialog);
731     setWindowTitle(QCoreApplication::translate("QPrintPreviewDialog", "Page Setup"));
732     static_cast<QUnixPageSetupDialogPrivate *>(d)->init();
733 }
734 
exec()735 int QPageSetupDialog::exec()
736 {
737     Q_D(QPageSetupDialog);
738 
739     int ret = QDialog::exec();
740     if (ret == Accepted) {
741         static_cast <QUnixPageSetupDialogPrivate*>(d)->widget->setupPrinter();
742         static_cast <QUnixPageSetupDialogPrivate*>(d)->widget->updateSavedValues();
743     } else {
744         static_cast <QUnixPageSetupDialogPrivate*>(d)->widget->revertToSavedValues();
745     }
746     return ret;
747 }
748 
749 QT_END_NAMESPACE
750 
751 #include "moc_qpagesetupdialog.cpp"
752