Skip to content

Commit

Permalink
macOS: Support printing when no printers are installed
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
torarnv committed Mar 9, 2020
1 parent 2097932 commit cc59f0d
Showing 1 changed file with 37 additions and 35 deletions.
72 changes: 37 additions & 35 deletions src/printsupport/dialogs/qprintdialog_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "qprintdialog.h"
#include "qabstractprintdialog_p.h"

#include <QtCore/qtemporarydir.h>
#include <QtCore/private/qcore_mac_p.h>
#include <QtWidgets/private/qapplication_p.h>
#include <QtPrintSupport/qprinter.h>
Expand Down Expand Up @@ -127,21 +128,36 @@ - (void)printPanelDidEnd:(NSPrintPanel *)printPanel
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<CFURLRef> 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<const char *>(localFile)));
*/
} else {
auto outputFile = QFileInfo(QString::fromUtf8(reinterpret_cast<const char *>(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);
}
Expand Down Expand Up @@ -199,14 +215,18 @@ - (void)printPanelDidEnd:(NSPrintPanel *)printPanel
{
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<NSPrintInfo *>(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<NSPrintInfo *>(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
Expand Down Expand Up @@ -269,31 +289,15 @@ - (void)printPanelDidEnd:(NSPrintPanel *)printPanel
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);
}

Expand All @@ -304,8 +308,6 @@ static bool warnIfNotNative(QPrinter *printer)
int QPrintDialog::exec()
{
Q_D(QPrintDialog);
if (!warnIfNotNative(d->printer))
return QDialog::Rejected;

QDialog::setVisible(true);

Expand Down

0 comments on commit cc59f0d

Please sign in to comment.