merge the formfield patch from ooo-build
[ooovba.git] / framework / source / classes / addonmenu.cxx
blob35b61510cefce7b6c19943b58343ddf71b67a5b4
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: addonmenu.cxx,v $
10 * $Revision: 1.15 $
12 * This file is part of OpenOffice.org.
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.
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).
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.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_framework.hxx"
34 //_________________________________________________________________________________________________________________
35 // my own includes
36 //_________________________________________________________________________________________________________________
37 #include "classes/addonmenu.hxx"
38 #include "classes/addonsoptions.hxx"
39 #include <general.h>
40 #include <macros/debug/assertion.hxx>
41 #include <helper/imageproducer.hxx>
42 #include <xml/menuconfiguration.hxx>
44 //_________________________________________________________________________________________________________________
45 // interface includes
46 //_________________________________________________________________________________________________________________
47 #include <com/sun/star/uno/Reference.hxx>
48 #include <com/sun/star/util/URL.hpp>
49 #include <com/sun/star/util/XURLTransformer.hpp>
50 #include <com/sun/star/lang/XServiceInfo.hpp>
52 //_________________________________________________________________________________________________________________
53 // includes of other projects
54 //_________________________________________________________________________________________________________________
55 #include <tools/config.hxx>
56 #include <vcl/svapp.hxx>
57 #include <svtools/menuoptions.hxx>
59 //_________________________________________________________________________________________________________________
60 // namespace
61 //_________________________________________________________________________________________________________________
63 using namespace ::com::sun::star::uno;
64 using namespace ::com::sun::star::lang;
65 using namespace ::com::sun::star::frame;
66 using namespace ::com::sun::star::beans;
68 // Please look at sfx2/inc/sfxsids.hrc the values are defined there. Due to build dependencies
69 // we cannot include the header file.
70 const USHORT SID_SFX_START = 5000;
71 const USHORT SID_HELPMENU = (SID_SFX_START + 410);
72 const USHORT SID_ONLINE_REGISTRATION = (SID_SFX_START + 1537);
74 namespace framework
77 AddonMenu::AddonMenu( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& rFrame ) :
78 m_xFrame( rFrame )
82 AddonMenu::~AddonMenu()
84 for ( USHORT i = 0; i < GetItemCount(); i++ )
86 if ( GetItemType( i ) != MENUITEM_SEPARATOR )
88 // delete user attributes created with new!
89 USHORT nId = GetItemId( i );
90 MenuConfiguration::Attributes* pUserAttributes = (MenuConfiguration::Attributes*)GetUserValue( nId );
91 delete pUserAttributes;
92 delete GetPopupMenu( nId );
97 // ------------------------------------------------------------------------
99 // ------------------------------------------------------------------------
100 // Check if command URL string has the unique prefix to identify addon popup menus
101 sal_Bool AddonPopupMenu::IsCommandURLPrefix( const ::rtl::OUString& aCmdURL )
103 const char aPrefixCharBuf[] = ADDONSPOPUPMENU_URL_PREFIX_STR;
105 return aCmdURL.matchAsciiL( aPrefixCharBuf, sizeof( aPrefixCharBuf )-1, 0 );
108 AddonPopupMenu::AddonPopupMenu( const com::sun::star::uno::Reference< com::sun::star::frame::XFrame >& rFrame ) :
109 AddonMenu( rFrame )
113 AddonPopupMenu::~AddonPopupMenu()
117 // ------------------------------------------------------------------------
119 static Reference< XModel > GetModelFromFrame( const Reference< XFrame >& rFrame )
121 // Query for the model to get check the context information
122 Reference< XModel > xModel;
123 if ( rFrame.is() )
125 Reference< XController > xController( rFrame->getController(), UNO_QUERY );
126 if ( xController.is() )
127 xModel = xController->getModel();
130 return xModel;
133 // ------------------------------------------------------------------------
135 sal_Bool AddonMenuManager::HasAddonMenuElements()
137 return AddonsOptions().HasAddonsMenu();
140 sal_Bool AddonMenuManager::HasAddonHelpMenuElements()
142 return AddonsOptions().HasAddonsHelpMenu();
145 // Factory method to create different Add-On menu types
146 PopupMenu* AddonMenuManager::CreatePopupMenuType( MenuType eMenuType, const Reference< XFrame >& rFrame )
148 if ( eMenuType == ADDON_MENU )
149 return new AddonMenu( rFrame );
150 else if ( eMenuType == ADDON_POPUPMENU )
151 return new AddonPopupMenu( rFrame );
152 else
153 return NULL;
156 // Create the Add-Ons menu
157 AddonMenu* AddonMenuManager::CreateAddonMenu( const Reference< XFrame >& rFrame )
159 AddonsOptions aOptions;
160 AddonMenu* pAddonMenu = NULL;
161 USHORT nUniqueMenuId = ADDONMENU_ITEMID_START;
163 const Sequence< Sequence< PropertyValue > >& rAddonMenuEntries = aOptions.GetAddonsMenu();
164 if ( rAddonMenuEntries.getLength() > 0 )
166 pAddonMenu = (AddonMenu *)AddonMenuManager::CreatePopupMenuType( ADDON_MENU, rFrame );
167 Reference< XModel > xModel = GetModelFromFrame( rFrame );
168 AddonMenuManager::BuildMenu( pAddonMenu, ADDON_MENU, MENU_APPEND, nUniqueMenuId, rAddonMenuEntries, rFrame, xModel );
170 // Don't return an empty Add-On menu
171 if ( pAddonMenu->GetItemCount() == 0 )
173 delete pAddonMenu;
174 pAddonMenu = NULL;
178 return pAddonMenu;
181 // Returns the next insert position from nPos.
182 USHORT AddonMenuManager::GetNextPos( USHORT nPos )
184 return ( nPos == MENU_APPEND ) ? MENU_APPEND : ( nPos+1 );
188 static USHORT FindMenuId( Menu* pMenu, const String aCommand )
190 USHORT nPos = 0;
191 String aCmd;
192 for ( nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
194 USHORT nId = pMenu->GetItemId( nPos );
195 aCmd = pMenu->GetItemCommand( nId );
196 if ( aCmd == aCommand )
197 return nId;
200 return USHRT_MAX;
204 // Merge the Add-Ons help menu items into the given menu bar at a defined pos
205 void AddonMenuManager::MergeAddonHelpMenu( const Reference< XFrame >& rFrame, MenuBar* pMergeMenuBar )
207 if ( pMergeMenuBar )
209 PopupMenu* pHelpMenu = pMergeMenuBar->GetPopupMenu( SID_HELPMENU );
210 if ( !pHelpMenu )
212 USHORT nId = FindMenuId( pMergeMenuBar, String::CreateFromAscii( ".uno:HelpMenu" ));
213 if ( nId != USHRT_MAX )
214 pHelpMenu = pMergeMenuBar->GetPopupMenu( nId );
217 if ( pHelpMenu )
219 static const char REFERENCECOMMAND_AFTER[] = ".uno:OnlineRegistrationDlg";
220 static const char REFERENCECOMMAND_BEFORE[] = ".uno:About";
222 // Add-Ons help menu items should be inserted after the "registration" menu item
223 bool bAddAfter = true;
224 USHORT nItemCount = pHelpMenu->GetItemCount();
225 USHORT nRegPos = pHelpMenu->GetItemPos( SID_ONLINE_REGISTRATION );
226 USHORT nInsPos = nRegPos;
227 USHORT nInsSepAfterPos = MENU_APPEND;
228 USHORT nUniqueMenuId = ADDONMENU_ITEMID_START;
229 AddonsOptions aOptions;
231 if ( nRegPos == USHRT_MAX )
233 // try to detect the online registration dialog menu item with the command URL
234 USHORT nId = FindMenuId( pHelpMenu, String::CreateFromAscii( REFERENCECOMMAND_AFTER ));
235 nRegPos = pHelpMenu->GetItemPos( nId );
236 nInsPos = nRegPos;
239 if ( nRegPos == USHRT_MAX )
241 // second try:
242 // try to detect the about menu item with the command URL
243 USHORT nId = FindMenuId( pHelpMenu, String::CreateFromAscii( REFERENCECOMMAND_BEFORE ));
244 nRegPos = pHelpMenu->GetItemPos( nId );
245 nInsPos = nRegPos;
246 bAddAfter = false;
249 Sequence< Sequence< PropertyValue > > aAddonSubMenu;
250 const Sequence< Sequence< PropertyValue > >& rAddonHelpMenuEntries = aOptions.GetAddonsHelpMenu();
252 nInsPos = bAddAfter ? AddonMenuManager::GetNextPos( nInsPos ) : nInsPos;
253 if ( nInsPos < nItemCount && pHelpMenu->GetItemType( nInsPos ) != MENUITEM_SEPARATOR )
254 nInsSepAfterPos = nInsPos;
256 Reference< XModel > xModel = GetModelFromFrame( rFrame );
257 AddonMenuManager::BuildMenu( pHelpMenu, ADDON_MENU, nInsPos, nUniqueMenuId, rAddonHelpMenuEntries, rFrame, xModel );
259 if ( pHelpMenu->GetItemCount() > nItemCount )
261 if ( nInsSepAfterPos < MENU_APPEND )
263 nInsSepAfterPos += ( pHelpMenu->GetItemCount() - nItemCount );
264 if ( pHelpMenu->GetItemType( nInsSepAfterPos ) != MENUITEM_SEPARATOR )
265 pHelpMenu->InsertSeparator( nInsSepAfterPos );
267 if ( nRegPos < MENU_APPEND )
268 pHelpMenu->InsertSeparator( nRegPos+1 );
269 else
270 pHelpMenu->InsertSeparator( nItemCount );
276 // Merge the addon popup menus into the given menu bar at the provided pos.
277 void AddonMenuManager::MergeAddonPopupMenus( const Reference< XFrame >& rFrame,
278 const Reference< XModel >& rModel,
279 USHORT nMergeAtPos,
280 MenuBar* pMergeMenuBar )
282 if ( pMergeMenuBar )
284 AddonsOptions aAddonsOptions;
285 USHORT nInsertPos = nMergeAtPos;
287 ::rtl::OUString aTitle;
288 ::rtl::OUString aURL;
289 ::rtl::OUString aTarget;
290 ::rtl::OUString aImageId;
291 ::rtl::OUString aContext;
292 Sequence< Sequence< PropertyValue > > aAddonSubMenu;
293 USHORT nUniqueMenuId = ADDONMENU_ITEMID_START;
295 const Sequence< Sequence< PropertyValue > >& rAddonMenuEntries = aAddonsOptions.GetAddonsMenuBarPart();
296 for ( sal_Int32 i = 0; i < rAddonMenuEntries.getLength(); i++ )
298 AddonMenuManager::GetMenuEntry( rAddonMenuEntries[i],
299 aTitle,
300 aURL,
301 aTarget,
302 aImageId,
303 aContext,
304 aAddonSubMenu );
305 if ( aTitle.getLength() > 0 &&
306 aURL.getLength() > 0 &&
307 aAddonSubMenu.getLength() > 0 &&
308 AddonMenuManager::IsCorrectContext( rModel, aContext ))
310 USHORT nId = nUniqueMenuId++;
311 AddonPopupMenu* pAddonPopupMenu = (AddonPopupMenu *)AddonMenuManager::CreatePopupMenuType( ADDON_POPUPMENU, rFrame );
313 AddonMenuManager::BuildMenu( pAddonPopupMenu, ADDON_MENU, MENU_APPEND, nUniqueMenuId, aAddonSubMenu, rFrame, rModel );
315 if ( pAddonPopupMenu->GetItemCount() > 0 )
317 pAddonPopupMenu->SetCommandURL( aURL );
318 pMergeMenuBar->InsertItem( nId, aTitle, 0, nInsertPos++ );
319 pMergeMenuBar->SetPopupMenu( nId, pAddonPopupMenu );
321 // Store the command URL into the VCL menu bar for later identification
322 pMergeMenuBar->SetItemCommand( nId, aURL );
324 else
325 delete pAddonPopupMenu;
331 // Insert the menu and sub menu entries into pCurrentMenu with the aAddonMenuDefinition provided
332 void AddonMenuManager::BuildMenu( PopupMenu* pCurrentMenu,
333 MenuType nSubMenuType,
334 USHORT nInsPos,
335 USHORT& nUniqueMenuId,
336 Sequence< Sequence< PropertyValue > > aAddonMenuDefinition,
337 const Reference< XFrame >& rFrame,
338 const Reference< XModel >& rModel )
340 Sequence< Sequence< PropertyValue > > aAddonSubMenu;
341 BOOL bInsertSeparator = FALSE;
342 UINT32 i = 0;
343 UINT32 nElements = 0;
344 UINT32 nCount = aAddonMenuDefinition.getLength();
345 AddonsOptions aAddonsOptions;
347 ::rtl::OUString aTitle;
348 ::rtl::OUString aURL;
349 ::rtl::OUString aTarget;
350 ::rtl::OUString aImageId;
351 ::rtl::OUString aContext;
353 for ( i = 0; i < nCount; ++i )
355 GetMenuEntry( aAddonMenuDefinition[i], aTitle, aURL, aTarget, aImageId, aContext, aAddonSubMenu );
357 if ( !IsCorrectContext( rModel, aContext ) || ( !aTitle.getLength() && !aURL.getLength() ))
358 continue;
360 if ( aURL == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:separator" )))
361 bInsertSeparator = TRUE;
362 else
364 PopupMenu* pSubMenu = NULL;
365 if ( aAddonSubMenu.getLength() > 0 )
367 pSubMenu = AddonMenuManager::CreatePopupMenuType( nSubMenuType, rFrame );
368 AddonMenuManager::BuildMenu( pSubMenu, nSubMenuType, MENU_APPEND, nUniqueMenuId, aAddonSubMenu, rFrame, rModel );
370 // Don't create a menu item for an empty sub menu
371 if ( pSubMenu->GetItemCount() == 0 )
373 delete pSubMenu;
374 pSubMenu = NULL;
375 continue;
379 if ( bInsertSeparator && nElements > 0 )
381 // Insert a separator only when we insert a new element afterwards and we
382 // have already one before us
383 nElements = 0;
384 bInsertSeparator = FALSE;
385 pCurrentMenu->InsertSeparator( nInsPos );
386 nInsPos = AddonMenuManager::GetNextPos( nInsPos );
389 USHORT nId = nUniqueMenuId++;
390 pCurrentMenu->InsertItem( nId, aTitle, 0, nInsPos );
391 nInsPos = AddonMenuManager::GetNextPos( nInsPos );
393 ++nElements;
395 // Store values from configuration to the New and Wizard menu entries to enable
396 // sfx2 based code to support high contrast mode correctly!
397 pCurrentMenu->SetUserValue( nId, ULONG( new MenuConfiguration::Attributes( aTarget, aImageId )) );
398 pCurrentMenu->SetItemCommand( nId, aURL );
400 if ( pSubMenu )
401 pCurrentMenu->SetPopupMenu( nId, pSubMenu );
406 // Retrieve the menu entry property values from a sequence
407 void AddonMenuManager::GetMenuEntry( const Sequence< PropertyValue >& rAddonMenuEntry,
408 ::rtl::OUString& rTitle,
409 ::rtl::OUString& rURL,
410 ::rtl::OUString& rTarget,
411 ::rtl::OUString& rImageId,
412 ::rtl::OUString& rContext,
413 Sequence< Sequence< PropertyValue > >& rAddonSubMenu )
415 // Reset submenu parameter
416 rAddonSubMenu = Sequence< Sequence< PropertyValue > >();
418 for ( int i = 0; i < rAddonMenuEntry.getLength(); i++ )
420 ::rtl::OUString aMenuEntryPropName = rAddonMenuEntry[i].Name;
421 if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_URL )
422 rAddonMenuEntry[i].Value >>= rURL;
423 else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_TITLE )
424 rAddonMenuEntry[i].Value >>= rTitle;
425 else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_TARGET )
426 rAddonMenuEntry[i].Value >>= rTarget;
427 else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_IMAGEIDENTIFIER )
428 rAddonMenuEntry[i].Value >>= rImageId;
429 else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_SUBMENU )
430 rAddonMenuEntry[i].Value >>= rAddonSubMenu;
431 else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_CONTEXT )
432 rAddonMenuEntry[i].Value >>= rContext;
436 // Check if the context string matches the provided xModel context
437 sal_Bool AddonMenuManager::IsCorrectContext( const Reference< XModel >& rModel, const ::rtl::OUString& aContext )
439 if ( rModel.is() )
441 Reference< com::sun::star::lang::XServiceInfo > xServiceInfo( rModel, UNO_QUERY );
442 if ( xServiceInfo.is() )
444 sal_Int32 nIndex = 0;
447 ::rtl::OUString aToken = aContext.getToken( 0, ',', nIndex );
449 if ( xServiceInfo->supportsService( aToken ))
450 return sal_True;
452 while ( nIndex >= 0 );
456 return ( aContext.getLength() == 0 );