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 //_________________________________________________________________________________________________________________
33 //_________________________________________________________________________________________________________________
34 #include "classes/addonmenu.hxx"
35 #include "classes/addonsoptions.hxx"
37 #include <macros/debug/assertion.hxx>
38 #include <helper/imageproducer.hxx>
39 #include <xml/menuconfiguration.hxx>
41 //_________________________________________________________________________________________________________________
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 //_________________________________________________________________________________________________________________
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);
73 AddonMenu::AddonMenu( const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::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
) :
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
;
121 Reference
< XController
> xController( rFrame
->getController(), UNO_QUERY
);
122 if ( xController
.is() )
123 xModel
= xController
->getModel();
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
);
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 )
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
)
188 for ( nPos
= 0; nPos
< pMenu
->GetItemCount(); nPos
++ )
190 USHORT nId
= pMenu
->GetItemId( nPos
);
191 aCmd
= pMenu
->GetItemCommand( nId
);
192 if ( aCmd
== aCommand
)
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
)
205 PopupMenu
* pHelpMenu
= pMergeMenuBar
->GetPopupMenu( SID_HELPMENU
);
208 USHORT nId
= FindMenuId( pMergeMenuBar
, String::CreateFromAscii( ".uno:HelpMenu" ));
209 if ( nId
!= USHRT_MAX
)
210 pHelpMenu
= pMergeMenuBar
->GetPopupMenu( nId
);
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
);
235 if ( nRegPos
== USHRT_MAX
)
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
);
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 );
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
,
276 MenuBar
* 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
],
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
);
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
,
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
;
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() ))
356 if ( aURL
== ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:separator" )))
357 bInsertSeparator
= TRUE
;
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 )
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
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
);
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
);
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
)
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
))
448 while ( nIndex
>= 0 );
452 return ( aContext
.getLength() == 0 );