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 : :
30 : : #include <uielement/menubarmerger.hxx>
31 : : #include <framework/addonsoptions.hxx>
32 : :
33 : : using namespace ::com::sun::star;
34 : :
35 : : static const char SEPARATOR_STRING[] = "private:separator";
36 : : static const sal_uInt32 SEPARATOR_STRING_LEN = 17;
37 : :
38 : : static const char MERGECOMMAND_ADDAFTER[] = "AddAfter";
39 : : static const sal_uInt32 MERGECOMMAND_ADDAFTER_LEN = 8;
40 : : static const char MERGECOMMAND_ADDBEFORE[] = "AddBefore";
41 : : static const sal_uInt32 MERGECOMMAND_ADDBEFORE_LEN = 9;
42 : : static const char MERGECOMMAND_REPLACE[] = "Replace";
43 : : static const sal_uInt32 MERGECOMMAND_REPLACE_LEN = 7;
44 : : static const char MERGECOMMAND_REMOVE[] = "Remove";
45 : : static const sal_uInt32 MERGECOMMAND_REMOVE_LEN = 6;
46 : :
47 : : static const char MERGEFALLBACK_ADDPATH[] = "AddPath";
48 : : static const char MERGEFALLBACK_ADDPATH_LEN = 7;
49 : : static const char MERGEFALLBACK_IGNORE[] = "Ignore";
50 : : static const char MERGEFALLBACK_IGNORE_LEN = 6;
51 : :
52 : :
53 : : namespace framework
54 : : {
55 : :
56 : : /**
57 : : Check whether a module identifier is part of a context
58 : : defined by a colon separated list of module identifier.
59 : :
60 : : @param
61 : : rContext
62 : :
63 : : Describes a context string list where all contexts
64 : : are delimited by a colon. For more information about
65 : : the module identifier used as context strings see the
66 : : IDL description of com::sun::star::frame::XModuleManager
67 : :
68 : : @param
69 : : rModuleIdentifier
70 : :
71 : : A string describing a module identifier. See IDL
72 : : description of com::sun::star::frame::XModuleManager.
73 : :
74 : : */
75 : 1211 : bool MenuBarMerger::IsCorrectContext( const ::rtl::OUString& rContext, const ::rtl::OUString& rModuleIdentifier )
76 : : {
77 [ + + ][ + + ]: 1211 : return ( rContext.isEmpty() || ( rContext.indexOf( rModuleIdentifier ) >= 0 ));
78 : : }
79 : :
80 : 26 : void MenuBarMerger::RetrieveReferencePath(
81 : : const ::rtl::OUString& rReferencePathString,
82 : : ::std::vector< ::rtl::OUString >& rReferencePath )
83 : : {
84 : 26 : const sal_Char aDelimiter = '\\';
85 : :
86 : 26 : rReferencePath.clear();
87 : 26 : sal_Int32 nIndex( 0 );
88 [ + + ]: 52 : do
89 : : {
90 : 52 : ::rtl::OUString aToken = rReferencePathString.getToken( 0, aDelimiter, nIndex );
91 [ + - ]: 52 : if ( !aToken.isEmpty() )
92 [ + - ]: 52 : rReferencePath.push_back( aToken );
93 : : }
94 : : while ( nIndex >= 0 );
95 : 26 : }
96 : :
97 : 26 : ReferencePathInfo MenuBarMerger::FindReferencePath(
98 : : const ::std::vector< ::rtl::OUString >& rReferencePath,
99 : : Menu* pMenu )
100 : : {
101 : 26 : sal_uInt32 i( 0 );
102 : 26 : const sal_uInt32 nCount( rReferencePath.size() );
103 : :
104 : : ReferencePathInfo aResult;
105 [ - + ]: 26 : if ( !nCount )
106 : : {
107 : 0 : aResult.eResult = RP_MENUITEM_NOT_FOUND;
108 : 0 : return aResult;
109 : : }
110 : :
111 : 26 : Menu* pCurrMenu( pMenu );
112 : 26 : RPResultInfo eResult( RP_OK );
113 : :
114 : 26 : sal_Int32 nLevel( - 1 );
115 : 26 : sal_uInt16 nPos( MENU_ITEM_NOTFOUND );
116 [ + + ][ + - ]: 52 : do
[ + + ][ + - ]
117 : : {
118 : 52 : ++nLevel;
119 : 52 : ::rtl::OUString aCmd( rReferencePath[i] );
120 : :
121 [ + + ]: 52 : if ( i == nCount-1 )
122 : : {
123 : : // Check last reference path element. Must be a leave (menu item).
124 [ + - ]: 26 : sal_uInt16 nTmpPos = FindMenuItem( aCmd, pCurrMenu );
125 [ + - ]: 26 : if ( nTmpPos != MENU_ITEM_NOTFOUND )
126 : 26 : nPos = nTmpPos;
127 [ + - ]: 26 : eResult = ( nTmpPos != MENU_ITEM_NOTFOUND ) ? RP_OK : RP_MENUITEM_NOT_FOUND;
128 : : }
129 : : else
130 : : {
131 : : // Check reference path element. Must be a node (popup menu)!
132 [ + - ]: 26 : sal_uInt16 nTmpPos = FindMenuItem( aCmd, pCurrMenu );
133 [ + - ]: 26 : if ( nTmpPos != MENU_ITEM_NOTFOUND )
134 : : {
135 [ + - ]: 26 : sal_uInt16 nItemId = pCurrMenu->GetItemId( nTmpPos );
136 [ + - ]: 26 : Menu* pTmpMenu = pCurrMenu->GetPopupMenu( nItemId );
137 [ + - ]: 26 : if ( pTmpMenu != 0 )
138 : 26 : pCurrMenu = pTmpMenu;
139 : : else
140 : : {
141 : 0 : nPos = nTmpPos;
142 : 0 : eResult = RP_MENUITEM_INSTEAD_OF_POPUPMENU_FOUND;
143 : : }
144 : : }
145 : : else
146 : 0 : eResult = RP_POPUPMENU_NOT_FOUND;
147 : : }
148 : 52 : i++;
149 : : }
150 : : while (( pCurrMenu != 0 ) && ( i < nCount ) && ( eResult == RP_OK ));
151 : :
152 : 26 : aResult.pPopupMenu = pCurrMenu;
153 : 26 : aResult.nPos = nPos;
154 : 26 : aResult.nLevel = nLevel;
155 : 26 : aResult.eResult = eResult;
156 : :
157 : 26 : return aResult;
158 : : }
159 : :
160 : 52 : sal_uInt16 MenuBarMerger::FindMenuItem( const ::rtl::OUString& rCmd, Menu* pCurrMenu )
161 : : {
162 [ + - ]: 312 : for ( sal_uInt16 i = 0; i < pCurrMenu->GetItemCount(); i++ )
163 : : {
164 : 312 : const sal_uInt16 nItemId = pCurrMenu->GetItemId( i );
165 [ + + ]: 312 : if ( nItemId > 0 )
166 : : {
167 [ + + ]: 286 : if ( rCmd == ::rtl::OUString( pCurrMenu->GetItemCommand( nItemId )))
168 : 52 : return i;
169 : : }
170 : : }
171 : :
172 : 52 : return MENU_ITEM_NOTFOUND;
173 : : }
174 : :
175 : 0 : bool MenuBarMerger::CreateSubMenu(
176 : : Menu* pSubMenu,
177 : : sal_uInt16& nItemId,
178 : : const ::rtl::OUString& rModuleIdentifier,
179 : : const AddonMenuContainer& rAddonSubMenu )
180 : : {
181 : 0 : const sal_uInt32 nSize = rAddonSubMenu.size();
182 [ # # ]: 0 : for ( sal_uInt32 i = 0; i < nSize; i++ )
183 : : {
184 : 0 : const AddonMenuItem& rMenuItem = rAddonSubMenu[i];
185 : :
186 [ # # ]: 0 : if ( IsCorrectContext( rMenuItem.aContext, rModuleIdentifier ))
187 : : {
188 [ # # ]: 0 : if ( rMenuItem.aURL.equalsAsciiL( SEPARATOR_STRING, SEPARATOR_STRING_LEN ))
189 : : {
190 : 0 : pSubMenu->InsertSeparator( MENU_APPEND );
191 : : }
192 : : else
193 : : {
194 [ # # ]: 0 : pSubMenu->InsertItem( nItemId, rMenuItem.aTitle, 0, MENU_APPEND );
195 [ # # ]: 0 : pSubMenu->SetItemCommand( nItemId, rMenuItem.aURL );
196 [ # # ]: 0 : if ( !rMenuItem.aSubMenu.empty() )
197 : : {
198 [ # # ]: 0 : PopupMenu* pPopupMenu = new PopupMenu();
199 : 0 : pSubMenu->SetPopupMenu( nItemId, pPopupMenu );
200 : 0 : ++nItemId;
201 : :
202 : 0 : CreateSubMenu( pPopupMenu, nItemId, rModuleIdentifier, rMenuItem.aSubMenu );
203 : : }
204 : : else
205 : 0 : ++nItemId;
206 : : }
207 : : }
208 : : }
209 : :
210 : 0 : return true;
211 : : }
212 : :
213 : 26 : bool MenuBarMerger::MergeMenuItems(
214 : : Menu* pMenu,
215 : : sal_uInt16 nPos,
216 : : sal_uInt16 nModIndex,
217 : : sal_uInt16& nItemId,
218 : : const ::rtl::OUString& rModuleIdentifier,
219 : : const AddonMenuContainer& rAddonMenuItems )
220 : : {
221 : 26 : sal_uInt16 nIndex( 0 );
222 : 26 : const sal_uInt32 nSize = rAddonMenuItems.size();
223 [ + + ]: 78 : for ( sal_uInt32 i = 0; i < nSize; i++ )
224 : : {
225 : 52 : const AddonMenuItem& rMenuItem = rAddonMenuItems[i];
226 : :
227 [ + - ]: 52 : if ( IsCorrectContext( rMenuItem.aContext, rModuleIdentifier ))
228 : : {
229 [ + + ]: 52 : if ( rMenuItem.aURL.equalsAsciiL( SEPARATOR_STRING, SEPARATOR_STRING_LEN ))
230 : : {
231 : 26 : pMenu->InsertSeparator( nPos+nModIndex+nIndex );
232 : : }
233 : : else
234 : : {
235 [ + - ]: 26 : pMenu->InsertItem( nItemId, rMenuItem.aTitle, 0, nPos+nModIndex+nIndex );
236 [ + - ]: 26 : pMenu->SetItemCommand( nItemId, rMenuItem.aURL );
237 [ - + ]: 26 : if ( !rMenuItem.aSubMenu.empty() )
238 : : {
239 [ # # ]: 0 : PopupMenu* pSubMenu = new PopupMenu();
240 : 0 : pMenu->SetPopupMenu( nItemId, pSubMenu );
241 : 0 : ++nItemId;
242 : :
243 : 0 : CreateSubMenu( pSubMenu, nItemId, rModuleIdentifier, rMenuItem.aSubMenu );
244 : : }
245 : : else
246 : 26 : ++nItemId;
247 : : }
248 : 52 : ++nIndex;
249 : : }
250 : : }
251 : :
252 : 26 : return true;
253 : : }
254 : :
255 : 0 : bool MenuBarMerger::ReplaceMenuItem(
256 : : Menu* pMenu,
257 : : sal_uInt16 nPos,
258 : : sal_uInt16& rItemId,
259 : : const ::rtl::OUString& rModuleIdentifier,
260 : : const AddonMenuContainer& rAddonMenuItems )
261 : : {
262 : : // There is no replace available. Therfore we first have to
263 : : // remove the old menu entry,
264 : 0 : pMenu->RemoveItem( nPos );
265 : :
266 : 0 : return MergeMenuItems( pMenu, nPos, 0, rItemId, rModuleIdentifier, rAddonMenuItems );
267 : : }
268 : :
269 : 0 : bool MenuBarMerger::RemoveMenuItems(
270 : : Menu* pMenu,
271 : : sal_uInt16 nPos,
272 : : const ::rtl::OUString& rMergeCommandParameter )
273 : : {
274 : 0 : const sal_uInt16 nParam( sal_uInt16( rMergeCommandParameter.toInt32() ));
275 : 0 : sal_uInt16 nCount( 1 );
276 : :
277 [ # # ]: 0 : nCount = std::max( nParam, nCount );
278 : :
279 : 0 : sal_uInt16 i = 0;
280 [ # # ][ # # ]: 0 : while (( nPos < pMenu->GetItemCount() ) && ( i < nCount ))
[ # # ][ # # ]
281 : : {
282 [ # # ]: 0 : pMenu->RemoveItem( nPos );
283 : 0 : ++i;
284 : : }
285 : :
286 : 0 : return true;
287 : : }
288 : :
289 : 26 : bool MenuBarMerger::ProcessMergeOperation(
290 : : Menu* pMenu,
291 : : sal_uInt16 nPos,
292 : : sal_uInt16& nItemId,
293 : : const ::rtl::OUString& rMergeCommand,
294 : : const ::rtl::OUString& rMergeCommandParameter,
295 : : const ::rtl::OUString& rModuleIdentifier,
296 : : const AddonMenuContainer& rAddonMenuItems )
297 : : {
298 : 26 : sal_uInt16 nModIndex( 0 );
299 : :
300 [ - + ]: 26 : if ( rMergeCommand.equalsAsciiL( MERGECOMMAND_ADDBEFORE, MERGECOMMAND_ADDBEFORE_LEN ))
301 : : {
302 : 0 : nModIndex = 0;
303 : 0 : return MergeMenuItems( pMenu, nPos, nModIndex, nItemId, rModuleIdentifier, rAddonMenuItems );
304 : : }
305 [ + - ]: 26 : else if ( rMergeCommand.equalsAsciiL( MERGECOMMAND_ADDAFTER, MERGECOMMAND_ADDAFTER_LEN ))
306 : : {
307 : 26 : nModIndex = 1;
308 : 26 : return MergeMenuItems( pMenu, nPos, nModIndex, nItemId, rModuleIdentifier, rAddonMenuItems );
309 : : }
310 [ # # ]: 0 : else if ( rMergeCommand.equalsAsciiL( MERGECOMMAND_REPLACE, MERGECOMMAND_REPLACE_LEN ))
311 : : {
312 : 0 : return ReplaceMenuItem( pMenu, nPos, nItemId, rModuleIdentifier, rAddonMenuItems );
313 : : }
314 [ # # ]: 0 : else if ( rMergeCommand.equalsAsciiL( MERGECOMMAND_REMOVE, MERGECOMMAND_REMOVE_LEN ))
315 : : {
316 : 0 : return RemoveMenuItems( pMenu, nPos, rMergeCommandParameter );
317 : : }
318 : :
319 : 26 : return false;
320 : : }
321 : :
322 : 0 : bool MenuBarMerger::ProcessFallbackOperation(
323 : : const ReferencePathInfo& aRefPathInfo,
324 : : sal_uInt16& rItemId,
325 : : const ::rtl::OUString& rMergeCommand,
326 : : const ::rtl::OUString& rMergeFallback,
327 : : const ::std::vector< ::rtl::OUString >& rReferencePath,
328 : : const ::rtl::OUString& rModuleIdentifier,
329 : : const AddonMenuContainer& rAddonMenuItems )
330 : : {
331 [ # # # # : 0 : if (( rMergeFallback.equalsAsciiL( MERGEFALLBACK_IGNORE, MERGEFALLBACK_IGNORE_LEN )) ||
# # ][ # # ]
332 : 0 : ( rMergeCommand.equalsAsciiL( MERGECOMMAND_REPLACE, MERGECOMMAND_REPLACE_LEN )) ||
333 : 0 : ( rMergeCommand.equalsAsciiL( MERGECOMMAND_REMOVE, MERGECOMMAND_REMOVE_LEN )) )
334 : : {
335 : 0 : return true;
336 : : }
337 [ # # ]: 0 : else if ( rMergeFallback.equalsAsciiL( MERGEFALLBACK_ADDPATH, MERGEFALLBACK_ADDPATH_LEN ))
338 : : {
339 : 0 : Menu* pCurrMenu( aRefPathInfo.pPopupMenu );
340 : 0 : sal_Int32 nLevel( aRefPathInfo.nLevel );
341 : 0 : const sal_Int32 nSize( rReferencePath.size() );
342 : 0 : bool bFirstLevel( true );
343 : :
344 [ # # ]: 0 : while ( nLevel < nSize )
345 : : {
346 [ # # ]: 0 : if ( nLevel == nSize-1 )
347 : : {
348 : 0 : const sal_uInt32 nCount = rAddonMenuItems.size();
349 [ # # ]: 0 : for ( sal_uInt32 i = 0; i < nCount; ++i )
350 : : {
351 : 0 : const AddonMenuItem& rMenuItem = rAddonMenuItems[i];
352 [ # # ]: 0 : if ( IsCorrectContext( rMenuItem.aContext, rModuleIdentifier ))
353 : : {
354 [ # # ]: 0 : if ( rMenuItem.aURL.equalsAsciiL( SEPARATOR_STRING, SEPARATOR_STRING_LEN ))
355 : 0 : pCurrMenu->InsertSeparator( MENU_APPEND );
356 : : else
357 : : {
358 [ # # ]: 0 : pCurrMenu->InsertItem( rItemId, rMenuItem.aTitle, 0, MENU_APPEND );
359 [ # # ]: 0 : pCurrMenu->SetItemCommand( rItemId, rMenuItem.aURL );
360 : 0 : ++rItemId;
361 : : }
362 : : }
363 : : }
364 : : }
365 : : else
366 : : {
367 : 0 : const ::rtl::OUString aCmd( rReferencePath[nLevel] );
368 : :
369 : 0 : sal_uInt16 nInsPos( MENU_APPEND );
370 [ # # ][ # # ]: 0 : PopupMenu* pPopupMenu( new PopupMenu );
371 : :
372 [ # # ][ # # ]: 0 : if ( bFirstLevel && ( aRefPathInfo.eResult == RP_MENUITEM_INSTEAD_OF_POPUPMENU_FOUND ))
373 : : {
374 : : // special case: menu item without popup
375 : 0 : nInsPos = aRefPathInfo.nPos;
376 [ # # ]: 0 : sal_uInt16 nSetItemId = pCurrMenu->GetItemId( nInsPos );
377 [ # # ][ # # ]: 0 : pCurrMenu->SetItemCommand( nSetItemId, aCmd );
[ # # ]
378 [ # # ]: 0 : pCurrMenu->SetPopupMenu( nSetItemId, pPopupMenu );
379 : : }
380 : : else
381 : : {
382 : : // normal case: insert a new item with popup
383 [ # # ][ # # ]: 0 : pCurrMenu->InsertItem( rItemId, ::rtl::OUString(), 0, MENU_APPEND );
[ # # ]
384 [ # # ][ # # ]: 0 : pCurrMenu->SetItemCommand( rItemId, aCmd );
[ # # ]
385 [ # # ]: 0 : pCurrMenu->SetPopupMenu( rItemId, pPopupMenu );
386 : : }
387 : :
388 : 0 : pCurrMenu = pPopupMenu;
389 : 0 : ++rItemId;
390 : 0 : bFirstLevel = false;
391 : : }
392 : 0 : ++nLevel;
393 : : }
394 : 0 : return true;
395 : : }
396 : :
397 : 0 : return false;
398 : : }
399 : :
400 : 52 : void MenuBarMerger::GetMenuEntry(
401 : : const uno::Sequence< beans::PropertyValue >& rAddonMenuEntry,
402 : : AddonMenuItem& rAddonMenuItem )
403 : : {
404 : : // Reset submenu member
405 : 52 : rAddonMenuItem.aSubMenu.clear();
406 : :
407 [ + + ]: 364 : for ( sal_Int32 i = 0; i < rAddonMenuEntry.getLength(); i++ )
408 : : {
409 : 312 : ::rtl::OUString aMenuEntryPropName = rAddonMenuEntry[i].Name;
410 [ + + ]: 312 : if ( aMenuEntryPropName.equalsAsciiL( ADDONSMENUITEM_STRING_URL, ADDONSMENUITEM_URL_LEN ))
411 : 52 : rAddonMenuEntry[i].Value >>= rAddonMenuItem.aURL;
412 [ + + ]: 260 : else if ( aMenuEntryPropName.equalsAsciiL( ADDONSMENUITEM_STRING_TITLE, ADDONSMENUITEM_TITLE_LEN ))
413 : 52 : rAddonMenuEntry[i].Value >>= rAddonMenuItem.aTitle;
414 [ + + ]: 208 : else if ( aMenuEntryPropName.equalsAsciiL( ADDONSMENUITEM_STRING_TARGET, ADDONSMENUITEM_TARGET_LEN ))
415 : 52 : rAddonMenuEntry[i].Value >>= rAddonMenuItem.aTarget;
416 [ + + ]: 156 : else if ( aMenuEntryPropName.equalsAsciiL( ADDONSMENUITEM_STRING_SUBMENU, ADDONSMENUITEM_SUBMENU_LEN ))
417 : : {
418 [ + - ]: 52 : uno::Sequence< uno::Sequence< beans::PropertyValue > > aSubMenu;
419 [ + - ]: 52 : rAddonMenuEntry[i].Value >>= aSubMenu;
420 [ + - ][ + - ]: 52 : GetSubMenu( aSubMenu, rAddonMenuItem.aSubMenu );
421 : : }
422 [ + + ]: 104 : else if ( aMenuEntryPropName.equalsAsciiL( ADDONSMENUITEM_STRING_CONTEXT, ADDONSMENUITEM_CONTEXT_LEN ))
423 : 52 : rAddonMenuEntry[i].Value >>= rAddonMenuItem.aContext;
424 [ + - ]: 52 : else if ( aMenuEntryPropName.equalsAsciiL( ADDONSMENUITEM_STRING_IMAGEIDENTIFIER, ADDONSMENUITEM_IMAGEIDENTIFIER_LEN ))
425 : 52 : rAddonMenuEntry[i].Value >>= rAddonMenuItem.aImageId;
426 : 312 : }
427 : 52 : }
428 : :
429 : 78 : void MenuBarMerger::GetSubMenu(
430 : : const uno::Sequence< uno::Sequence< beans::PropertyValue > >& rSubMenuEntries,
431 : : AddonMenuContainer& rSubMenu )
432 : : {
433 : 78 : rSubMenu.clear();
434 : :
435 : 78 : const sal_Int32 nCount = rSubMenuEntries.getLength();
436 : 78 : rSubMenu.reserve(rSubMenu.size() + nCount);
437 [ + + ]: 130 : for ( sal_Int32 i = 0; i < nCount; i++ )
438 : : {
439 : 52 : const uno::Sequence< beans::PropertyValue >& rMenuEntry = rSubMenuEntries[ i ];
440 : :
441 [ + - ]: 52 : AddonMenuItem aMenuItem;
442 [ + - ]: 52 : GetMenuEntry( rMenuEntry, aMenuItem );
443 [ + - ]: 52 : rSubMenu.push_back( aMenuItem );
444 : 52 : }
445 : 78 : }
446 : :
447 : : } // namespace framework
448 : :
449 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|