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 $
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 //_________________________________________________________________________________________________________________
36 //_________________________________________________________________________________________________________________
37 #include "classes/addonmenu.hxx"
38 #include "classes/addonsoptions.hxx"
40 #include <macros/debug/assertion.hxx>
41 #include <helper/imageproducer.hxx>
42 #include <xml/menuconfiguration.hxx>
44 //_________________________________________________________________________________________________________________
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 //_________________________________________________________________________________________________________________
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);
77 AddonMenu::AddonMenu( const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::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
) :
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
;
125 Reference
< XController
> xController( rFrame
->getController(), UNO_QUERY
);
126 if ( xController
.is() )
127 xModel
= xController
->getModel();
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
);
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 )
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
)
192 for ( nPos
= 0; nPos
< pMenu
->GetItemCount(); nPos
++ )
194 USHORT nId
= pMenu
->GetItemId( nPos
);
195 aCmd
= pMenu
->GetItemCommand( nId
);
196 if ( aCmd
== aCommand
)
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
)
209 PopupMenu
* pHelpMenu
= pMergeMenuBar
->GetPopupMenu( SID_HELPMENU
);
212 USHORT nId
= FindMenuId( pMergeMenuBar
, String::CreateFromAscii( ".uno:HelpMenu" ));
213 if ( nId
!= USHRT_MAX
)
214 pHelpMenu
= pMergeMenuBar
->GetPopupMenu( nId
);
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
);
239 if ( nRegPos
== USHRT_MAX
)
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
);
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 );
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
,
280 MenuBar
* 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
],
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
);
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
,
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
;
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() ))
360 if ( aURL
== ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:separator" )))
361 bInsertSeparator
= TRUE
;
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 )
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
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
);
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
);
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
)
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
))
452 while ( nIndex
>= 0 );
456 return ( aContext
.getLength() == 0 );