Cocoa: Load the standard app menu.
[profile/ivi/qtbase.git] / src / plugins / platforms / cocoa / qcocoamenuloader.mm
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the plugins of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qcocoamenuloader.h"
43
44 #include <QtCore/private/qcore_mac_p.h>
45 #include <QtCore/qcoreapplication.h>
46 #include <QtCore/qdir.h>
47 #include <QtCore/qstring.h>
48
49 QT_FORWARD_DECLARE_CLASS(QCFString)
50 QT_FORWARD_DECLARE_CLASS(QString)
51
52 #ifndef QT_NO_TRANSLATION
53     QT_BEGIN_NAMESPACE
54     extern QString qt_mac_applicationmenu_string(int type);
55     QT_END_NAMESPACE
56 #endif
57
58 QT_USE_NAMESPACE
59
60 /*
61     Loads and instantiates the main app menu from the menu nib file(s).
62
63     The main app menu contains the Quit, Hide  About, Preferences entries, and
64     The reason for having the nib file is that those can not be created
65     programmatically. To ease deployment the nib files are stored in Qt resources
66     and written to QDir::temp() before loading. (Earlier Qt versions used
67     to require having the nib file in the QtGui framework.)
68 */
69 void qt_mac_loadMenuNib(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader)
70 {
71     // Create qt_menu.nib dir in temp.
72     QDir temp = QDir::temp();
73     temp.mkdir("qt_menu.nib");
74     QString nibDir = temp.canonicalPath() + QLatin1String("/") + QLatin1String("qt_menu.nib/");
75     if (!QDir(nibDir).exists()) {
76         qWarning("qt_mac_loadMenuNib: could not create nib directory in temp");
77         return;
78     }
79
80     // Copy nib files from resources to temp.
81     QDir nibResource(":/trolltech/mac/qt_menu.nib/");
82     if (!nibResource.exists()) {
83         qWarning("qt_mac_loadMenuNib: could not load nib from resources");
84         return;
85     }
86     foreach (const QFileInfo &file, nibResource.entryInfoList()) {
87         QFile::copy(file.absoluteFilePath(), nibDir + QLatin1String("/") + file.fileName());
88     }
89
90     // Load and instantiate nib file from temp
91     NSURL *nibUrl = [NSURL fileURLWithPath : reinterpret_cast<const NSString *>(QCFString::toCFStringRef(nibDir))];
92     [nibUrl autorelease];
93     NSNib *nib = [[NSNib alloc] initWithContentsOfURL : nibUrl];
94     [nib autorelease];
95     if(!nib) {
96         qWarning("qt_mac_loadMenuNib: could not load nib from  temp");
97         return;
98     }
99     bool ok = [nib instantiateNibWithOwner : qtMenuLoader topLevelObjects : nil];
100     if (!ok) {
101         qWarning("qt_mac_loadMenuNib: could not instantiate nib");
102     }
103 }
104
105
106
107 @implementation QT_MANGLE_NAMESPACE(QCocoaMenuLoader)
108
109 - (void)awakeFromNib
110 {
111     servicesItem = [[appMenu itemWithTitle:@"Services"] retain];
112     hideAllOthersItem = [[appMenu itemWithTitle:@"Hide Others"] retain];
113     showAllItem = [[appMenu itemWithTitle:@"Show All"] retain];
114
115     // Get the names in the nib to match the app name set by Qt.
116     const NSString *appName = reinterpret_cast<const NSString*>(QCFString::toCFStringRef(qAppName()));
117     [quitItem setTitle:[[quitItem title] stringByReplacingOccurrencesOfString:@"NewApplication"
118                                                                    withString:const_cast<NSString *>(appName)]];
119     [hideItem setTitle:[[hideItem title] stringByReplacingOccurrencesOfString:@"NewApplication"
120                                                                    withString:const_cast<NSString *>(appName)]];
121     [aboutItem setTitle:[[aboutItem title] stringByReplacingOccurrencesOfString:@"NewApplication"
122                                                                    withString:const_cast<NSString *>(appName)]];
123     [appName release];
124     // Disable the items that don't do anything. If someone associates a QAction with them
125     // They should get synced back in.
126     [preferencesItem setEnabled:NO];
127     [preferencesItem setHidden:YES];
128     [aboutItem setEnabled:NO];
129     [aboutItem setHidden:YES];
130 }
131
132 - (void)ensureAppMenuInMenu:(NSMenu *)menu
133 {
134     // The application menu is the menu in the menu bar that contains the
135     // 'Quit' item. When changing menu bar (e.g when switching between
136     // windows with different menu bars), we never recreate this menu, but
137     // instead pull it out the current menu bar and place into the new one:
138     NSMenu *mainMenu = [NSApp mainMenu];
139     if ([NSApp mainMenu] == menu)
140         return; // nothing to do (menu is the current menu bar)!
141
142 #ifndef QT_NAMESPACE
143     Q_ASSERT(mainMenu);
144 #endif
145     // Grab the app menu out of the current menu.
146     int numItems = [mainMenu numberOfItems];
147     NSMenuItem *oldAppMenuItem = 0;
148     for (int i = 0; i < numItems; ++i) {
149         NSMenuItem *item = [mainMenu itemAtIndex:i];
150         if ([item submenu] == appMenu) {
151             oldAppMenuItem = item;
152             [oldAppMenuItem retain];
153             [mainMenu removeItemAtIndex:i];
154             break;
155         }
156     }
157
158     if (oldAppMenuItem) {
159         [oldAppMenuItem setSubmenu:nil];
160         [oldAppMenuItem release];
161         NSMenuItem *appMenuItem = [[NSMenuItem alloc] initWithTitle:@"Apple"
162             action:nil keyEquivalent:@""];
163         [appMenuItem setSubmenu:appMenu];
164         [menu insertItem:appMenuItem atIndex:0];
165     }
166 }
167
168 - (void)removeActionsFromAppMenu
169 {
170     for (NSMenuItem *item in [appMenu itemArray])
171         [item setTag:nil];
172 }
173
174 - (void)dealloc
175 {
176     [servicesItem release];
177     [hideAllOthersItem release];
178     [showAllItem release];
179
180     [lastAppSpecificItem release];
181     [theMenu release];
182     [appMenu release];
183     [super dealloc];
184 }
185
186 - (NSMenu *)menu
187 {
188     return [[theMenu retain] autorelease];
189 }
190
191 - (NSMenu *)applicationMenu
192 {
193     return [[appMenu retain] autorelease];
194 }
195
196 - (NSMenuItem *)quitMenuItem
197 {
198     return [[quitItem retain] autorelease];
199 }
200
201 - (NSMenuItem *)preferencesMenuItem
202 {
203     return [[preferencesItem retain] autorelease];
204 }
205
206 - (NSMenuItem *)aboutMenuItem
207 {
208     return [[aboutItem retain] autorelease];
209 }
210
211 - (NSMenuItem *)aboutQtMenuItem
212 {
213     return [[aboutQtItem retain] autorelease];
214 }
215
216 - (NSMenuItem *)hideMenuItem
217 {
218     return [[hideItem retain] autorelease];
219 }
220
221 - (NSMenuItem *)appSpecificMenuItem
222 {
223     // Create an App-Specific menu item, insert it into the menu and return
224     // it as an autorelease item.
225     NSMenuItem *item = [[NSMenuItem alloc] init];
226
227     NSInteger location;
228     if (lastAppSpecificItem == nil) {
229         location = [appMenu indexOfItem:aboutQtItem];
230     } else {
231         location = [appMenu indexOfItem:lastAppSpecificItem];
232         [lastAppSpecificItem release];
233     }
234     lastAppSpecificItem = item;  // Keep track of this for later (i.e., don't release it)
235     [appMenu insertItem:item atIndex:location + 1];
236
237     return [[item retain] autorelease];
238 }
239
240 - (BOOL) acceptsFirstResponder
241 {
242     return YES;
243 }
244
245 - (void)terminate:(id)sender
246 {
247     [NSApp terminate:sender];
248 }
249
250 - (void)orderFrontStandardAboutPanel:(id)sender
251 {
252     [NSApp orderFrontStandardAboutPanel:sender];
253 }
254
255 - (void)hideOtherApplications:(id)sender
256 {
257     [NSApp hideOtherApplications:sender];
258 }
259
260 - (void)unhideAllApplications:(id)sender
261 {
262     [NSApp unhideAllApplications:sender];
263 }
264
265 - (void)hide:(id)sender
266 {
267     [NSApp hide:sender];
268 }
269
270 - (void)qtUpdateMenubar
271 {
272     //    QMenuBarPrivate::macUpdateMenuBarImmediatly();
273 }
274
275 - (void)qtTranslateApplicationMenu
276 {
277 /*
278 #ifndef QT_NO_TRANSLATION
279     [servicesItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(0))];
280     [hideItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(1).arg(qAppName()))];
281     [hideAllOthersItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(2))];
282     [showAllItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(3))];
283     [preferencesItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(4))];
284     [quitItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(5).arg(qAppName()))];
285     [aboutItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(6).arg(qAppName()))];
286 #endif
287 */
288 }
289
290 - (IBAction)qtDispatcherToQAction:(id)sender
291 {
292     /*
293     QScopedLoopLevelCounter loopLevelCounter(QApplicationPrivate::instance()->threadData);
294     NSMenuItem *item = static_cast<NSMenuItem *>(sender);
295     if (QAction *action = reinterpret_cast<QAction *>([item tag])) {
296         action->trigger();
297     } else if (item == quitItem) {
298         // We got here because someone was once the quitItem, but it has been
299         // abandoned (e.g., the menubar was deleted). In the meantime, just do
300         // normal QApplication::quit().
301         qApp->quit();
302     }
303 */
304 }
305
306  - (void)orderFrontCharacterPalette:(id)sender
307  {
308      [NSApp orderFrontCharacterPalette:sender];
309  }
310 @end