From cc59f0de557e2d8fba274a86ba43afc4ffcd935b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 2 Mar 2020 16:10:35 +0100 Subject: macOS: Support printing when no printers are installed Even if there are no printers installed, we can still show the print dialog, which gives the user feedback about no printers being installed, allows them to install one, or allows them to print to PDF as a fallback. The code for printing to PDF has been re-enabled, and the conditions of QTBUG-38820 have been removed as the problem is no longer present. The code also takes into account the possibility that the user chose to print to PostScript, which we don't yet support, but warn about. We now also support opening the printed document in Preview. This requires a minor assumption about the print operation being done synchronously after the print dialog is accepted, but this is something we can improve in the future with internal APIs if it turns out to be a problem. Printing workflows such as sending the printed document via mail or messenger are not not supported, and will give a warning. Fixes: QTBUG-36112 Change-Id: I8ba9e2c5ce31a5a06542c4a7126d005e4b27f2be Reviewed-by: Andy Shaw --- src/printsupport/dialogs/qprintdialog_mac.mm | 72 ++++++++++++++-------------- 1 file changed, 37 insertions(+), 35 deletions(-) (limited to 'src/printsupport') diff --git a/src/printsupport/dialogs/qprintdialog_mac.mm b/src/printsupport/dialogs/qprintdialog_mac.mm index ed2d0908c4..a4101f7ec0 100644 --- a/src/printsupport/dialogs/qprintdialog_mac.mm +++ b/src/printsupport/dialogs/qprintdialog_mac.mm @@ -42,6 +42,7 @@ #include "qprintdialog.h" #include "qabstractprintdialog_p.h" +#include #include #include #include @@ -127,21 +128,36 @@ QT_USE_NAMESPACE PMDestinationType dest; PMSessionGetDestinationType(session, settings, &dest); if (dest == kPMDestinationFile) { - // QTBUG-38820 - // If user selected Print to File, leave OSX to generate the PDF, - // otherwise setting PdfFormat would prevent us showing dialog again. - // TODO Restore this when QTBUG-36112 is fixed. - /* QCFType file; PMSessionCopyDestinationLocation(session, settings, &file); UInt8 localFile[2048]; // Assuming there's a POSIX file system here. CFURLGetFileSystemRepresentation(file, true, localFile, sizeof(localFile)); - printer->setOutputFileName(QString::fromUtf8(reinterpret_cast(localFile))); - */ - } else { + auto outputFile = QFileInfo(QString::fromUtf8(reinterpret_cast(localFile))); + if (outputFile.suffix() == QLatin1String("pdf")) + printer->setOutputFileName(outputFile.absoluteFilePath()); + else + qWarning() << "Can not print to file type" << outputFile.suffix(); + } else if (dest == kPMDestinationPreview) { + static QTemporaryDir printPreviews; + auto documentName = printer->docName(); + if (documentName.isEmpty()) + documentName = QGuiApplication::applicationDisplayName(); + auto fileName = printPreviews.filePath(QString(QLatin1String("%1.pdf")).arg(documentName)); + printer->setOutputFileName(fileName); + // Ideally we would have a callback when the PDF engine is done writing + // to the file, and open Preview in response to that. Lacking that, we + // use the quick and dirty assumption that the the print operation will + // happen synchronously after the dialog is accepted, so we can defer + // the opening of the file to the next runloop pass. + dispatch_async(dispatch_get_main_queue(), ^{ + [NSWorkspace.sharedWorkspace openFile:fileName.toNSString()]; + }); + } else if (dest == kPMDestinationProcessPDF) { + qWarning("Printing workflows are not supported"); + } else if (dest == kPMDestinationPrinter) { PMPrinter macPrinter; PMSessionGetCurrentPrinter(session, &macPrinter); - QString printerId = QString::fromCFString(PMPrinterGetID(macPrinter)); + QString printerId = QString::fromCFString(PMPrinterGetID(macPrinter)).trimmed(); if (printer->printerName() != printerId) printer->setPrinterName(printerId); } @@ -199,14 +215,18 @@ void QPrintDialogPrivate::openCocoaPrintPanel(Qt::WindowModality modality) { Q_Q(QPrintDialog); - // get the NSPrintInfo from the print engine in the platform plugin - void *voidp = 0; - (void) QMetaObject::invokeMethod(qApp->platformNativeInterface(), - "NSPrintInfoForPrintEngine", - Q_RETURN_ARG(void *, voidp), - Q_ARG(QPrintEngine *, printer->printEngine())); - printInfo = static_cast(voidp); - [printInfo retain]; + if (printer->outputFormat() == QPrinter::NativeFormat) { + // get the NSPrintInfo from the print engine in the platform plugin + void *voidp = 0; + (void) QMetaObject::invokeMethod(qApp->platformNativeInterface(), + "NSPrintInfoForPrintEngine", + Q_RETURN_ARG(void *, voidp), + Q_ARG(QPrintEngine *, printer->printEngine())); + printInfo = static_cast(voidp); + [printInfo retain]; + } else { + printInfo = [NSPrintInfo.sharedPrintInfo retain]; + } // It seems the only way that PM lets you use all is if the minimum // for the page range is 1. This _kind of_ makes sense if you think about @@ -269,31 +289,15 @@ void QPrintDialogPrivate::closeCocoaPrintPanel() printPanel = 0; } -static bool warnIfNotNative(QPrinter *printer) -{ - if (printer->outputFormat() != QPrinter::NativeFormat) { - qWarning("QPrintDialog: Cannot be used on non-native printers"); - return false; - } - return true; -} - - QPrintDialog::QPrintDialog(QPrinter *printer, QWidget *parent) : QAbstractPrintDialog(*(new QPrintDialogPrivate), printer, parent) { - Q_D(QPrintDialog); - if (!warnIfNotNative(d->printer)) - return; setAttribute(Qt::WA_DontShowOnScreen); } QPrintDialog::QPrintDialog(QWidget *parent) : QAbstractPrintDialog(*(new QPrintDialogPrivate), 0, parent) { - Q_D(QPrintDialog); - if (!warnIfNotNative(d->printer)) - return; setAttribute(Qt::WA_DontShowOnScreen); } @@ -304,8 +308,6 @@ QPrintDialog::~QPrintDialog() int QPrintDialog::exec() { Q_D(QPrintDialog); - if (!warnIfNotNative(d->printer)) - return QDialog::Rejected; QDialog::setVisible(true); -- cgit v1.2.3