Use setNSToolbar from the cocoa platform plugin
[qt:qtmacextras.git] / src / macextras / qmactoolbar.mm
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtMacExtras 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 Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #import <AppKit/AppKit.h>
42 #include "qmactoolbar.h"
43 #include "qmactoolbar_p.h"
44
45 #include <QtCore/QDebug>
46 #include <QtCore/QTimer>
47 #include <QtCore/QUuid>
48 #include <QtCore/qdebug.h>
49
50 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
51 #include <QtGui/QGuiApplication>
52 #include <qpa/qplatformnativeinterface.h>
53 #else
54 #include <QtGui/QMainWindow>
55 #endif
56
57 #include "qmacfunctions.h"
58 #include "qmacfunctions_p.h"
59 #include "qmactoolbaritem_p.h"
60 #include "qmactoolbardelegate_p.h"
61 #include "qnstoolbar_p.h"
62
63 QT_BEGIN_NAMESPACE
64
65 /*!
66   \class QMacToolBar
67   \inmodule QtMacExtras
68   \since 5.3
69   \brief The QMacToolBar class wraps the native NSToolbar class.
70
71   QMacToolBar provides a Qt-based API for NSToolBar. The toolbar displays one or
72   more \e items. Each toolbar item has an icon and a text label.
73
74   The toolbar must be attached to a QWindow with \fn attachToWindow in order to be
75   visible. The toolbar is attached to the native NSWindow and is displayed above
76   the QWindow. QMacToolBar visibility follows window visibility.
77
78   Add items by calling addItem(). The toolbar has a customization menu which
79   is available to the user from the toolbar context menu. Use addAllowedItem() to
80   add items to the customization menu.
81
82   Usage: (QtWidgets)
83   \code
84     QMacToolBar *toolBar = new QMacToolBar(this);
85     QMacToolBarItem *toolBarItem = toolBar->addItem(QIcon(), QStringLiteral("foo"));
86     connect(toolButton, SIGNAL(activated()), this, SLOT(fooClicked()))
87
88     this->window()->winId(); // create window->windowhandle()
89     toolBar->attachToWindow(this->window()->windowHandle())
90   \endcode
91
92   \sa QMacToolBarItem
93 */
94
95 /*!
96     Constructs a QMacToolBar with the given \a parent
97 */
98 QMacToolBar::QMacToolBar(QObject *parent)
99     : QObject(*new QMacToolBarPrivate(), parent)
100 {
101 }
102
103 /*!
104     Constructs a QMacToolBar with the given \a identifier and \a parent. The identifier is used
105     to uniquely identify the toolbar within the appliation, for example when autosaving the
106     toolbar configuration.
107 */
108 QMacToolBar::QMacToolBar(const QString &identifier, QObject *parent)
109     : QObject(*new QMacToolBarPrivate(identifier), parent)
110 {
111 }
112
113 /*!
114     Destroys the toolbar.
115 */
116 QMacToolBar::~QMacToolBar()
117 {
118     Q_D(QMacToolBar);
119     [d->toolbar release];
120 }
121
122 /*!
123     Add a toolbar item with \a icon and \a text.
124 */
125 QMacToolBarItem *QMacToolBar::addItem(const QIcon &icon, const QString &text)
126 {
127     Q_D(QMacToolBar);
128     QMacToolBarItem *item = new QMacToolBarItem(this);
129     item->setText(text);
130     item->setIcon(icon);
131     d->items.append(item);
132     d->allowedItems.append(item);
133     return item;
134 }
135
136 /*!
137     Add a toolbar separator item.
138 */
139 void QMacToolBar::addSeparator()
140 {
141     addStandardItem(QMacToolBarItem::Space); // No Seprator on OS X.
142 }
143
144 /*!
145     Add a toolbar standard item.
146     \omitvalue standardItem
147     \internal
148 */
149 QMacToolBarItem *QMacToolBar::addStandardItem(QMacToolBarItem::StandardItem standardItem)
150 {
151     Q_D(QMacToolBar);
152     QMacToolBarItem *item = new QMacToolBarItem(this);
153     item->setStandardItem(standardItem);
154     d->items.append(item);
155     d->allowedItems.append(item);
156     return item;
157 }
158
159 /*!
160     Add atoolbar item with \a icon and \a text to the toolbar customization menu.
161 */
162 QMacToolBarItem *QMacToolBar::addAllowedItem(const QIcon &icon, const QString &text)
163 {
164     Q_D(QMacToolBar);
165     QMacToolBarItem *item = new QMacToolBarItem(this);
166     item->setText(text);
167     item->setIcon(icon);
168     d->allowedItems.append(item);
169     return item;
170 }
171
172 /*!
173     Add a standard toolbar item to the toolbar customization menu.
174     \omitvalue standardItem
175     \internal
176 */
177 QMacToolBarItem *QMacToolBar::addAllowedStandardItem(QMacToolBarItem::StandardItem standardItem)
178 {
179     Q_D(QMacToolBar);
180     QMacToolBarItem *item = new QMacToolBarItem(this);
181     item->setStandardItem(standardItem);
182     d->allowedItems.append(item);
183     return item;
184 }
185
186 /*!
187     Sets the list of the default toolbar items.
188 */
189 void QMacToolBar::setItems(QList<QMacToolBarItem *> &items)
190 {
191     Q_D(QMacToolBar);
192     d->items = items;
193 }
194
195 /*!
196     Returns the list of the default toolbar items.
197 */
198 QList<QMacToolBarItem *> QMacToolBar::items()
199 {
200     Q_D(QMacToolBar);
201     return d->items;
202 }
203
204 /*!
205     Sets the list of toolbar items shown on the the toolbar customization menu.
206 */
207 void QMacToolBar::setAllowedItems(QList<QMacToolBarItem *> &allowedItems)
208 {
209     Q_D(QMacToolBar);
210     d->allowedItems = allowedItems;
211 }
212
213 /*!
214     Returns the list oftoolbar items shown on the the toolbar customization menu.
215 */
216 QList<QMacToolBarItem *> QMacToolBar::allowedItems()
217 {
218     Q_D(QMacToolBar);
219     return d->allowedItems;
220 }
221
222 /*!
223     Attaches the toolbar to \a window. The toolbar will be displayed at the top of the
224     native window, under and attached to the title bar above the QWindow. The toolbar is displayed
225     outside the QWidnow area.
226
227     Use QWidget::windowHandle() to get a QWindow pointer from a QWidget instance. At app startup
228     the QWindow might not have been created yet, call QWidget::winId() to make sure it is.
229 */
230 void QMacToolBar::attachToWindow(QWindow *window)
231 {
232     Q_D(QMacToolBar);
233     if (!window) {
234         detachFromWindow();
235         return;
236     }
237
238     QPlatformNativeInterface::NativeResourceForIntegrationFunction function = resolvePlatformFunction("setNSToolbar");
239     if (function) {
240         typedef void (*SetNSToolbarFunction)(QWindow *window, void *nsToolbar);
241         reinterpret_cast<SetNSToolbarFunction>(function)(window, d->toolbar);
242     } else {
243         d->targetWindow = window;
244         QTimer::singleShot(100, this, SLOT(showInWindow_impl())); // ### hackety hack
245     }
246 }
247
248 /*!
249     \internal
250 */
251 void QMacToolBar::showInWindow_impl()
252 {
253     Q_D(QMacToolBar);
254     if (!d->targetWindow) {
255         QTimer::singleShot(100, this, SLOT(showInWindow_impl()));
256         return;
257     }
258
259     NSWindow *macWindow = static_cast<NSWindow*>(
260         QGuiApplication::platformNativeInterface()->nativeResourceForWindow("nswindow", d->targetWindow));
261
262     if (!macWindow) {
263         QTimer::singleShot(100, this, SLOT(showInWindow_impl()));
264         return;
265     }
266
267     [macWindow setToolbar: d->toolbar];
268     [macWindow setShowsToolbarButton:YES];
269 }
270
271 /*!
272     Detatches the toolbar from the current window.
273 */
274 void QMacToolBar::detachFromWindow()
275 {
276     Q_D(QMacToolBar);
277     if (!d->targetWindow)
278         return;
279
280     NSWindow *macWindow = static_cast<NSWindow*>(
281         QGuiApplication::platformNativeInterface()->nativeResourceForWindow("nswindow", d->targetWindow));
282     [macWindow setToolbar:nil];
283 }
284
285 /*!
286     Returns the naitve NSTooolbar object.
287 */
288 NSToolbar *QMacToolBar::nativeToolbar() const
289 {
290     Q_D(const QMacToolBar);
291     return d->toolbar;
292 }
293
294 QMacToolBarPrivate::QMacToolBarPrivate(const QString &identifier)
295 {
296     QString ident = identifier.isEmpty() ? QUuid::createUuid().toString() : identifier;
297     toolbar = [[NSToolbar alloc] initWithIdentifier:ident.toNSString()];
298     [toolbar setAutosavesConfiguration:NO];
299     [toolbar setAllowsUserCustomization:YES];
300
301     QMacToolbarDelegate *delegate = [[QMacToolbarDelegate alloc] init];
302     delegate->toolbarPrivate = this;
303     [toolbar setDelegate:delegate];
304
305     targetWindow = 0;
306 }
307
308 QMacToolBarPrivate::~QMacToolBarPrivate()
309 {
310     [[toolbar delegate]release];
311     [toolbar release];
312 }
313
314 NSMutableArray *QMacToolBarPrivate::getItemIdentifiers(const QList<QMacToolBarItem *> &items, bool cullUnselectable)
315 {
316     NSMutableArray *array = [[NSMutableArray alloc] init];
317     foreach (const QMacToolBarItem * item, items) {
318         if (cullUnselectable && item->selectable() == false)
319             continue;
320         [array addObject : item->d_func()->itemIdentifier()];
321     }
322     return array;
323 }
324
325 void QMacToolBarPrivate::itemClicked(NSToolbarItem *item)
326 {
327     QString identifier = QtMac::fromNSString([item itemIdentifier]);
328     QMacToolBarItem *toolButton = reinterpret_cast<QMacToolBarItem *>(identifier.toULongLong());
329     Q_EMIT toolButton->activated();
330 }
331
332
333 QT_END_NAMESPACE