e1d85eed59a862fe7b3b70b7d80b31ce1c156caa
[profile/ivi/qtbase.git] / src / printsupport / dialogs / qprintdialog_mac.mm
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QT_NO_PRINTDIALOG
43
44 #include <Cocoa/Cocoa.h>
45
46 #include "qprintdialog.h"
47 #include "qabstractprintdialog_p.h"
48
49 #include <QtCore/qhash.h>
50 #include <QtCore/private/qcore_mac_p.h>
51 #include <QtWidgets/private/qapplication_p.h>
52 #include <QtPrintSupport/qprinter.h>
53 #include <QtPrintSupport/qprintengine.h>
54
55 QT_BEGIN_NAMESPACE
56
57 class QPrintDialogPrivate : public QAbstractPrintDialogPrivate
58 {
59     Q_DECLARE_PUBLIC(QPrintDialog)
60
61 public:
62     QPrintDialogPrivate() : printInfo(0), printPanel(0)
63        {}
64
65     void openCocoaPrintPanel(Qt::WindowModality modality);
66     void closeCocoaPrintPanel();
67
68     inline QPrintDialog *printDialog() { return q_func(); }
69
70     inline void _q_printToFileChanged(int) {}
71     inline void _q_rbPrintRangeToggled(bool) {}
72     inline void _q_printerChanged(int) {}
73 #ifndef QT_NO_MESSAGEBOX
74     inline void _q_checkFields() {}
75 #endif
76     inline void _q_chbPrintLastFirstToggled(bool) {}
77     inline void _q_paperSizeChanged(int) {}
78     inline void _q_btnBrowseClicked() {}
79     inline void _q_btnPropertiesClicked() {}
80
81     NSPrintInfo *printInfo;
82     NSPrintPanel *printPanel;
83 };
84
85 QT_END_NAMESPACE
86
87 QT_USE_NAMESPACE
88
89
90 @class QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate);
91
92 @interface QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) : NSObject
93 {
94     NSPrintInfo *printInfo;
95 }
96 - (id)initWithNSPrintInfo:(NSPrintInfo *)nsPrintInfo;
97 - (void)printPanelDidEnd:(NSPrintPanel *)printPanel
98         returnCode:(int)returnCode contextInfo:(void *)contextInfo;
99 @end
100
101 @implementation QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate)
102 - (id)initWithNSPrintInfo:(NSPrintInfo *)nsPrintInfo
103 {
104     if (self = [super init]) {
105         printInfo = nsPrintInfo;
106     }
107     return self;
108 }
109 - (void)printPanelDidEnd:(NSPrintPanel *)printPanel
110         returnCode:(int)returnCode contextInfo:(void *)contextInfo
111 {
112     Q_UNUSED(printPanel);
113
114     QPrintDialog *dialog = static_cast<QPrintDialog *>(contextInfo);
115     QPrinter *printer = dialog->printer();
116
117     if (returnCode == NSOKButton) {
118         PMPrintSession session = static_cast<PMPrintSession>([printInfo PMPrintSession]);
119         PMPrintSettings settings = static_cast<PMPrintSettings>([printInfo PMPrintSettings]);
120
121         UInt32 frompage, topage;
122         PMGetFirstPage(settings, &frompage);
123         PMGetLastPage(settings, &topage);
124         topage = qMin(UInt32(INT_MAX), topage);
125         dialog->setFromTo(frompage, topage);
126
127         // OK, I need to map these values back let's see
128         // If from is 1 and to is INT_MAX, then print it all
129         // (Apologies to the folks with more than INT_MAX pages)
130         if (dialog->fromPage() == 1 && dialog->toPage() == INT_MAX) {
131             dialog->setPrintRange(QPrintDialog::AllPages);
132             dialog->setFromTo(0, 0);
133         } else {
134             dialog->setPrintRange(QPrintDialog::PageRange); // In a way a lie, but it shouldn't hurt.
135             // Carbon hands us back a very large number here even for ALL, set it to max
136             // in that case to follow the behavior of the other print dialogs.
137             if (dialog->maxPage() < dialog->toPage())
138                 dialog->setFromTo(dialog->fromPage(), dialog->maxPage());
139         }
140         // Keep us in sync with file output
141         PMDestinationType dest;
142
143         // If the user selected print to file, the session has been
144         // changed behind our back and our d->ep->session object is a
145         // dangling pointer. Update it based on the "current" session
146         PMSessionGetDestinationType(session, settings, &dest);
147         if (dest == kPMDestinationFile) {
148             QCFType<CFURLRef> file;
149             PMSessionCopyDestinationLocation(session, settings, &file);
150             UInt8 localFile[2048];  // Assuming there's a POSIX file system here.
151             CFURLGetFileSystemRepresentation(file, true, localFile, sizeof(localFile));
152             printer->setOutputFileName(QString::fromUtf8(reinterpret_cast<const char *>(localFile)));
153         } else {
154             // Keep output format.
155             QPrinter::OutputFormat format;
156             format = printer->outputFormat();
157             printer->setOutputFileName(QString());
158             printer->setOutputFormat(format);
159         }
160     }
161
162     dialog->done((returnCode == NSOKButton) ? QDialog::Accepted : QDialog::Rejected);
163 }
164 @end
165
166 QT_BEGIN_NAMESPACE
167
168 void QPrintDialogPrivate::openCocoaPrintPanel(Qt::WindowModality modality)
169 {
170     Q_Q(QPrintDialog);
171
172     // get the NSPrintInfo from the print engine in the platform plugin
173     void *voidp = 0;
174     (void) QMetaObject::invokeMethod(qApp->platformNativeInterface(),
175                                      "NSPrintInfoForPrintEngine",
176                                      Q_RETURN_ARG(void *, voidp),
177                                      Q_ARG(QPrintEngine *, printer->printEngine()));
178     printInfo = static_cast<NSPrintInfo *>(voidp);
179     [printInfo retain];
180
181     // It seems the only way that PM lets you use all is if the minimum
182     // for the page range is 1. This _kind of_ makes sense if you think about
183     // it. However, calling PMSetFirstPage() or PMSetLastPage() always enforces
184     // the range.
185     // get print settings from the platform plugin
186     PMPrintSettings settings = static_cast<PMPrintSettings>([printInfo PMPrintSettings]);
187     PMSetPageRange(settings, q->minPage(), q->maxPage());
188     if (q->printRange() == QAbstractPrintDialog::PageRange) {
189         PMSetFirstPage(settings, q->fromPage(), false);
190         PMSetLastPage(settings, q->toPage(), false);
191     }
192     [printInfo updateFromPMPrintSettings];
193
194     QPrintDialog::PrintDialogOptions qtOptions = q->options();
195     NSPrintPanelOptions macOptions = NSPrintPanelShowsCopies;
196     if (qtOptions & QPrintDialog::PrintPageRange)
197         macOptions |= NSPrintPanelShowsPageRange;
198     if (qtOptions & QPrintDialog::PrintShowPageSize)
199         macOptions |= NSPrintPanelShowsPaperSize | NSPrintPanelShowsPageSetupAccessory
200                       | NSPrintPanelShowsOrientation;
201
202     printPanel = [NSPrintPanel printPanel];
203     [printPanel retain];
204     [printPanel setOptions:macOptions];
205
206     QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) alloc] init];
207     if (modality == Qt::ApplicationModal) {
208         int rval = [printPanel runModalWithPrintInfo:printInfo];
209         [delegate printPanelDidEnd:printPanel returnCode:rval contextInfo:q];
210     } else {
211         Q_ASSERT(q->parentWidget());
212         QWindow *parentWindow = q->parentWidget()->windowHandle();
213         NSWindow *window = static_cast<NSWindow *>(qApp->platformNativeInterface()->nativeResourceForWindow("nswindow", parentWindow));
214         [printPanel beginSheetWithPrintInfo:printInfo
215                              modalForWindow:window
216                                    delegate:delegate
217                              didEndSelector:@selector(printPanelDidEnd:returnCode:contextInfo:)
218                                 contextInfo:q];
219     }
220 }
221
222 void QPrintDialogPrivate::closeCocoaPrintPanel()
223 {
224     [printInfo release];
225     printInfo = 0;
226     [printPanel release];
227     printPanel = 0;
228 }
229
230 static bool warnIfNotNative(QPrinter *printer)
231 {
232     if (printer->outputFormat() != QPrinter::NativeFormat) {
233         qWarning("QPrintDialog: Cannot be used on non-native printers");
234         return false;
235     }
236     return true;
237 }
238
239
240 QPrintDialog::QPrintDialog(QPrinter *printer, QWidget *parent)
241     : QAbstractPrintDialog(*(new QPrintDialogPrivate), printer, parent)
242 {
243     Q_D(QPrintDialog);
244     if (!warnIfNotNative(d->printer))
245         return;
246     setAttribute(Qt::WA_DontShowOnScreen);
247 }
248
249 QPrintDialog::QPrintDialog(QWidget *parent)
250     : QAbstractPrintDialog(*(new QPrintDialogPrivate), 0, parent)
251 {
252     Q_D(QPrintDialog);
253     if (!warnIfNotNative(d->printer))
254         return;
255     setAttribute(Qt::WA_DontShowOnScreen);
256 }
257
258 QPrintDialog::~QPrintDialog()
259 {
260 }
261
262 int QPrintDialog::exec()
263 {
264     Q_D(QPrintDialog);
265     if (!warnIfNotNative(d->printer))
266         return QDialog::Rejected;
267
268     QDialog::setVisible(true);
269
270     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
271     d->openCocoaPrintPanel(Qt::ApplicationModal);
272     d->closeCocoaPrintPanel();
273     [pool release];
274
275     QDialog::setVisible(false);
276
277     return result();
278 }
279
280
281 /*!
282     \reimp
283 */
284 void QPrintDialog::setVisible(bool visible)
285 {
286     Q_D(QPrintDialog);
287
288     bool isCurrentlyVisible = (d->printPanel != 0);
289
290     if (!visible == !isCurrentlyVisible)
291         return;
292
293     if (d->printer->outputFormat() != QPrinter::NativeFormat)
294         return;
295
296     QDialog::setVisible(visible);
297
298     if (visible) {
299         Qt::WindowModality modality = windowModality();
300         if (modality == Qt::NonModal) {
301             // NSPrintPanels can only be modal, so we must pick a type
302             modality = parentWidget() ? Qt::WindowModal : Qt::ApplicationModal;
303         }
304         d->openCocoaPrintPanel(modality);
305         return;
306     } else {
307         if (d->printPanel) {
308             d->closeCocoaPrintPanel();
309             return;
310         }
311     }
312 }
313
314 QT_END_NAMESPACE
315
316 #include "moc_qprintdialog.cpp"
317
318 #endif // QT_NO_PRINTDIALOG