merged tag ooo/OOO330_m14
[LibreOffice.git] / framework / source / classes / addonmenu.cxx
blob4961a8f7c1f28e85d2fe9747b0475a428e523e89
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_framework.hxx"
31 //_________________________________________________________________________________________________________________
32 // my own includes
33 //_________________________________________________________________________________________________________________
34 #include "classes/addonmenu.hxx"
35 #include "classes/addonsoptions.hxx"
36 #include <general.h>
37 #include <macros/debug/assertion.hxx>
38 #include <helper/imageproducer.hxx>
39 #include <xml/menuconfiguration.hxx>
41 //_________________________________________________________________________________________________________________
42 // interface includes
43 //_________________________________________________________________________________________________________________
44 #include <com/sun/star/uno/Reference.hxx>
45 #include <com/sun/star/util/URL.hpp>
46 #include <com/sun/star/util/XURLTransformer.hpp>
47 #include <com/sun/star/lang/XServiceInfo.hpp>
49 //_________________________________________________________________________________________________________________
50 // includes of other projects
51 //_________________________________________________________________________________________________________________
52 #include <tools/config.hxx>
53 #include <vcl/svapp.hxx>
54 #include <svtools/menuoptions.hxx>
55 #include <svl/solar.hrc>
56 //_________________________________________________________________________________________________________________
57 // namespace
58 //_________________________________________________________________________________________________________________
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star::lang;
62 using namespace ::com::sun::star::frame;
63 using namespace ::com::sun::star::beans;
65 // Please look at sfx2/inc/sfxsids.hrc the values are defined there. Due to build dependencies
66 // we cannot include the header file.
67 const USHORT SID_HELPMENU = (SID_SFX_START + 410);
68 const USHORT SID_ONLINE_REGISTRATION = (SID_SFX_START + 1537);
70 namespace framework
73 AddonMenu::AddonMenu( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& rFrame ) :
74 m_xFrame( rFrame )
78 AddonMenu::~AddonMenu()
80 for ( USHORT i = 0; i < GetItemCount(); i++ )
82 if ( GetItemType( i ) != MENUITEM_SEPARATOR )
84 // delete user attributes created with new!
85 USHORT nId = GetItemId( i );
86 MenuConfiguration::Attributes* pUserAttributes = (MenuConfiguration::Attributes*)GetUserValue( nId );
87 delete pUserAttributes;
88 delete GetPopupMenu( nId );
93 // ------------------------------------------------------------------------
95 // ------------------------------------------------------------------------
96 // Check if command URL string has the unique prefix to identify addon popup menus
97 sal_Bool AddonPopupMenu::IsCommandURLPrefix( const ::rtl::OUString& aCmdURL )
99 const char aPrefixCharBuf[] = ADDONSPOPUPMENU_URL_PREFIX_STR;
101 return aCmdURL.matchAsciiL( aPrefixCharBuf, sizeof( aPrefixCharBuf )-1, 0 );
104 AddonPopupMenu::AddonPopupMenu( const com::sun::star::uno::Reference< com::sun::star::frame::XFrame >& rFrame ) :
105 AddonMenu( rFrame )
109 AddonPopupMenu::~AddonPopupMenu()
113 // ------------------------------------------------------------------------
115 static Reference< XModel > GetModelFromFrame( const Reference< XFrame >& rFrame )
117 // Query for the model to get check the context information
118 Reference< XModel > xModel;
119 if ( rFrame.is() )
121 Reference< XController > xController( rFrame->getController(), UNO_QUERY );
122 if ( xController.is() )
123 xModel = xController->getModel();
126 return xModel;
129 // ------------------------------------------------------------------------
131 sal_Bool AddonMenuManager::HasAddonMenuElements()
133 return AddonsOptions().HasAddonsMenu();
136 sal_Bool AddonMenuManager::HasAddonHelpMenuElements()
138 return AddonsOptions().HasAddonsHelpMenu();
141 // Factory method to create different Add-On menu types
142 PopupMenu* AddonMenuManager::CreatePopupMenuType( MenuType eMenuType, const Reference< XFrame >& rFrame )
144 if ( eMenuType == ADDON_MENU )
145 return new AddonMenu( rFrame );
146 else if ( eMenuType == ADDON_POPUPMENU )
147 return new AddonPopupMenu( rFrame );
148 else
149 return NULL;
152 // Create the Add-Ons menu
153 AddonMenu* AddonMenuManager::CreateAddonMenu( const Reference< XFrame >& rFrame )
155 AddonsOptions aOptions;
156 AddonMenu* pAddonMenu = NULL;
157 USHORT nUniqueMenuId = ADDONMENU_ITEMID_START;
159 const Sequence< Sequence< PropertyValue > >& rAddonMenuEntries = aOptions.GetAddonsMenu();
160 if ( rAddonMenuEntries.getLength() > 0 )
162 pAddonMenu = (AddonMenu *)AddonMenuManager::CreatePopupMenuType( ADDON_MENU, rFrame );
163 Reference< XModel > xModel = GetModelFromFrame( rFrame );
164 AddonMenuManager::BuildMenu( pAddonMenu, ADDON_MENU, MENU_APPEND, nUniqueMenuId, rAddonMenuEntries, rFrame, xModel );
166 // Don't return an empty Add-On menu
167 if ( pAddonMenu->GetItemCount() == 0 )
169 delete pAddonMenu;
170 pAddonMenu = NULL;
174 return pAddonMenu;
177 // Returns the next insert position from nPos.
178 USHORT AddonMenuManager::GetNextPos( USHORT nPos )
180 return ( nPos == MENU_APPEND ) ? MENU_APPEND : ( nPos+1 );
184 static USHORT FindMenuId( Menu* pMenu, const String aCommand )
186 USHORT nPos = 0;
187 String aCmd;
188 for ( nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
190 USHORT nId = pMenu->GetItemId( nPos );
191 aCmd = pMenu->GetItemCommand( nId );
192 if ( aCmd == aCommand )
193 return nId;
196 return USHRT_MAX;
200 // Merge the Add-Ons help menu items into the given menu bar at a defined pos
201 void AddonMenuManager::MergeAddonHelpMenu( const Reference< XFrame >& rFrame, MenuBar* pMergeMenuBar )
203 if ( pMergeMenuBar )
205 PopupMenu* pHelpMenu = pMergeMenuBar->GetPopupMenu( SID_HELPMENU );
206 if ( !pHelpMenu )
208 USHORT nId = FindMenuId( pMergeMenuBar, String::CreateFromAscii( ".uno:HelpMenu" ));
209 if ( nId != USHRT_MAX )
210 pHelpMenu = pMergeMenuBar->GetPopupMenu( nId );
213 if ( pHelpMenu )
215 static const char REFERENCECOMMAND_AFTER[] = ".uno:OnlineRegistrationDlg";
216 static const char REFERENCECOMMAND_BEFORE[] = ".uno:About";
218 // Add-Ons help menu items should be inserted after the "registration" menu item
219 bool bAddAfter = true;
220 USHORT nItemCount = pHelpMenu->GetItemCount();
221 USHORT nRegPos = pHelpMenu->GetItemPos( SID_ONLINE_REGISTRATION );
222 USHORT nInsPos = nRegPos;
223 USHORT nInsSepAfterPos = MENU_APPEND;
224 USHORT nUniqueMenuId = ADDONMENU_ITEMID_START;
225 AddonsOptions aOptions;
227 if ( nRegPos == USHRT_MAX )
229 // try to detect the online registration dialog menu item with the command URL
230 USHORT nId = FindMenuId( pHelpMenu, String::CreateFromAscii( REFERENCECOMMAND_AFTER ));
231 nRegPos = pHelpMenu->GetItemPos( nId );
232 nInsPos = nRegPos;
235 if ( nRegPos == USHRT_MAX )
237 // second try:
238 // try to detect the about menu item with the command URL
239 USHORT nId = FindMenuId( pHelpMenu, String::CreateFromAscii( REFERENCECOMMAND_BEFORE ));
240 nRegPos = pHelpMenu->GetItemPos( nId );
241 nInsPos = nRegPos;
242 bAddAfter = false;
245 Sequence< Sequence< PropertyValue > > aAddonSubMenu;
246 const Sequence< Sequence< PropertyValue > >& rAddonHelpMenuEntries = aOptions.GetAddonsHelpMenu();
248 nInsPos = bAddAfter ? AddonMenuManager::GetNextPos( nInsPos ) : nInsPos;
249 if ( nInsPos < nItemCount && pHelpMenu->GetItemType( nInsPos ) != MENUITEM_SEPARATOR )
250 nInsSepAfterPos = nInsPos;
252 Reference< XModel > xModel = GetModelFromFrame( rFrame );
253 AddonMenuManager::BuildMenu( pHelpMenu, ADDON_MENU, nInsPos, nUniqueMenuId, rAddonHelpMenuEntries, rFrame, xModel );
255 if ( pHelpMenu->GetItemCount() > nItemCount )
257 if ( nInsSepAfterPos < MENU_APPEND )
259 nInsSepAfterPos += ( pHelpMenu->GetItemCount() - nItemCount );
260 if ( pHelpMenu->GetItemType( nInsSepAfterPos ) != MENUITEM_SEPARATOR )
261 pHelpMenu->InsertSeparator( nInsSepAfterPos );
263 if ( nRegPos < MENU_APPEND )
264 pHelpMenu->InsertSeparator( nRegPos+1 );
265 else
266 pHelpMenu->InsertSeparator( nItemCount );
272 // Merge the addon popup menus into the given menu bar at the provided pos.
273 void AddonMenuManager::MergeAddonPopupMenus( const Reference< XFrame >& rFrame,
274 const Reference< XModel >& rModel,
275 USHORT nMergeAtPos,
276 MenuBar* pMergeMenuBar )
278 if ( pMergeMenuBar )
280 AddonsOptions aAddonsOptions;
281 USHORT nInsertPos = nMergeAtPos;
283 ::rtl::OUString aTitle;
284 ::rtl::OUString aURL;
285 ::rtl::OUString aTarget;
286 ::rtl::OUString aImageId;
287 ::rtl::OUString aContext;
288 Sequence< Sequence< PropertyValue > > aAddonSubMenu;
289 USHORT nUniqueMenuId = ADDONMENU_ITEMID_START;
291 const Sequence< Sequence< PropertyValue > >& rAddonMenuEntries = aAddonsOptions.GetAddonsMenuBarPart();
292 for ( sal_Int32 i = 0; i < rAddonMenuEntries.getLength(); i++ )
294 AddonMenuManager::GetMenuEntry( rAddonMenuEntries[i],
295 aTitle,
296 aURL,
297 aTarget,
298 aImageId,
299 aContext,
300 aAddonSubMenu );
301 if ( aTitle.getLength() > 0 &&
302 aURL.getLength() > 0 &&
303 aAddonSubMenu.getLength() > 0 &&
304 AddonMenuManager::IsCorrectContext( rModel, aContext ))
306 USHORT nId = nUniqueMenuId++;
307 AddonPopupMenu* pAddonPopupMenu = (AddonPopupMenu *)AddonMenuManager::CreatePopupMenuType( ADDON_POPUPMENU, rFrame );
309 AddonMenuManager::BuildMenu( pAddonPopupMenu, ADDON_MENU, MENU_APPEND, nUniqueMenuId, aAddonSubMenu, rFrame, rModel );
311 if ( pAddonPopupMenu->GetItemCount() > 0 )
313 pAddonPopupMenu->SetCommandURL( aURL );
314 pMergeMenuBar->InsertItem( nId, aTitle, 0, nInsertPos++ );
315 pMergeMenuBar->SetPopupMenu( nId, pAddonPopupMenu );
317 // Store the command URL into the VCL menu bar for later identification
318 pMergeMenuBar->SetItemCommand( nId, aURL );
320 else
321 delete pAddonPopupMenu;
327 // Insert the menu and sub menu entries into pCurrentMenu with the aAddonMenuDefinition provided
328 void AddonMenuManager::BuildMenu( PopupMenu* pCurrentMenu,
329 MenuType nSubMenuType,
330 USHORT nInsPos,
331 USHORT& nUniqueMenuId,
332 Sequence< Sequence< PropertyValue > > aAddonMenuDefinition,
333 const Reference< XFrame >& rFrame,
334 const Reference< XModel >& rModel )
336 Sequence< Sequence< PropertyValue > > aAddonSubMenu;
337 BOOL bInsertSeparator = FALSE;
338 UINT32 i = 0;
339 UINT32 nElements = 0;
340 UINT32 nCount = aAddonMenuDefinition.getLength();
341 AddonsOptions aAddonsOptions;
343 ::rtl::OUString aTitle;
344 ::rtl::OUString aURL;
345 ::rtl::OUString aTarget;
346 ::rtl::OUString aImageId;
347 ::rtl::OUString aContext;
349 for ( i = 0; i < nCount; ++i )
351 GetMenuEntry( aAddonMenuDefinition[i], aTitle, aURL, aTarget, aImageId, aContext, aAddonSubMenu );
353 if ( !IsCorrectContext( rModel, aContext ) || ( !aTitle.getLength() && !aURL.getLength() ))
354 continue;
356 if ( aURL == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:separator" )))
357 bInsertSeparator = TRUE;
358 else
360 PopupMenu* pSubMenu = NULL;
361 if ( aAddonSubMenu.getLength() > 0 )
363 pSubMenu = AddonMenuManager::CreatePopupMenuType( nSubMenuType, rFrame );
364 AddonMenuManager::BuildMenu( pSubMenu, nSubMenuType, MENU_APPEND, nUniqueMenuId, aAddonSubMenu, rFrame, rModel );
366 // Don't create a menu item for an empty sub menu
367 if ( pSubMenu->GetItemCount() == 0 )
369 delete pSubMenu;
370 pSubMenu = NULL;
371 continue;
375 if ( bInsertSeparator && nElements > 0 )
377 // Insert a separator only when we insert a new element afterwards and we
378 // have already one before us
379 nElements = 0;
380 bInsertSeparator = FALSE;
381 pCurrentMenu->InsertSeparator( nInsPos );
382 nInsPos = AddonMenuManager::GetNextPos( nInsPos );
385 USHORT nId = nUniqueMenuId++;
386 pCurrentMenu->InsertItem( nId, aTitle, 0, nInsPos );
387 nInsPos = AddonMenuManager::GetNextPos( nInsPos );
389 ++nElements;
391 // Store values from configuration to the New and Wizard menu entries to enable
392 // sfx2 based code to support high contrast mode correctly!
393 pCurrentMenu->SetUserValue( nId, ULONG( new MenuConfiguration::Attributes( aTarget, aImageId )) );
394 pCurrentMenu->SetItemCommand( nId, aURL );
396 if ( pSubMenu )
397 pCurrentMenu->SetPopupMenu( nId, pSubMenu );
402 // Retrieve the menu entry property values from a sequence
403 void AddonMenuManager::GetMenuEntry( const Sequence< PropertyValue >& rAddonMenuEntry,
404 ::rtl::OUString& rTitle,
405 ::rtl::OUString& rURL,
406 ::rtl::OUString& rTarget,
407 ::rtl::OUString& rImageId,
408 ::rtl::OUString& rContext,
409 Sequence< Sequence< PropertyValue > >& rAddonSubMenu )
411 // Reset submenu parameter
412 rAddonSubMenu = Sequence< Sequence< PropertyValue > >();
414 for ( int i = 0; i < rAddonMenuEntry.getLength(); i++ )
416 ::rtl::OUString aMenuEntryPropName = rAddonMenuEntry[i].Name;
417 if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_URL )
418 rAddonMenuEntry[i].Value >>= rURL;
419 else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_TITLE )
420 rAddonMenuEntry[i].Value >>= rTitle;
421 else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_TARGET )
422 rAddonMenuEntry[i].Value >>= rTarget;
423 else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_IMAGEIDENTIFIER )
424 rAddonMenuEntry[i].Value >>= rImageId;
425 else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_SUBMENU )
426 rAddonMenuEntry[i].Value >>= rAddonSubMenu;
427 else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_CONTEXT )
428 rAddonMenuEntry[i].Value >>= rContext;
432 // Check if the context string matches the provided xModel context
433 sal_Bool AddonMenuManager::IsCorrectContext( const Reference< XModel >& rModel, const ::rtl::OUString& aContext )
435 if ( rModel.is() )
437 Reference< com::sun::star::lang::XServiceInfo > xServiceInfo( rModel, UNO_QUERY );
438 if ( xServiceInfo.is() )
440 sal_Int32 nIndex = 0;
443 ::rtl::OUString aToken = aContext.getToken( 0, ',', nIndex );
445 if ( xServiceInfo->supportsService( aToken ))
446 return sal_True;
448 while ( nIndex >= 0 );
452 return ( aContext.getLength() == 0 );