QPrinter - Fix OutputFormat when no printers
Currently the QPrinter constructor, setOutputFormat() and setPrinterName() make bad assumptions about the availability of printers when configuring NativeFormat which can lead to inconsistent print engine set-ups leading to crashes in the print dialog, especially on Windows where a valid DEVMODE is needed. This change cleans up the init and methods to ensure NativeFormat can only ever be set if we have both a valid plugin and a valid printer, if not the PdfFormat is used. One side-effect of this is that it is now impossible to set an invalid printer name via QPrinter (but still able to be done via QPrintEngine if really needed). Also if no default printer is set then use the first available one. This also fixes a bug where setting a new printer name on Windows reset all the saved settings. [ChangeLog][Important Behavior Changes] QPrinter no longer allows you to set an invalid printer name. Task-number: QTBUG-34345 Task-number: QTBUG-26008 Task-number: QTBUG-26430 Change-Id: I19737e4209d8c8df5817ea83246b3dd0c483ee85 Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
This commit is contained in:
parent
7079f11213
commit
e8a45152b5
@ -48,7 +48,6 @@
|
||||
#include <qpa/qplatformprintersupport.h>
|
||||
|
||||
#include "qprintengine.h"
|
||||
#include "qprinterinfo.h"
|
||||
#include "qlist.h"
|
||||
#include <qcoreapplication.h>
|
||||
#include <qfileinfo.h>
|
||||
@ -163,10 +162,39 @@ Q_PRINTSUPPORT_EXPORT QSizeF qt_printerPaperSize(QPrinter::Orientation orientati
|
||||
(qt_paperSizes[paperSize][height_index] * 72 / 25.4) / multiplier);
|
||||
}
|
||||
|
||||
void QPrinterPrivate::createDefaultEngines()
|
||||
QPrinterInfo QPrinterPrivate::findValidPrinter(const QPrinterInfo &printer)
|
||||
{
|
||||
QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();
|
||||
if (outputFormat == QPrinter::NativeFormat && ps) {
|
||||
// Try find a valid printer to use, either the one given, the default or the first available
|
||||
QPrinterInfo printerToUse = printer;
|
||||
if (printerToUse.isNull()) {
|
||||
printerToUse = QPrinterInfo::defaultPrinter();
|
||||
if (printerToUse.isNull()) {
|
||||
QList<QPrinterInfo> availablePrinters = QPrinterInfo::availablePrinters();
|
||||
if (!availablePrinters.isEmpty())
|
||||
printerToUse = availablePrinters.at(0);
|
||||
}
|
||||
}
|
||||
return printerToUse;
|
||||
}
|
||||
|
||||
void QPrinterPrivate::initEngines(QPrinter::OutputFormat format, const QPrinterInfo &printer)
|
||||
{
|
||||
// Default to PdfFormat
|
||||
outputFormat = QPrinter::PdfFormat;
|
||||
QPlatformPrinterSupport *ps = 0;
|
||||
QString printerName;
|
||||
|
||||
// Only set NativeFormat if we have a valid plugin and printer to use
|
||||
if (format == QPrinter::NativeFormat) {
|
||||
ps = QPlatformPrinterSupportPlugin::get();
|
||||
QPrinterInfo printerToUse = findValidPrinter(printer);
|
||||
if (ps && !printerToUse.isNull()) {
|
||||
outputFormat = QPrinter::NativeFormat;
|
||||
printerName = printerToUse.printerName();
|
||||
}
|
||||
}
|
||||
|
||||
if (outputFormat == QPrinter::NativeFormat) {
|
||||
printEngine = ps->createNativePrintEngine(printerMode);
|
||||
paintEngine = ps->createPaintEngine(printEngine, printerMode);
|
||||
} else {
|
||||
@ -174,8 +202,42 @@ void QPrinterPrivate::createDefaultEngines()
|
||||
paintEngine = pdfEngine;
|
||||
printEngine = pdfEngine;
|
||||
}
|
||||
|
||||
use_default_engine = true;
|
||||
had_default_engines = true;
|
||||
printEngine->setProperty(QPrintEngine::PPK_PrinterName, printerName);
|
||||
addToManualSetList(QPrintEngine::PPK_PrinterName);
|
||||
validPrinter = true;
|
||||
}
|
||||
|
||||
void QPrinterPrivate::changeEngines(QPrinter::OutputFormat format, const QPrinterInfo &printer)
|
||||
{
|
||||
QPrintEngine *oldPrintEngine = printEngine;
|
||||
const bool def_engine = use_default_engine;
|
||||
|
||||
initEngines(format, printer);
|
||||
|
||||
if (oldPrintEngine) {
|
||||
for (int i = 0; i < manualSetList.size(); ++i) {
|
||||
QPrintEngine::PrintEnginePropertyKey key = manualSetList[i];
|
||||
QVariant prop;
|
||||
// PPK_NumberOfCopies need special treatmeant since it in most cases
|
||||
// will return 1, disregarding the actual value that was set
|
||||
// PPK_PrinterName also needs special treatment as initEngines has set it already
|
||||
if (key == QPrintEngine::PPK_NumberOfCopies)
|
||||
prop = QVariant(q_ptr->copyCount());
|
||||
else if (key != QPrintEngine::PPK_PrinterName)
|
||||
prop = oldPrintEngine->property(key);
|
||||
|
||||
if (prop.isValid()) {
|
||||
printEngine->setProperty(key, prop);
|
||||
addToManualSetList(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (def_engine)
|
||||
delete oldPrintEngine;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_PRINTPREVIEWWIDGET
|
||||
@ -510,13 +572,7 @@ QPrinter::QPrinter(PrinterMode mode)
|
||||
: QPagedPaintDevice(),
|
||||
d_ptr(new QPrinterPrivate(this))
|
||||
{
|
||||
d_ptr->init(mode);
|
||||
QPrinterInfo defPrn(QPrinterInfo::defaultPrinter());
|
||||
if (!defPrn.isNull()) {
|
||||
setPrinterName(defPrn.printerName());
|
||||
} else if (QPrinterInfo::availablePrinters().isEmpty()) {
|
||||
setOutputFormat(QPrinter::PdfFormat);
|
||||
}
|
||||
d_ptr->init(QPrinterInfo(), mode);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -528,11 +584,10 @@ QPrinter::QPrinter(const QPrinterInfo& printer, PrinterMode mode)
|
||||
: QPagedPaintDevice(),
|
||||
d_ptr(new QPrinterPrivate(this))
|
||||
{
|
||||
d_ptr->init(mode);
|
||||
setPrinterName(printer.printerName());
|
||||
d_ptr->init(printer, mode);
|
||||
}
|
||||
|
||||
void QPrinterPrivate::init(QPrinter::PrinterMode mode)
|
||||
void QPrinterPrivate::init(const QPrinterInfo &printer, QPrinter::PrinterMode mode)
|
||||
{
|
||||
if (!QCoreApplication::instance()) {
|
||||
qFatal("QPrinter: Must construct a QCoreApplication before a QPrinter");
|
||||
@ -540,14 +595,8 @@ void QPrinterPrivate::init(QPrinter::PrinterMode mode)
|
||||
}
|
||||
|
||||
printerMode = mode;
|
||||
outputFormat = QPrinter::NativeFormat;
|
||||
createDefaultEngines();
|
||||
|
||||
#ifndef QT_NO_PRINTPREVIEWWIDGET
|
||||
previewEngine = 0;
|
||||
#endif
|
||||
realPrintEngine = 0;
|
||||
realPaintEngine = 0;
|
||||
initEngines(QPrinter::NativeFormat, printer);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -612,40 +661,30 @@ QPrinter::~QPrinter()
|
||||
\since 4.1
|
||||
|
||||
Sets the output format for this printer to \a format.
|
||||
|
||||
If \a format is the same value as currently set then no change will be made.
|
||||
|
||||
If \a format is NativeFormat then the printerName will be set to the default
|
||||
printer. If there are no valid printers configured then no change will be made.
|
||||
If you want to set NativeFormat with a specific printerName then use
|
||||
setPrinterName().
|
||||
|
||||
\sa setPrinterName()
|
||||
*/
|
||||
void QPrinter::setOutputFormat(OutputFormat format)
|
||||
{
|
||||
Q_D(QPrinter);
|
||||
if (d->validPrinter && d->outputFormat == format)
|
||||
|
||||
if (d->outputFormat == format)
|
||||
return;
|
||||
d->outputFormat = format;
|
||||
|
||||
QPrintEngine *oldPrintEngine = d->printEngine;
|
||||
const bool def_engine = d->use_default_engine;
|
||||
d->printEngine = 0;
|
||||
|
||||
d->createDefaultEngines();
|
||||
|
||||
if (oldPrintEngine) {
|
||||
for (int i = 0; i < d->manualSetList.size(); ++i) {
|
||||
QPrintEngine::PrintEnginePropertyKey key = d->manualSetList[i];
|
||||
QVariant prop;
|
||||
// PPK_NumberOfCopies need special treatmeant since it in most cases
|
||||
// will return 1, disregarding the actual value that was set
|
||||
if (key == QPrintEngine::PPK_NumberOfCopies)
|
||||
prop = QVariant(copyCount());
|
||||
else
|
||||
prop = oldPrintEngine->property(key);
|
||||
if (prop.isValid())
|
||||
d->printEngine->setProperty(key, prop);
|
||||
}
|
||||
if (format == QPrinter::NativeFormat) {
|
||||
QPrinterInfo printerToUse = d->findValidPrinter();
|
||||
if (!printerToUse.isNull())
|
||||
d->changeEngines(format, printerToUse);
|
||||
} else {
|
||||
d->changeEngines(format, QPrinterInfo());
|
||||
}
|
||||
|
||||
if (def_engine)
|
||||
delete oldPrintEngine;
|
||||
|
||||
if (d->outputFormat == QPrinter::PdfFormat)
|
||||
d->validPrinter = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -683,30 +722,38 @@ QString QPrinter::printerName() const
|
||||
/*!
|
||||
Sets the printer name to \a name.
|
||||
|
||||
\sa printerName(), isValid()
|
||||
If the \a name is empty then the output format will be set to PdfFormat.
|
||||
|
||||
If the \a name is not a valid printer then no change will be made.
|
||||
|
||||
If the \a name is a valid printer then the output format will be set to NativeFormat.
|
||||
|
||||
\sa printerName(), isValid(), setOutputFormat()
|
||||
*/
|
||||
void QPrinter::setPrinterName(const QString &name)
|
||||
{
|
||||
Q_D(QPrinter);
|
||||
ABORT_IF_ACTIVE("QPrinter::setPrinterName");
|
||||
|
||||
QList<QPrinterInfo> prnList = QPrinterInfo::availablePrinters();
|
||||
if (printerName() == name)
|
||||
return;
|
||||
|
||||
if (name.isEmpty()) {
|
||||
d->validPrinter = d->outputFormat == QPrinter::PdfFormat;
|
||||
} else {
|
||||
d->validPrinter = false;
|
||||
for (int i = 0; i < prnList.size(); ++i) {
|
||||
if (prnList[i].printerName() == name) {
|
||||
d->validPrinter = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
setOutputFormat(QPrinter::PdfFormat);
|
||||
return;
|
||||
}
|
||||
|
||||
d->printEngine->setProperty(QPrintEngine::PPK_PrinterName, name);
|
||||
d->addToManualSetList(QPrintEngine::PPK_PrinterName);
|
||||
}
|
||||
QPrinterInfo printerToUse = QPrinterInfo::printerInfo(name);
|
||||
if (printerToUse.isNull())
|
||||
return;
|
||||
|
||||
if (outputFormat() == QPrinter::PdfFormat) {
|
||||
d->changeEngines(QPrinter::NativeFormat, printerToUse);
|
||||
} else {
|
||||
d->printEngine->setProperty(QPrintEngine::PPK_PrinterName, name);
|
||||
d->addToManualSetList(QPrintEngine::PPK_PrinterName);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 4.4
|
||||
|
@ -59,6 +59,7 @@
|
||||
#ifndef QT_NO_PRINTER
|
||||
|
||||
#include "QtPrintSupport/qprinter.h"
|
||||
#include "QtPrintSupport/qprinterinfo.h"
|
||||
#include "QtPrintSupport/qprintengine.h"
|
||||
#include "QtCore/qpointer.h"
|
||||
|
||||
@ -75,14 +76,19 @@ class Q_PRINTSUPPORT_EXPORT QPrinterPrivate
|
||||
Q_DECLARE_PUBLIC(QPrinter)
|
||||
public:
|
||||
QPrinterPrivate(QPrinter *printer)
|
||||
: printEngine(0)
|
||||
, paintEngine(0)
|
||||
, q_ptr(printer)
|
||||
, printRange(QPrinter::AllPages)
|
||||
, use_default_engine(true)
|
||||
, validPrinter(false)
|
||||
, hasCustomPageMargins(false)
|
||||
, hasUserSetPageSize(false)
|
||||
: printEngine(0),
|
||||
paintEngine(0),
|
||||
realPrintEngine(0),
|
||||
realPaintEngine(0),
|
||||
#ifndef QT_NO_PRINTPREVIEWWIDGET
|
||||
previewEngine(0),
|
||||
#endif
|
||||
q_ptr(printer),
|
||||
printRange(QPrinter::AllPages),
|
||||
use_default_engine(true),
|
||||
validPrinter(false),
|
||||
hasCustomPageMargins(false),
|
||||
hasUserSetPageSize(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -90,9 +96,11 @@ public:
|
||||
|
||||
}
|
||||
|
||||
void init(QPrinter::PrinterMode mode);
|
||||
void init(const QPrinterInfo &printer, QPrinter::PrinterMode mode);
|
||||
|
||||
void createDefaultEngines();
|
||||
QPrinterInfo findValidPrinter(const QPrinterInfo &printer = QPrinterInfo());
|
||||
void initEngines(QPrinter::OutputFormat format, const QPrinterInfo &printer);
|
||||
void changeEngines(QPrinter::OutputFormat format, const QPrinterInfo &printer);
|
||||
#ifndef QT_NO_PRINTPREVIEWWIDGET
|
||||
QList<const QPicture *> previewPages() const;
|
||||
void setPreviewMode(bool);
|
||||
|
@ -207,9 +207,6 @@ void tst_QPrinter::getSetCheck()
|
||||
QCOMPARE(obj1.printerSelectionOption(), QString::fromLatin1("--option"));
|
||||
#endif
|
||||
|
||||
obj1.setPrinterName(QString::fromLatin1("myPrinter"));
|
||||
QCOMPARE(obj1.printerName(), QString::fromLatin1("myPrinter"));
|
||||
|
||||
// bool QPrinter::fontEmbeddingEnabled()
|
||||
// void QPrinter::setFontEmbeddingEnabled(bool)
|
||||
obj1.setFontEmbeddingEnabled(false);
|
||||
@ -461,7 +458,7 @@ void tst_QPrinter::testNonExistentPrinter()
|
||||
QPainter painter;
|
||||
|
||||
// Make sure it doesn't crash on setting or getting properties
|
||||
printer.setPrinterName("some non existing printer");
|
||||
printer.printEngine()->setProperty(QPrintEngine::PPK_PrinterName, "some non existing printer");
|
||||
printer.setPageSize(QPrinter::A4);
|
||||
printer.setOrientation(QPrinter::Portrait);
|
||||
printer.setFullPage(true);
|
||||
@ -709,9 +706,6 @@ void tst_QPrinter::valuePreservation()
|
||||
|
||||
printer.setCollateCopies(!status);
|
||||
printer.setOutputFormat(newFormat);
|
||||
#ifdef Q_OS_MAC
|
||||
QEXPECT_FAIL("","QTBUG-26430", Abort);
|
||||
#endif
|
||||
QCOMPARE(printer.collateCopies(), !status);
|
||||
printer.setOutputFormat(oldFormat);
|
||||
QCOMPARE(printer.collateCopies(), !status);
|
||||
@ -909,13 +903,6 @@ void tst_QPrinter::valuePreservation()
|
||||
printer.setOutputFormat(newFormat);
|
||||
printer.setOutputFormat(oldFormat);
|
||||
QCOMPARE(printer.printerName(), status);
|
||||
|
||||
status = QString::fromLatin1("SuperDuperPrinter");
|
||||
printer.setPrinterName(status);
|
||||
printer.setOutputFormat(newFormat);
|
||||
QCOMPARE(printer.printerName(), status);
|
||||
printer.setOutputFormat(oldFormat);
|
||||
QCOMPARE(printer.printerName(), status);
|
||||
}
|
||||
// QPrinter::printerSelectionOption is explicitly documented not to be available on Windows.
|
||||
#ifndef Q_OS_WIN
|
||||
|
Loading…
Reference in New Issue
Block a user