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: menubarmerger.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 #include <uielement/menubarmerger.hxx>
35 #include <classes/addonsoptions.hxx>
37 using namespace ::com::sun::star
;
39 static const char SEPARATOR_STRING
[] = "private:separator";
40 static const sal_uInt32 SEPARATOR_STRING_LEN
= 17;
42 static const char MERGECOMMAND_ADDAFTER
[] = "AddAfter";
43 static const sal_uInt32 MERGECOMMAND_ADDAFTER_LEN
= 8;
44 static const char MERGECOMMAND_ADDBEFORE
[] = "AddBefore";
45 static const sal_uInt32 MERGECOMMAND_ADDBEFORE_LEN
= 9;
46 static const char MERGECOMMAND_REPLACE
[] = "Replace";
47 static const sal_uInt32 MERGECOMMAND_REPLACE_LEN
= 7;
48 static const char MERGECOMMAND_REMOVE
[] = "Remove";
49 static const sal_uInt32 MERGECOMMAND_REMOVE_LEN
= 6;
51 static const char MERGEFALLBACK_ADDPATH
[] = "AddPath";
52 static const char MERGEFALLBACK_ADDPATH_LEN
= 7;
53 static const char MERGEFALLBACK_IGNORE
[] = "Ignore";
54 static const char MERGEFALLBACK_IGNORE_LEN
= 6;
61 Check whether a module identifier is part of a context
62 defined by a colon separated list of module identifier.
67 Describes a context string list where all contexts
68 are delimited by a colon. For more information about
69 the module identifier used as context strings see the
70 IDL description of com::sun::star::frame::XModuleManager
75 A string describing a module identifier. See IDL
76 description of com::sun::star::frame::XModuleManager.
79 bool MenuBarMerger::IsCorrectContext( const ::rtl::OUString
& rContext
, const ::rtl::OUString
& rModuleIdentifier
)
81 return (( rContext
.getLength() == 0 ) || ( rContext
.indexOf( rModuleIdentifier
) >= 0 ));
84 void MenuBarMerger::RetrieveReferencePath(
85 const ::rtl::OUString
& rReferencePathString
,
86 ::std::vector
< ::rtl::OUString
>& rReferencePath
)
88 const sal_Char aDelimiter
= '\\';
90 rReferencePath
.clear();
91 sal_Int32
nIndex( 0 );
94 ::rtl::OUString aToken
= rReferencePathString
.getToken( 0, aDelimiter
, nIndex
);
95 if ( aToken
.getLength() > 0 )
96 rReferencePath
.push_back( aToken
);
98 while ( nIndex
>= 0 );
101 ReferencePathInfo
MenuBarMerger::FindReferencePath(
102 const ::std::vector
< ::rtl::OUString
>& rReferencePath
,
106 const sal_uInt32
nCount( rReferencePath
.size() );
107 Menu
* pCurrMenu( pMenu
);
108 RPResultInfo
eResult( RP_OK
);
110 sal_Int32
nLevel( - 1 );
111 sal_uInt16
nPos( MENU_ITEM_NOTFOUND
);
115 ::rtl::OUString
aCmd( rReferencePath
[i
] );
119 // Check last reference path element. Must be a leave (menu item).
120 sal_uInt16 nTmpPos
= FindMenuItem( aCmd
, pCurrMenu
);
121 if ( nTmpPos
!= MENU_ITEM_NOTFOUND
)
123 eResult
= ( nTmpPos
!= MENU_ITEM_NOTFOUND
) ? RP_OK
: RP_MENUITEM_NOT_FOUND
;
127 // Check reference path element. Must be a node (popup menu)!
128 sal_uInt16 nTmpPos
= FindMenuItem( aCmd
, pCurrMenu
);
129 if ( nTmpPos
!= MENU_ITEM_NOTFOUND
)
131 sal_uInt16 nItemId
= pCurrMenu
->GetItemId( nTmpPos
);
132 Menu
* pTmpMenu
= pCurrMenu
->GetPopupMenu( nItemId
);
134 pCurrMenu
= pTmpMenu
;
138 eResult
= RP_MENUITEM_INSTEAD_OF_POPUPMENU_FOUND
;
142 eResult
= RP_POPUPMENU_NOT_FOUND
;
146 while (( pCurrMenu
!= 0 ) && ( i
< nCount
) && ( eResult
== RP_OK
));
148 ReferencePathInfo aResult
;
149 aResult
.pPopupMenu
= pCurrMenu
;
151 aResult
.nLevel
= nLevel
;
152 aResult
.eResult
= eResult
;
157 sal_uInt16
MenuBarMerger::FindMenuItem( const ::rtl::OUString
& rCmd
, Menu
* pCurrMenu
)
159 for ( sal_uInt16 i
= 0; i
< pCurrMenu
->GetItemCount(); i
++ )
161 const sal_uInt16 nItemId
= pCurrMenu
->GetItemId( i
);
164 if ( rCmd
== ::rtl::OUString( pCurrMenu
->GetItemCommand( nItemId
)))
169 return MENU_ITEM_NOTFOUND
;
172 bool MenuBarMerger::CreateSubMenu(
175 const ::rtl::OUString
& rModuleIdentifier
,
176 const AddonMenuContainer
& rAddonSubMenu
)
178 const sal_uInt32 nSize
= rAddonSubMenu
.size();
179 for ( sal_uInt32 i
= 0; i
< nSize
; i
++ )
181 const AddonMenuItem
& rMenuItem
= rAddonSubMenu
[i
];
183 if ( IsCorrectContext( rMenuItem
.aContext
, rModuleIdentifier
))
185 if ( rMenuItem
.aURL
.equalsAsciiL( SEPARATOR_STRING
, SEPARATOR_STRING_LEN
))
187 pSubMenu
->InsertSeparator( MENU_APPEND
);
191 pSubMenu
->InsertItem( nItemId
, rMenuItem
.aTitle
, 0, MENU_APPEND
);
192 pSubMenu
->SetItemCommand( nItemId
, rMenuItem
.aURL
);
193 if ( !rMenuItem
.aSubMenu
.empty() )
195 PopupMenu
* pPopupMenu
= new PopupMenu();
196 pSubMenu
->SetPopupMenu( nItemId
, pPopupMenu
);
199 CreateSubMenu( pPopupMenu
, nItemId
, rModuleIdentifier
, rMenuItem
.aSubMenu
);
210 bool MenuBarMerger::MergeMenuItems(
213 sal_uInt16 nModIndex
,
215 const ::rtl::OUString
& rModuleIdentifier
,
216 const AddonMenuContainer
& rAddonMenuItems
)
218 sal_uInt16
nIndex( 0 );
219 const sal_uInt32 nSize
= rAddonMenuItems
.size();
220 for ( sal_uInt32 i
= 0; i
< nSize
; i
++ )
222 const AddonMenuItem
& rMenuItem
= rAddonMenuItems
[i
];
224 if ( IsCorrectContext( rMenuItem
.aContext
, rModuleIdentifier
))
226 if ( rMenuItem
.aURL
.equalsAsciiL( SEPARATOR_STRING
, SEPARATOR_STRING_LEN
))
228 pMenu
->InsertSeparator( nPos
+nModIndex
+nIndex
);
232 pMenu
->InsertItem( nItemId
, rMenuItem
.aTitle
, 0, nPos
+nModIndex
+nIndex
);
233 pMenu
->SetItemCommand( nItemId
, rMenuItem
.aURL
);
234 if ( !rMenuItem
.aSubMenu
.empty() )
236 PopupMenu
* pSubMenu
= new PopupMenu();
237 pMenu
->SetPopupMenu( nItemId
, pSubMenu
);
240 CreateSubMenu( pSubMenu
, nItemId
, rModuleIdentifier
, rMenuItem
.aSubMenu
);
252 bool MenuBarMerger::ReplaceMenuItem(
256 const ::rtl::OUString
& rModuleIdentifier
,
257 const AddonMenuContainer
& rAddonMenuItems
)
259 // There is no replace available. Therfore we first have to
260 // remove the old menu entry,
261 pMenu
->RemoveItem( nPos
);
263 return MergeMenuItems( pMenu
, nPos
, 0, rItemId
, rModuleIdentifier
, rAddonMenuItems
);
266 bool MenuBarMerger::RemoveMenuItems(
269 const ::rtl::OUString
& rMergeCommandParameter
)
271 const sal_uInt16
nParam( sal_uInt16( rMergeCommandParameter
.toInt32() ));
272 sal_uInt16
nCount( 1 );
274 nCount
= std::max( nParam
, nCount
);
277 while (( nPos
< pMenu
->GetItemCount() ) && ( i
< nCount
))
279 pMenu
->RemoveItem( nPos
);
286 bool MenuBarMerger::ProcessMergeOperation(
290 const ::rtl::OUString
& rMergeCommand
,
291 const ::rtl::OUString
& rMergeCommandParameter
,
292 const ::rtl::OUString
& rModuleIdentifier
,
293 const AddonMenuContainer
& rAddonMenuItems
)
295 sal_uInt16
nModIndex( 0 );
297 if ( rMergeCommand
.equalsAsciiL( MERGECOMMAND_ADDBEFORE
, MERGECOMMAND_ADDBEFORE_LEN
))
300 return MergeMenuItems( pMenu
, nPos
, nModIndex
, nItemId
, rModuleIdentifier
, rAddonMenuItems
);
302 else if ( rMergeCommand
.equalsAsciiL( MERGECOMMAND_ADDAFTER
, MERGECOMMAND_ADDAFTER_LEN
))
305 return MergeMenuItems( pMenu
, nPos
, nModIndex
, nItemId
, rModuleIdentifier
, rAddonMenuItems
);
307 else if ( rMergeCommand
.equalsAsciiL( MERGECOMMAND_REPLACE
, MERGECOMMAND_REPLACE_LEN
))
309 return ReplaceMenuItem( pMenu
, nPos
, nItemId
, rModuleIdentifier
, rAddonMenuItems
);
311 else if ( rMergeCommand
.equalsAsciiL( MERGECOMMAND_REMOVE
, MERGECOMMAND_REMOVE_LEN
))
313 return RemoveMenuItems( pMenu
, nPos
, rMergeCommandParameter
);
319 bool MenuBarMerger::ProcessFallbackOperation(
320 const ReferencePathInfo
& aRefPathInfo
,
322 const ::rtl::OUString
& rMergeCommand
,
323 const ::rtl::OUString
& rMergeFallback
,
324 const ::std::vector
< ::rtl::OUString
>& rReferencePath
,
325 const ::rtl::OUString
& rModuleIdentifier
,
326 const AddonMenuContainer
& rAddonMenuItems
)
328 if (( rMergeFallback
.equalsAsciiL( MERGEFALLBACK_IGNORE
, MERGEFALLBACK_IGNORE_LEN
)) ||
329 ( rMergeCommand
.equalsAsciiL( MERGECOMMAND_REPLACE
, MERGECOMMAND_REPLACE_LEN
)) ||
330 ( rMergeCommand
.equalsAsciiL( MERGECOMMAND_REMOVE
, MERGECOMMAND_REMOVE_LEN
)) )
334 else if ( rMergeFallback
.equalsAsciiL( MERGEFALLBACK_ADDPATH
, MERGEFALLBACK_ADDPATH_LEN
))
336 Menu
* pCurrMenu( aRefPathInfo
.pPopupMenu
);
337 sal_Int32
nLevel( aRefPathInfo
.nLevel
);
338 const sal_Int32
nSize( rReferencePath
.size() );
339 bool bFirstLevel( true );
341 while ( nLevel
< nSize
)
343 if ( nLevel
== nSize
-1 )
345 const sal_uInt32 nCount
= rAddonMenuItems
.size();
346 for ( sal_uInt32 i
= 0; i
< nCount
; ++i
)
348 const AddonMenuItem
& rMenuItem
= rAddonMenuItems
[i
];
349 if ( IsCorrectContext( rMenuItem
.aContext
, rModuleIdentifier
))
351 if ( rMenuItem
.aURL
.equalsAsciiL( SEPARATOR_STRING
, SEPARATOR_STRING_LEN
))
352 pCurrMenu
->InsertSeparator( MENU_APPEND
);
355 pCurrMenu
->InsertItem( rItemId
, rMenuItem
.aTitle
, 0, MENU_APPEND
);
356 pCurrMenu
->SetItemCommand( rItemId
, rMenuItem
.aURL
);
364 const ::rtl::OUString
aCmd( rReferencePath
[nLevel
] );
366 sal_uInt16
nInsPos( MENU_APPEND
);
367 PopupMenu
* pPopupMenu( new PopupMenu
);
369 if ( bFirstLevel
&& ( aRefPathInfo
.eResult
== RP_MENUITEM_INSTEAD_OF_POPUPMENU_FOUND
))
371 // special case: menu item without popup
372 nInsPos
= aRefPathInfo
.nPos
;
373 sal_uInt16 nSetItemId
= pCurrMenu
->GetItemId( nInsPos
);
374 pCurrMenu
->SetItemCommand( nSetItemId
, aCmd
);
375 pCurrMenu
->SetPopupMenu( nSetItemId
, pPopupMenu
);
379 // normal case: insert a new item with popup
380 pCurrMenu
->InsertItem( rItemId
, ::rtl::OUString(), 0, MENU_APPEND
);
381 pCurrMenu
->SetItemCommand( rItemId
, aCmd
);
382 pCurrMenu
->SetPopupMenu( rItemId
, pPopupMenu
);
385 pCurrMenu
= pPopupMenu
;
397 void MenuBarMerger::GetMenuEntry(
398 const uno::Sequence
< beans::PropertyValue
>& rAddonMenuEntry
,
399 AddonMenuItem
& rAddonMenuItem
)
401 // Reset submenu member
402 rAddonMenuItem
.aSubMenu
.clear();
404 for ( sal_Int32 i
= 0; i
< rAddonMenuEntry
.getLength(); i
++ )
406 ::rtl::OUString aMenuEntryPropName
= rAddonMenuEntry
[i
].Name
;
407 if ( aMenuEntryPropName
.equalsAsciiL( ADDONSMENUITEM_STRING_URL
, ADDONSMENUITEM_URL_LEN
))
408 rAddonMenuEntry
[i
].Value
>>= rAddonMenuItem
.aURL
;
409 else if ( aMenuEntryPropName
.equalsAsciiL( ADDONSMENUITEM_STRING_TITLE
, ADDONSMENUITEM_TITLE_LEN
))
410 rAddonMenuEntry
[i
].Value
>>= rAddonMenuItem
.aTitle
;
411 else if ( aMenuEntryPropName
.equalsAsciiL( ADDONSMENUITEM_STRING_TARGET
, ADDONSMENUITEM_TARGET_LEN
))
412 rAddonMenuEntry
[i
].Value
>>= rAddonMenuItem
.aTarget
;
413 else if ( aMenuEntryPropName
.equalsAsciiL( ADDONSMENUITEM_STRING_SUBMENU
, ADDONSMENUITEM_SUBMENU_LEN
))
415 uno::Sequence
< uno::Sequence
< beans::PropertyValue
> > aSubMenu
;
416 rAddonMenuEntry
[i
].Value
>>= aSubMenu
;
417 GetSubMenu( aSubMenu
, rAddonMenuItem
.aSubMenu
);
419 else if ( aMenuEntryPropName
.equalsAsciiL( ADDONSMENUITEM_STRING_CONTEXT
, ADDONSMENUITEM_CONTEXT_LEN
))
420 rAddonMenuEntry
[i
].Value
>>= rAddonMenuItem
.aContext
;
421 else if ( aMenuEntryPropName
.equalsAsciiL( ADDONSMENUITEM_STRING_IMAGEIDENTIFIER
, ADDONSMENUITEM_IMAGEIDENTIFIER_LEN
))
422 rAddonMenuEntry
[i
].Value
>>= rAddonMenuItem
.aImageId
;
426 void MenuBarMerger::GetSubMenu(
427 const uno::Sequence
< uno::Sequence
< beans::PropertyValue
> >& rSubMenuEntries
,
428 AddonMenuContainer
& rSubMenu
)
432 const sal_Int32 nCount
= rSubMenuEntries
.getLength();
433 rSubMenu
.reserve(rSubMenu
.size() + nCount
);
434 for ( sal_Int32 i
= 0; i
< nCount
; i
++ )
436 const uno::Sequence
< beans::PropertyValue
>& rMenuEntry
= rSubMenuEntries
[ i
];
438 AddonMenuItem aMenuItem
;
439 GetMenuEntry( rMenuEntry
, aMenuItem
);
440 rSubMenu
.push_back( aMenuItem
);
444 } // namespace framework