update dev300-m58
[ooovba.git] / sfx2 / source / appl / shutdowniconaqua.mm
blobe9326b4a22c2cd107906e980ce893eb478612eeb
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  * 
5  * Copyright 2008 by Sun Microsystems, Inc.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * $RCSfile: shutdowniconaqua.mm,v $
10  * $Revision: 1.5 $
11  *
12  * This file is part of OpenOffice.org.
13  *
14  * OpenOffice.org is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU Lesser General Public License version 3
16  * only, as published by the Free Software Foundation.
17  *
18  * OpenOffice.org is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU Lesser General Public License version 3 for more details
22  * (a copy is included in the LICENSE file that accompanied this code).
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * version 3 along with OpenOffice.org.  If not, see
26  * <http://www.openoffice.org/license.html>
27  * for a copy of the LGPLv3 License.
28  *
29  ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sfx2.hxx"
34 #include "svtools/moduleoptions.hxx"
35 #include "svtools/dynamicmenuoptions.hxx"
36 #include "svtools/historyoptions.hxx"
37 #include "tools/urlobj.hxx"
38 #include "osl/file.h"
39 #include "comphelper/sequenceashashmap.hxx"
40 #include "vos/mutex.hxx"
41 #include "sfx2/app.hxx"
42 #include "app.hrc"
43 #define USE_APP_SHORTCUTS
44 #include "shutdownicon.hxx"
46 #include "com/sun/star/util/XStringWidth.hpp"
48 #include "cppuhelper/implbase1.hxx"
50 #include <set>
51 #include <vector>
53 #include "premac.h"
54 #include <Cocoa/Cocoa.h>
55 #include "postmac.h"
57 using namespace ::rtl;
58 using namespace ::osl;
59 using namespace ::com::sun::star::uno;
60 using namespace ::com::sun::star::task;
61 using namespace ::com::sun::star::lang;
62 using namespace ::com::sun::star::beans;
63 using namespace ::com::sun::star::util;
65 #define MI_OPEN                    1
66 #define MI_WRITER                  2
67 #define MI_CALC                    3
68 #define MI_IMPRESS                 4
69 #define MI_DRAW                    5
70 #define MI_BASE                    6
71 #define MI_MATH                    7
72 #define MI_TEMPLATE                8
73 #define MI_STARTMODULE             9
75 @interface QSMenuExecute : NSObject
78 -(void)executeMenuItem: (NSMenuItem*)pItem;
79 -(void)dockIconClicked: (NSObject*)pSender;
80 @end
82 @implementation QSMenuExecute
83 -(void)executeMenuItem: (NSMenuItem*)pItem
85     switch( [pItem tag] )
86     {
87     case MI_OPEN:
88         ShutdownIcon::FileOpen();
89         break;
90     case MI_WRITER:
91         ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( WRITER_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
92         break;
93     case MI_CALC:
94         ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( CALC_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
95         break;
96     case MI_IMPRESS:
97         ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( IMPRESS_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
98         break;
99     case MI_DRAW:
100         ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( DRAW_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
101         break;
102     case MI_BASE:
103         ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( BASE_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
104         break;
105     case MI_MATH:
106         ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( MATH_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
107         break;
108     case MI_TEMPLATE:
109         ShutdownIcon::FromTemplate();
110         break;
111     case MI_STARTMODULE:
112         ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( STARTMODULE_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
113         break;
114     default:
115         break;
116     }
119 -(void)dockIconClicked: (NSObject*)pSender
121     // start start module
122     ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( STARTMODULE_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
125 @end
127 bool ShutdownIcon::IsQuickstarterInstalled()
129     return true;
132 static NSMenuItem* pDefMenu = nil, *pDockSubMenu = nil;
133 static QSMenuExecute* pExecute = nil;
135 static std::set< OUString > aShortcuts;
137 static NSString* getAutoreleasedString( const rtl::OUString& rStr )
139     return [[[NSString alloc] initWithCharacters: rStr.getStr() length: rStr.getLength()] autorelease];
142 struct RecentMenuEntry
144     rtl::OUString aURL;
145     rtl::OUString aFilter;
146     rtl::OUString aTitle;
147     rtl::OUString aPassword;
150 class RecentFilesStringLength : public ::cppu::WeakImplHelper1< ::com::sun::star::util::XStringWidth >
152         public:
153                 RecentFilesStringLength() {}
154                 virtual ~RecentFilesStringLength() {}
156                 // XStringWidth
157                 sal_Int32 SAL_CALL queryStringWidth( const ::rtl::OUString& aString )
158                         throw (::com::sun::star::uno::RuntimeException)
159                 {
160                         return aString.getLength();
161                 }
164 @interface RecentMenuDelegate : NSObject
166     std::vector< RecentMenuEntry >* m_pRecentFilesItems;
168 -(id)init;
169 -(void)dealloc;
170 -(void)menuNeedsUpdate:(NSMenu *)menu;
171 -(void)executeRecentEntry: (NSMenuItem*)item;
172 @end
174 @implementation RecentMenuDelegate
175 -(id)init
177     if( (self = [super init]) )
178     {
179         m_pRecentFilesItems = new std::vector< RecentMenuEntry >();
180     }
181     return self;
184 -(void)dealloc
186     delete m_pRecentFilesItems;
187     [super dealloc];
190 -(void)menuNeedsUpdate:(NSMenu *)menu
192     // clear menu
193     int nItems = [menu numberOfItems];
194     while( nItems -- )
195         [menu removeItemAtIndex: 0];
196     
197     // update recent item list
198     Sequence< Sequence< PropertyValue > > aHistoryList( SvtHistoryOptions().GetList( ePICKLIST ) );
200     int nPickListMenuItems = ( aHistoryList.getLength() > 99 ) ? 99 : aHistoryList.getLength();
201         
202     m_pRecentFilesItems->clear();
203     if( ( nPickListMenuItems > 0 ) )
204     {
205         for ( int i = 0; i < nPickListMenuItems; i++ )
206         {
207             Sequence< PropertyValue >& rPickListEntry = aHistoryList[i];
208             RecentMenuEntry aRecentFile;
209             
210             for ( int j = 0; j < rPickListEntry.getLength(); j++ )
211             {
212                 Any a = rPickListEntry[j].Value;
213                 
214                 if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_URL )
215                     a >>= aRecentFile.aURL;
216                 else if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_FILTER )
217                     a >>= aRecentFile.aFilter;
218                 else if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_TITLE )
219                     a >>= aRecentFile.aTitle;
220                 else if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_PASSWORD )
221                     a >>= aRecentFile.aPassword;
222             }
223             
224             m_pRecentFilesItems->push_back( aRecentFile );
225         }
226     }
228     // insert new recent items
229     for ( sal_uInt32 i = 0; i < m_pRecentFilesItems->size(); i++ )
230     {
231         rtl::OUString   aMenuTitle;
232         INetURLObject   aURL( (*m_pRecentFilesItems)[i].aURL );
233         
234         if ( aURL.GetProtocol() == INET_PROT_FILE )
235         {
236             // Do handle file URL differently => convert it to a system
237             // path and abbreviate it with a special function:
238             String aFileSystemPath( aURL.getFSysPath( INetURLObject::FSYS_DETECT ) );
239             
240             ::rtl::OUString     aSystemPath( aFileSystemPath );
241             ::rtl::OUString     aCompactedSystemPath;
242             
243             oslFileError nError = osl_abbreviateSystemPath( aSystemPath.pData, &aCompactedSystemPath.pData, 46, NULL );
244             if ( !nError )
245                 aMenuTitle = String( aCompactedSystemPath );
246             else
247                 aMenuTitle = aSystemPath;
248         }
249         else
250         {
251             // Use INetURLObject to abbreviate all other URLs
252             Reference< XStringWidth > xStringLength( new RecentFilesStringLength() );
253             aMenuTitle = aURL.getAbbreviated( xStringLength, 46, INetURLObject::DECODE_UNAMBIGUOUS );
254         }
255         
256         NSMenuItem* pNewItem = [[NSMenuItem alloc] initWithTitle: getAutoreleasedString( aMenuTitle )
257                                                    action: @selector(executeRecentEntry:)
258                                                    keyEquivalent: @""];
259         [pNewItem setTag: i];
260         [pNewItem setTarget: self];
261         [pNewItem setEnabled: YES];
262         [menu addItem: pNewItem];
263         [pNewItem autorelease];
264     }
267 -(void)executeRecentEntry: (NSMenuItem*)item
269     sal_Int32 nIndex = [item tag];
270     if( ( nIndex >= 0 ) && ( nIndex < static_cast<sal_Int32>( m_pRecentFilesItems->size() ) ) )
271     {
272         const RecentMenuEntry& rRecentFile = (*m_pRecentFilesItems)[ nIndex ];
273         int NUM_OF_PICKLIST_ARGS = 3;
274         Sequence< PropertyValue > aArgsList( NUM_OF_PICKLIST_ARGS );
275         
276         aArgsList[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Referer" ));
277         aArgsList[0].Value = makeAny( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:user" ) ) );
279         // documents in the picklist will never be opened as templates
280         aArgsList[1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AsTemplate" ));
281         aArgsList[1].Value = makeAny( (sal_Bool) sal_False );
283         ::rtl::OUString  aFilter( rRecentFile.aFilter );
284         sal_Int32 nPos = aFilter.indexOf( '|' );
285         if ( nPos >= 0 )
286         {
287                 rtl::OUString aFilterOptions;
289                 if ( nPos < ( aFilter.getLength() - 1 ) )
290                         aFilterOptions = aFilter.copy( nPos+1 );
292                 aArgsList[2].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterOptions" ));
293                 aArgsList[2].Value = makeAny( aFilterOptions );
295                 aFilter = aFilter.copy( 0, nPos-1 );
296                 aArgsList.realloc( ++NUM_OF_PICKLIST_ARGS );
297         }
299         aArgsList[NUM_OF_PICKLIST_ARGS-1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ));
300         aArgsList[NUM_OF_PICKLIST_ARGS-1].Value = makeAny( aFilter );
302         ShutdownIcon::OpenURL( rRecentFile.aURL, OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ), aArgsList );
303     }
305 @end
307 static RecentMenuDelegate* pRecentDelegate = nil;
309 static rtl::OUString getShortCut( const rtl::OUString i_rTitle )
311     // create shortcut
312     rtl::OUString aKeyEquiv;
313     for( sal_Int32 nIndex = 0; nIndex < i_rTitle.getLength(); nIndex++ )
314     {
315         rtl::OUString aShortcut( i_rTitle.copy( nIndex, 1 ).toAsciiLowerCase() );
316         if( aShortcuts.find( aShortcut ) == aShortcuts.end() )
317         {
318             aShortcuts.insert( aShortcut );
319             aKeyEquiv = aShortcut;
320             break;
321         }
322     }
324     return aKeyEquiv;   
327 static void appendMenuItem( NSMenu* i_pMenu, NSMenu* i_pDockMenu, const rtl::OUString& i_rTitle, int i_nTag, const rtl::OUString& i_rKeyEquiv )
329     if( ! i_rTitle.getLength() )
330         return;
331     
332     NSMenuItem* pItem = [[NSMenuItem alloc] initWithTitle: getAutoreleasedString( i_rTitle )
333                                             action: @selector(executeMenuItem:)
334                                             keyEquivalent: (i_rKeyEquiv.getLength() ? getAutoreleasedString( i_rKeyEquiv ) : @"")
335                         ];
336     [pItem setTag: i_nTag];
337     [pItem setTarget: pExecute];
338     [pItem setEnabled: YES];
339     [i_pMenu addItem: pItem];
341     if( i_pDockMenu )
342     {
343         // create a similar entry in the dock menu
344         pItem = [[NSMenuItem alloc] initWithTitle: getAutoreleasedString( i_rTitle )
345                                     action: @selector(executeMenuItem:)
346                                     keyEquivalent: @""
347                             ];
348         [pItem setTag: i_nTag];
349         [pItem setTarget: pExecute];
350         [pItem setEnabled: YES];
351         [i_pDockMenu addItem: pItem];
352     }
355 static void appendRecentMenu( NSMenu* i_pMenu, NSMenu* i_pDockMenu, const String& i_rTitle )
357     if( ! pRecentDelegate )
358         pRecentDelegate = [[RecentMenuDelegate alloc] init];
359     
360     NSMenuItem* pItem = [i_pMenu addItemWithTitle: getAutoreleasedString( i_rTitle )
361                                                    action: @selector(executeMenuItem:)
362                                                    keyEquivalent: @""
363                         ];
364     [pItem setEnabled: YES];
365     NSMenu* pRecentMenu = [[NSMenu alloc] initWithTitle: getAutoreleasedString( i_rTitle ) ];
366     [pRecentMenu setDelegate: pRecentDelegate];
367     [pRecentMenu setAutoenablesItems: NO];
368     [pItem setSubmenu: pRecentMenu];
370     if( i_pDockMenu )
371     {
372         // create a similar entry in the dock menu
373         pItem = [i_pDockMenu addItemWithTitle: getAutoreleasedString( i_rTitle )
374                              action: @selector(executeMenuItem:)
375                              keyEquivalent: @""
376                         ];
377         [pItem setEnabled: YES];
378         pRecentMenu = [[NSMenu alloc] initWithTitle: getAutoreleasedString( i_rTitle ) ];
379         [pRecentMenu setDelegate: pRecentDelegate];
380         [pRecentMenu setAutoenablesItems: NO];
381         [pItem setSubmenu: pRecentMenu];
382     }
386 extern "C"
389 void aqua_init_systray()
391         ::vos::OGuard aGuard( Application::GetSolarMutex() );
393     ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
394     if( ! pShutdownIcon )
395         return;
397         // disable shutdown
398         pShutdownIcon->SetVeto( true );
399         pShutdownIcon->addTerminateListener();
400     
401     if( ! pDefMenu )
402     {
403         if( [NSApp respondsToSelector: @selector(addFallbackMenuItem:)] )
404         {
405             aShortcuts.clear();
406             
407             pExecute = [[QSMenuExecute alloc] init];
408             pDefMenu = [[NSMenuItem alloc] initWithTitle: getAutoreleasedString( pShutdownIcon->GetResString( STR_QUICKSTART_FILE ) ) action: NULL keyEquivalent: @""];
409             pDockSubMenu = [[NSMenuItem alloc] initWithTitle: getAutoreleasedString( pShutdownIcon->GetResString( STR_QUICKSTART_FILE ) ) action: NULL keyEquivalent: @""];
410             NSMenu* pMenu = [[NSMenu alloc] initWithTitle: getAutoreleasedString( pShutdownIcon->GetResString( STR_QUICKSTART_FILE ) )];
411             [pMenu setAutoenablesItems: NO];
412             NSMenu* pDockMenu = [[NSMenu alloc] initWithTitle: getAutoreleasedString( pShutdownIcon->GetResString( STR_QUICKSTART_FILE ) )];
413             [pDockMenu setAutoenablesItems: NO];
414             
415             // collect the URLs of the entries in the File/New menu
416             SvtModuleOptions    aModuleOptions;
417             std::set< rtl::OUString > aFileNewAppsAvailable;
418             SvtDynamicMenuOptions aOpt;
419             Sequence < Sequence < PropertyValue > > aNewMenu = aOpt.GetMenu( E_NEWMENU );
420             const rtl::OUString sURLKey( RTL_CONSTASCII_USTRINGPARAM( "URL" ) );
421         
422             const Sequence< PropertyValue >* pNewMenu = aNewMenu.getConstArray();
423             const Sequence< PropertyValue >* pNewMenuEnd = aNewMenu.getConstArray() + aNewMenu.getLength();
424             for ( ; pNewMenu != pNewMenuEnd; ++pNewMenu )
425             {
426                 comphelper::SequenceAsHashMap aEntryItems( *pNewMenu );
427                 rtl::OUString sURL( aEntryItems.getUnpackedValueOrDefault( sURLKey, rtl::OUString() ) );
428                 if ( sURL.getLength() )
429                     aFileNewAppsAvailable.insert( sURL );
430             }
431             
432             // describe the menu entries for launching the applications
433             struct MenuEntryDescriptor
434             {
435                 SvtModuleOptions::EModule   eModuleIdentifier;
436                 int                         nMenuTag;
437                 const char*                 pAsciiURLDescription;
438             }   aMenuItems[] =
439             {
440                 { SvtModuleOptions::E_SWRITER,    MI_WRITER,  WRITER_URL },
441                 { SvtModuleOptions::E_SCALC,      MI_CALC,    CALC_URL },
442                 { SvtModuleOptions::E_SIMPRESS,   MI_IMPRESS, IMPRESS_WIZARD_URL },
443                 { SvtModuleOptions::E_SDRAW,      MI_DRAW,    DRAW_URL },
444                 { SvtModuleOptions::E_SDATABASE,  MI_BASE,    BASE_URL },
445                 { SvtModuleOptions::E_SMATH,      MI_MATH,    MATH_URL }
446             };
448             // insert entry for startcenter
449             if( aModuleOptions.IsModuleInstalled( SvtModuleOptions::E_SSTARTMODULE ) )
450             {
451                 appendMenuItem( pMenu, nil, pShutdownIcon->GetResString( STR_QUICKSTART_STARTCENTER ), MI_STARTMODULE, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "n" ) ) );
452                 if( [NSApp respondsToSelector: @selector(setDockIconClickHandler:)] )
453                     [NSApp performSelector:@selector(setDockIconClickHandler:) withObject: pExecute];
454                 else
455                     DBG_ERROR( "setDockIconClickHandler selector failed on NSApp\n" );
457             }
458             
459             // insert the menu entries for launching the applications
460             for ( size_t i = 0; i < sizeof( aMenuItems ) / sizeof( aMenuItems[0] ); ++i )
461             {
462                 if ( !aModuleOptions.IsModuleInstalled( aMenuItems[i].eModuleIdentifier ) )
463                     // the complete application is not even installed
464                     continue;
465         
466                 rtl::OUString sURL( ::rtl::OUString::createFromAscii( aMenuItems[i].pAsciiURLDescription ) );
467         
468                 if ( aFileNewAppsAvailable.find( sURL ) == aFileNewAppsAvailable.end() )
469                     // the application is installed, but the entry has been configured to *not* appear in the File/New
470                     // menu => also let not appear it in the quickstarter
471                     continue;
472                 
473                 rtl::OUString aKeyEquiv( getShortCut( pShutdownIcon->GetUrlDescription( sURL ) ) );
474         
475                 appendMenuItem( pMenu, pDockMenu, pShutdownIcon->GetUrlDescription( sURL ), aMenuItems[i].nMenuTag, aKeyEquiv );
476             }
478             // insert the remaining menu entries
480             // add recent menu
481             appendRecentMenu( pMenu, pDockMenu, pShutdownIcon->GetResString( STR_QUICKSTART_RECENTDOC ) );
483             rtl::OUString aTitle( pShutdownIcon->GetResString( STR_QUICKSTART_FROMTEMPLATE ) );
484             rtl::OUString aKeyEquiv( getShortCut( aTitle ) );
485             appendMenuItem( pMenu, pDockMenu, aTitle, MI_TEMPLATE, aKeyEquiv );
486             aTitle = pShutdownIcon->GetResString( STR_QUICKSTART_FILEOPEN );
487             aKeyEquiv = getShortCut( aTitle );
488             appendMenuItem( pMenu, pDockMenu, aTitle, MI_OPEN, aKeyEquiv );
489             
490             [pDefMenu setSubmenu: pMenu];
491             [NSApp performSelector:@selector(addFallbackMenuItem:) withObject: pDefMenu];
493             if( [NSApp respondsToSelector: @selector(addDockMenuItem:)] )
494             {
495                 [pDockSubMenu setSubmenu: pDockMenu];
496                 // insert a separator to the dock menu
497                 [NSApp performSelector:@selector(addDockMenuItem:) withObject: [NSMenuItem separatorItem]];
498                 // and now add the submenu
499                 [NSApp performSelector:@selector(addDockMenuItem:) withObject: pDockSubMenu];
500             }
501             else
502                 DBG_ERROR( "addDockMenuItem selector failed on NSApp\n" );
503         }
504         else
505             DBG_ERROR( "addFallbackMenuItem selector failed on NSApp\n" );
506     }
509 void SAL_DLLPUBLIC_EXPORT aqua_shutdown_systray()