Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "framework/addonmenu.hxx"
30 : : #include "framework/addonsoptions.hxx"
31 : : #include <general.h>
32 : : #include <macros/debug/assertion.hxx>
33 : : #include <framework/imageproducer.hxx>
34 : : #include <framework/menuconfiguration.hxx>
35 : :
36 : : #include <com/sun/star/uno/Reference.hxx>
37 : : #include <com/sun/star/util/URL.hpp>
38 : : #include <com/sun/star/util/XURLTransformer.hpp>
39 : : #include <com/sun/star/lang/XServiceInfo.hpp>
40 : :
41 : : #include <tools/config.hxx>
42 : : #include <vcl/svapp.hxx>
43 : : #include <svtools/menuoptions.hxx>
44 : : #include <svl/solar.hrc>
45 : :
46 : : using namespace ::com::sun::star::uno;
47 : : using namespace ::com::sun::star::lang;
48 : : using namespace ::com::sun::star::frame;
49 : : using namespace ::com::sun::star::beans;
50 : :
51 : : // Please look at sfx2/inc/sfxsids.hrc the values are defined there. Due to build dependencies
52 : : // we cannot include the header file.
53 : : const sal_uInt16 SID_HELPMENU = (SID_SFX_START + 410);
54 : :
55 : : namespace framework
56 : : {
57 : :
58 : 1104 : AddonMenu::AddonMenu( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& rFrame ) :
59 : 1104 : m_xFrame( rFrame )
60 : : {
61 : 1104 : }
62 : :
63 : 1104 : AddonMenu::~AddonMenu()
64 : : {
65 [ + - ][ + + ]: 17664 : for ( sal_uInt16 i = 0; i < GetItemCount(); i++ )
66 : : {
67 [ + - ][ + + ]: 16560 : if ( GetItemType( i ) != MENUITEM_SEPARATOR )
68 : : {
69 : : // delete user attributes created with new!
70 [ + - ]: 13248 : sal_uInt16 nId = GetItemId( i );
71 [ + - ]: 13248 : MenuConfiguration::Attributes* pUserAttributes = (MenuConfiguration::Attributes*)GetUserValue( nId );
72 [ + - ][ + - ]: 13248 : delete pUserAttributes;
73 [ + - ][ - + ]: 13248 : delete GetPopupMenu( nId );
[ # # ]
74 : : }
75 : : }
76 [ - + ]: 1104 : }
77 : :
78 : : // ------------------------------------------------------------------------
79 : :
80 : : // ------------------------------------------------------------------------
81 : : // Check if command URL string has the unique prefix to identify addon popup menus
82 : 0 : sal_Bool AddonPopupMenu::IsCommandURLPrefix( const ::rtl::OUString& aCmdURL )
83 : : {
84 : 0 : const char aPrefixCharBuf[] = ADDONSPOPUPMENU_URL_PREFIX_STR;
85 : :
86 : 0 : return aCmdURL.matchAsciiL( aPrefixCharBuf, sizeof( aPrefixCharBuf )-1, 0 );
87 : : }
88 : :
89 : 0 : AddonPopupMenu::AddonPopupMenu( const com::sun::star::uno::Reference< com::sun::star::frame::XFrame >& rFrame ) :
90 : 0 : AddonMenu( rFrame )
91 : : {
92 : 0 : }
93 : :
94 : 0 : AddonPopupMenu::~AddonPopupMenu()
95 : : {
96 [ # # ]: 0 : }
97 : :
98 : : // ------------------------------------------------------------------------
99 : :
100 : 1159 : static Reference< XModel > GetModelFromFrame( const Reference< XFrame >& rFrame )
101 : : {
102 : : // Query for the model to get check the context information
103 : 1159 : Reference< XModel > xModel;
104 [ + - ]: 1159 : if ( rFrame.is() )
105 : : {
106 [ + - ][ + - ]: 1159 : Reference< XController > xController( rFrame->getController(), UNO_QUERY );
[ + - ]
107 [ + - ]: 1159 : if ( xController.is() )
108 [ + - ][ + - ]: 1159 : xModel = xController->getModel();
[ + - ]
109 : : }
110 : :
111 : 1159 : return xModel;
112 : : }
113 : :
114 : : // ------------------------------------------------------------------------
115 : :
116 : 1159 : sal_Bool AddonMenuManager::HasAddonMenuElements()
117 : : {
118 [ + - ]: 1159 : return AddonsOptions().HasAddonsMenu();
119 : : }
120 : :
121 : : // Factory method to create different Add-On menu types
122 : 0 : PopupMenu* AddonMenuManager::CreatePopupMenuType( MenuType eMenuType, const Reference< XFrame >& rFrame )
123 : : {
124 [ # # ]: 0 : if ( eMenuType == ADDON_MENU )
125 [ # # ]: 0 : return new AddonMenu( rFrame );
126 [ # # ]: 0 : else if ( eMenuType == ADDON_POPUPMENU )
127 [ # # ]: 0 : return new AddonPopupMenu( rFrame );
128 : : else
129 : 0 : return NULL;
130 : : }
131 : :
132 : : // Create the Add-Ons menu
133 : 0 : AddonMenu* AddonMenuManager::CreateAddonMenu( const Reference< XFrame >& rFrame )
134 : : {
135 [ # # ]: 0 : AddonsOptions aOptions;
136 : 0 : AddonMenu* pAddonMenu = NULL;
137 : 0 : sal_uInt16 nUniqueMenuId = ADDONMENU_ITEMID_START;
138 : :
139 [ # # ]: 0 : const Sequence< Sequence< PropertyValue > >& rAddonMenuEntries = aOptions.GetAddonsMenu();
140 [ # # ]: 0 : if ( rAddonMenuEntries.getLength() > 0 )
141 : : {
142 [ # # ]: 0 : pAddonMenu = (AddonMenu *)AddonMenuManager::CreatePopupMenuType( ADDON_MENU, rFrame );
143 [ # # ]: 0 : Reference< XModel > xModel = GetModelFromFrame( rFrame );
144 [ # # ][ # # ]: 0 : AddonMenuManager::BuildMenu( pAddonMenu, ADDON_MENU, MENU_APPEND, nUniqueMenuId, rAddonMenuEntries, rFrame, xModel );
[ # # ]
145 : :
146 : : // Don't return an empty Add-On menu
147 [ # # ][ # # ]: 0 : if ( pAddonMenu->GetItemCount() == 0 )
148 : : {
149 [ # # ][ # # ]: 0 : delete pAddonMenu;
150 : 0 : pAddonMenu = NULL;
151 : 0 : }
152 : : }
153 : :
154 [ # # ]: 0 : return pAddonMenu;
155 : : }
156 : :
157 : : // Returns the next insert position from nPos.
158 : 0 : sal_uInt16 AddonMenuManager::GetNextPos( sal_uInt16 nPos )
159 : : {
160 [ # # ]: 0 : return ( nPos == MENU_APPEND ) ? MENU_APPEND : ( nPos+1 );
161 : : }
162 : :
163 : :
164 : 2884 : static sal_uInt16 FindMenuId( Menu* pMenu, const String aCommand )
165 : : {
166 : 2884 : sal_uInt16 nPos = 0;
167 [ + - ]: 2884 : String aCmd;
168 [ + - ][ + + ]: 19034 : for ( nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
169 : : {
170 [ + - ]: 18468 : sal_uInt16 nId = pMenu->GetItemId( nPos );
171 [ + - ][ + - ]: 18468 : aCmd = pMenu->GetItemCommand( nId );
172 [ + - ][ + + ]: 18468 : if ( aCmd == aCommand )
173 : 2318 : return nId;
174 : : }
175 : :
176 [ + - ]: 2884 : return USHRT_MAX;
177 : : }
178 : :
179 : :
180 : : // Merge the Add-Ons help menu items into the given menu bar at a defined pos
181 : 1725 : void AddonMenuManager::MergeAddonHelpMenu( const Reference< XFrame >& rFrame, MenuBar* pMergeMenuBar )
182 : : {
183 [ + - ]: 1725 : if ( pMergeMenuBar )
184 : : {
185 : 1725 : PopupMenu* pHelpMenu = pMergeMenuBar->GetPopupMenu( SID_HELPMENU );
186 [ + - ]: 1725 : if ( !pHelpMenu )
187 : : {
188 [ + - ][ + - ]: 1725 : sal_uInt16 nId = FindMenuId(pMergeMenuBar, rtl::OUString(".uno:HelpMenu"));
[ + - ]
189 [ + + ]: 1725 : if ( nId != USHRT_MAX )
190 : 1159 : pHelpMenu = pMergeMenuBar->GetPopupMenu( nId );
191 : : }
192 : :
193 [ + + ]: 1725 : if ( pHelpMenu )
194 : : {
195 : : // Add-Ons help menu items should be inserted after the "registration" menu item
196 [ + - ]: 1159 : sal_uInt16 nItemCount = pHelpMenu->GetItemCount();
197 : 1159 : sal_uInt16 nInsSepAfterPos = MENU_APPEND;
198 : 1159 : sal_uInt16 nUniqueMenuId = ADDONMENU_ITEMID_START;
199 [ + - ]: 1159 : AddonsOptions aOptions;
200 : :
201 : : // try to detect the about menu item with the command URL
202 [ + - ][ + - ]: 1159 : sal_uInt16 nId = FindMenuId(pHelpMenu, rtl::OUString(".uno:About"));
[ + - ]
203 [ + - ]: 1159 : sal_uInt16 nInsPos = pHelpMenu->GetItemPos( nId );
204 : :
205 [ + - ]: 1159 : Sequence< Sequence< PropertyValue > > aAddonSubMenu;
206 [ + - ]: 1159 : const Sequence< Sequence< PropertyValue > >& rAddonHelpMenuEntries = aOptions.GetAddonsHelpMenu();
207 : :
208 [ + - ][ + - ]: 1159 : if ( nInsPos < nItemCount && pHelpMenu->GetItemType( nInsPos ) != MENUITEM_SEPARATOR )
[ + - ][ + - ]
209 : 1159 : nInsSepAfterPos = nInsPos;
210 : :
211 [ + - ]: 1159 : Reference< XModel > xModel = GetModelFromFrame( rFrame );
212 [ + - ][ + - ]: 1159 : AddonMenuManager::BuildMenu( pHelpMenu, ADDON_MENU, nInsPos, nUniqueMenuId, rAddonHelpMenuEntries, rFrame, xModel );
[ + - ]
213 : :
214 [ + - ][ - + ]: 1159 : if ( pHelpMenu->GetItemCount() > nItemCount )
215 : : {
216 [ # # ]: 0 : if ( nInsSepAfterPos < MENU_APPEND )
217 : : {
218 [ # # ]: 0 : nInsSepAfterPos += ( pHelpMenu->GetItemCount() - nItemCount );
219 [ # # ][ # # ]: 0 : if ( pHelpMenu->GetItemType( nInsSepAfterPos ) != MENUITEM_SEPARATOR )
220 [ # # ]: 0 : pHelpMenu->InsertSeparator( nInsSepAfterPos );
221 : : }
222 [ # # ]: 0 : pHelpMenu->InsertSeparator( nItemCount );
223 [ + - ][ + - ]: 1159 : }
224 : : }
225 : : }
226 : 1725 : }
227 : :
228 : : // Merge the addon popup menus into the given menu bar at the provided pos.
229 : 1159 : void AddonMenuManager::MergeAddonPopupMenus( const Reference< XFrame >& rFrame,
230 : : const Reference< XModel >& rModel,
231 : : sal_uInt16 nMergeAtPos,
232 : : MenuBar* pMergeMenuBar )
233 : : {
234 [ + - ]: 1159 : if ( pMergeMenuBar )
235 : : {
236 [ + - ]: 1159 : AddonsOptions aAddonsOptions;
237 : 1159 : sal_uInt16 nInsertPos = nMergeAtPos;
238 : :
239 : 1159 : ::rtl::OUString aTitle;
240 : 1159 : ::rtl::OUString aURL;
241 : 1159 : ::rtl::OUString aTarget;
242 : 1159 : ::rtl::OUString aImageId;
243 : 1159 : ::rtl::OUString aContext;
244 [ + - ]: 1159 : Sequence< Sequence< PropertyValue > > aAddonSubMenu;
245 : 1159 : sal_uInt16 nUniqueMenuId = ADDONMENU_ITEMID_START;
246 : :
247 [ + - ]: 1159 : const Sequence< Sequence< PropertyValue > >& rAddonMenuEntries = aAddonsOptions.GetAddonsMenuBarPart();
248 [ - + ]: 1159 : for ( sal_Int32 i = 0; i < rAddonMenuEntries.getLength(); i++ )
249 : : {
250 : 0 : AddonMenuManager::GetMenuEntry( rAddonMenuEntries[i],
251 : : aTitle,
252 : : aURL,
253 : : aTarget,
254 : : aImageId,
255 : : aContext,
256 [ # # ]: 0 : aAddonSubMenu );
257 [ # # # # : 0 : if ( !aTitle.isEmpty() &&
# # ][ # # ]
[ # # ]
258 : 0 : !aURL.isEmpty() &&
259 : 0 : aAddonSubMenu.getLength() > 0 &&
260 [ # # ]: 0 : AddonMenuManager::IsCorrectContext( rModel, aContext ))
261 : : {
262 : 0 : sal_uInt16 nId = nUniqueMenuId++;
263 [ # # ]: 0 : AddonPopupMenu* pAddonPopupMenu = (AddonPopupMenu *)AddonMenuManager::CreatePopupMenuType( ADDON_POPUPMENU, rFrame );
264 : :
265 [ # # ][ # # ]: 0 : AddonMenuManager::BuildMenu( pAddonPopupMenu, ADDON_MENU, MENU_APPEND, nUniqueMenuId, aAddonSubMenu, rFrame, rModel );
[ # # ]
266 : :
267 [ # # ][ # # ]: 0 : if ( pAddonPopupMenu->GetItemCount() > 0 )
268 : : {
269 : 0 : pAddonPopupMenu->SetCommandURL( aURL );
270 [ # # ][ # # ]: 0 : pMergeMenuBar->InsertItem( nId, aTitle, 0, nInsertPos++ );
[ # # ]
271 [ # # ]: 0 : pMergeMenuBar->SetPopupMenu( nId, pAddonPopupMenu );
272 : :
273 : : // Store the command URL into the VCL menu bar for later identification
274 [ # # ][ # # ]: 0 : pMergeMenuBar->SetItemCommand( nId, aURL );
[ # # ]
275 : : }
276 : : else
277 [ # # ][ # # ]: 0 : delete pAddonPopupMenu;
278 : : }
279 [ + - ][ + - ]: 1159 : }
280 : : }
281 : 1159 : }
282 : :
283 : : // Insert the menu and sub menu entries into pCurrentMenu with the aAddonMenuDefinition provided
284 : 1159 : void AddonMenuManager::BuildMenu( PopupMenu* pCurrentMenu,
285 : : MenuType nSubMenuType,
286 : : sal_uInt16 nInsPos,
287 : : sal_uInt16& nUniqueMenuId,
288 : : Sequence< Sequence< PropertyValue > > aAddonMenuDefinition,
289 : : const Reference< XFrame >& rFrame,
290 : : const Reference< XModel >& rModel )
291 : : {
292 [ + - ]: 1159 : Sequence< Sequence< PropertyValue > > aAddonSubMenu;
293 : 1159 : sal_Bool bInsertSeparator = sal_False;
294 : 1159 : sal_uInt32 i = 0;
295 : 1159 : sal_uInt32 nElements = 0;
296 : 1159 : sal_uInt32 nCount = aAddonMenuDefinition.getLength();
297 [ + - ]: 1159 : AddonsOptions aAddonsOptions;
298 : :
299 : 1159 : ::rtl::OUString aTitle;
300 : 1159 : ::rtl::OUString aURL;
301 : 1159 : ::rtl::OUString aTarget;
302 : 1159 : ::rtl::OUString aImageId;
303 : 1159 : ::rtl::OUString aContext;
304 : :
305 [ - + ]: 1159 : for ( i = 0; i < nCount; ++i )
306 : : {
307 [ # # ][ # # ]: 0 : GetMenuEntry( aAddonMenuDefinition[i], aTitle, aURL, aTarget, aImageId, aContext, aAddonSubMenu );
308 : :
309 [ # # ][ # # ]: 0 : if ( !IsCorrectContext( rModel, aContext ) || ( aTitle.isEmpty() && aURL.isEmpty() ))
[ # # ][ # # ]
[ # # ]
310 : 0 : continue;
311 : :
312 [ # # ][ # # ]: 0 : if ( aURL == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:separator" )))
313 : 0 : bInsertSeparator = sal_True;
314 : : else
315 : : {
316 : 0 : PopupMenu* pSubMenu = NULL;
317 [ # # ]: 0 : if ( aAddonSubMenu.getLength() > 0 )
318 : : {
319 [ # # ]: 0 : pSubMenu = AddonMenuManager::CreatePopupMenuType( nSubMenuType, rFrame );
320 [ # # ][ # # ]: 0 : AddonMenuManager::BuildMenu( pSubMenu, nSubMenuType, MENU_APPEND, nUniqueMenuId, aAddonSubMenu, rFrame, rModel );
[ # # ]
321 : :
322 : : // Don't create a menu item for an empty sub menu
323 [ # # ][ # # ]: 0 : if ( pSubMenu->GetItemCount() == 0 )
324 : : {
325 [ # # ][ # # ]: 0 : delete pSubMenu;
326 : 0 : pSubMenu = NULL;
327 : 0 : continue;
328 : : }
329 : : }
330 : :
331 [ # # ][ # # ]: 0 : if ( bInsertSeparator && nElements > 0 )
332 : : {
333 : : // Insert a separator only when we insert a new element afterwards and we
334 : : // have already one before us
335 : 0 : nElements = 0;
336 : 0 : bInsertSeparator = sal_False;
337 [ # # ]: 0 : pCurrentMenu->InsertSeparator( nInsPos );
338 [ # # ]: 0 : nInsPos = AddonMenuManager::GetNextPos( nInsPos );
339 : : }
340 : :
341 : 0 : sal_uInt16 nId = nUniqueMenuId++;
342 [ # # ][ # # ]: 0 : pCurrentMenu->InsertItem( nId, aTitle, 0, nInsPos );
[ # # ]
343 [ # # ]: 0 : nInsPos = AddonMenuManager::GetNextPos( nInsPos );
344 : :
345 : 0 : ++nElements;
346 : :
347 : : // Store values from configuration to the New and Wizard menu entries to enable
348 : : // sfx2 based code to support high contrast mode correctly!
349 [ # # ][ # # ]: 0 : pCurrentMenu->SetUserValue( nId, sal_uIntPtr( new MenuConfiguration::Attributes( aTarget, aImageId )) );
[ # # ]
350 [ # # ][ # # ]: 0 : pCurrentMenu->SetItemCommand( nId, aURL );
[ # # ]
351 : :
352 [ # # ]: 0 : if ( pSubMenu )
353 [ # # ]: 0 : pCurrentMenu->SetPopupMenu( nId, pSubMenu );
354 : : }
355 [ + - ][ + - ]: 1159 : }
356 : 1159 : }
357 : :
358 : : // Retrieve the menu entry property values from a sequence
359 : 0 : void AddonMenuManager::GetMenuEntry( const Sequence< PropertyValue >& rAddonMenuEntry,
360 : : ::rtl::OUString& rTitle,
361 : : ::rtl::OUString& rURL,
362 : : ::rtl::OUString& rTarget,
363 : : ::rtl::OUString& rImageId,
364 : : ::rtl::OUString& rContext,
365 : : Sequence< Sequence< PropertyValue > >& rAddonSubMenu )
366 : : {
367 : : // Reset submenu parameter
368 [ # # ]: 0 : rAddonSubMenu = Sequence< Sequence< PropertyValue > >();
369 : :
370 [ # # ]: 0 : for ( int i = 0; i < rAddonMenuEntry.getLength(); i++ )
371 : : {
372 : 0 : ::rtl::OUString aMenuEntryPropName = rAddonMenuEntry[i].Name;
373 [ # # ][ # # ]: 0 : if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_URL )
374 : 0 : rAddonMenuEntry[i].Value >>= rURL;
375 [ # # ][ # # ]: 0 : else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_TITLE )
376 : 0 : rAddonMenuEntry[i].Value >>= rTitle;
377 [ # # ][ # # ]: 0 : else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_TARGET )
378 : 0 : rAddonMenuEntry[i].Value >>= rTarget;
379 [ # # ][ # # ]: 0 : else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_IMAGEIDENTIFIER )
380 : 0 : rAddonMenuEntry[i].Value >>= rImageId;
381 [ # # ][ # # ]: 0 : else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_SUBMENU )
382 [ # # ]: 0 : rAddonMenuEntry[i].Value >>= rAddonSubMenu;
383 [ # # ][ # # ]: 0 : else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_CONTEXT )
384 : 0 : rAddonMenuEntry[i].Value >>= rContext;
385 : 0 : }
386 : 0 : }
387 : :
388 : : // Check if the context string matches the provided xModel context
389 : 0 : sal_Bool AddonMenuManager::IsCorrectContext( const Reference< XModel >& rModel, const ::rtl::OUString& aContext )
390 : : {
391 [ # # ]: 0 : if ( rModel.is() )
392 : : {
393 [ # # ]: 0 : Reference< com::sun::star::lang::XServiceInfo > xServiceInfo( rModel, UNO_QUERY );
394 [ # # ]: 0 : if ( xServiceInfo.is() )
395 : : {
396 : 0 : sal_Int32 nIndex = 0;
397 [ # # ]: 0 : do
398 : : {
399 : 0 : ::rtl::OUString aToken = aContext.getToken( 0, ',', nIndex );
400 : :
401 [ # # ][ # # ]: 0 : if ( xServiceInfo->supportsService( aToken ))
[ # # ]
402 [ # # ]: 0 : return sal_True;
403 : : }
404 : : while ( nIndex >= 0 );
405 [ # # ]: 0 : }
406 : : }
407 : :
408 : 0 : return ( aContext.isEmpty() );
409 : : }
410 : :
411 : : }
412 : :
413 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|