1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <uielement/menubarmerger.hxx>
21 #include <framework/addonsoptions.hxx>
23 using namespace ::com::sun::star
;
25 static const char SEPARATOR_STRING
[] = "private:separator";
27 static const char MERGECOMMAND_ADDAFTER
[] = "AddAfter";
28 static const char MERGECOMMAND_ADDBEFORE
[] = "AddBefore";
29 static const char MERGECOMMAND_REPLACE
[] = "Replace";
30 static const char MERGECOMMAND_REMOVE
[] = "Remove";
32 static const char MERGEFALLBACK_ADDPATH
[] = "AddPath";
33 static const char MERGEFALLBACK_IGNORE
[] = "Ignore";
39 Check whether a module identifier is part of a context
40 defined by a colon separated list of module identifier.
45 Describes a context string list where all contexts
46 are delimited by a colon. For more information about
47 the module identifier used as context strings see the
48 IDL description of com::sun::star::frame::XModuleManager
53 A string describing a module identifier. See IDL
54 description of com::sun::star::frame::XModuleManager.
57 bool MenuBarMerger::IsCorrectContext( const OUString
& rContext
, const OUString
& rModuleIdentifier
)
59 return ( rContext
.isEmpty() || ( rContext
.indexOf( rModuleIdentifier
) >= 0 ));
62 void MenuBarMerger::RetrieveReferencePath(
63 const OUString
& rReferencePathString
,
64 ::std::vector
< OUString
>& rReferencePath
)
66 const sal_Char aDelimiter
= '\\';
68 rReferencePath
.clear();
69 sal_Int32
nIndex( 0 );
72 OUString aToken
= rReferencePathString
.getToken( 0, aDelimiter
, nIndex
);
73 if ( !aToken
.isEmpty() )
74 rReferencePath
.push_back( aToken
);
76 while ( nIndex
>= 0 );
79 ReferencePathInfo
MenuBarMerger::FindReferencePath(
80 const ::std::vector
< OUString
>& rReferencePath
,
84 const sal_uInt32
nCount( rReferencePath
.size() );
86 ReferencePathInfo aResult
;
89 aResult
.pPopupMenu
= NULL
;
92 aResult
.eResult
= RP_MENUITEM_NOT_FOUND
;
96 Menu
* pCurrMenu( pMenu
);
97 RPResultInfo
eResult( RP_OK
);
99 sal_Int32
nLevel( - 1 );
100 sal_uInt16
nPos( MENU_ITEM_NOTFOUND
);
104 OUString
aCmd( rReferencePath
[i
] );
108 // Check last reference path element. Must be a leave (menu item).
109 sal_uInt16 nTmpPos
= FindMenuItem( aCmd
, pCurrMenu
);
110 if ( nTmpPos
!= MENU_ITEM_NOTFOUND
)
112 eResult
= ( nTmpPos
!= MENU_ITEM_NOTFOUND
) ? RP_OK
: RP_MENUITEM_NOT_FOUND
;
116 // Check reference path element. Must be a node (popup menu)!
117 sal_uInt16 nTmpPos
= FindMenuItem( aCmd
, pCurrMenu
);
118 if ( nTmpPos
!= MENU_ITEM_NOTFOUND
)
120 sal_uInt16 nItemId
= pCurrMenu
->GetItemId( nTmpPos
);
121 Menu
* pTmpMenu
= pCurrMenu
->GetPopupMenu( nItemId
);
123 pCurrMenu
= pTmpMenu
;
127 eResult
= RP_MENUITEM_INSTEAD_OF_POPUPMENU_FOUND
;
131 eResult
= RP_POPUPMENU_NOT_FOUND
;
135 while ((i
< nCount
) && (eResult
== RP_OK
));
137 aResult
.pPopupMenu
= pCurrMenu
;
139 aResult
.nLevel
= nLevel
;
140 aResult
.eResult
= eResult
;
145 sal_uInt16
MenuBarMerger::FindMenuItem( const OUString
& rCmd
, Menu
* pCurrMenu
)
147 for ( sal_uInt16 i
= 0; i
< pCurrMenu
->GetItemCount(); i
++ )
149 const sal_uInt16 nItemId
= pCurrMenu
->GetItemId( i
);
152 if ( rCmd
== pCurrMenu
->GetItemCommand( nItemId
) )
157 return MENU_ITEM_NOTFOUND
;
160 bool MenuBarMerger::CreateSubMenu(
163 const OUString
& rModuleIdentifier
,
164 const AddonMenuContainer
& rAddonSubMenu
)
166 const sal_uInt32 nSize
= rAddonSubMenu
.size();
167 for ( sal_uInt32 i
= 0; i
< nSize
; i
++ )
169 const AddonMenuItem
& rMenuItem
= rAddonSubMenu
[i
];
171 if ( IsCorrectContext( rMenuItem
.aContext
, rModuleIdentifier
))
173 if ( rMenuItem
.aURL
== SEPARATOR_STRING
)
175 pSubMenu
->InsertSeparator();
179 pSubMenu
->InsertItem(nItemId
, rMenuItem
.aTitle
);
180 pSubMenu
->SetItemCommand( nItemId
, rMenuItem
.aURL
);
181 if ( !rMenuItem
.aSubMenu
.empty() )
183 PopupMenu
* pPopupMenu
= new PopupMenu();
184 pSubMenu
->SetPopupMenu( nItemId
, pPopupMenu
);
187 CreateSubMenu( pPopupMenu
, nItemId
, rModuleIdentifier
, rMenuItem
.aSubMenu
);
198 bool MenuBarMerger::MergeMenuItems(
201 sal_uInt16 nModIndex
,
203 const OUString
& rModuleIdentifier
,
204 const AddonMenuContainer
& rAddonMenuItems
)
206 sal_uInt16
nIndex( 0 );
207 const sal_uInt32 nSize
= rAddonMenuItems
.size();
208 for ( sal_uInt32 i
= 0; i
< nSize
; i
++ )
210 const AddonMenuItem
& rMenuItem
= rAddonMenuItems
[i
];
212 if ( IsCorrectContext( rMenuItem
.aContext
, rModuleIdentifier
))
214 if ( rMenuItem
.aURL
== SEPARATOR_STRING
)
216 pMenu
->InsertSeparator(OString(), nPos
+nModIndex
+nIndex
);
220 pMenu
->InsertItem(nItemId
, rMenuItem
.aTitle
, MenuItemBits::NONE
, OString(), nPos
+nModIndex
+nIndex
);
221 pMenu
->SetItemCommand( nItemId
, rMenuItem
.aURL
);
222 if ( !rMenuItem
.aSubMenu
.empty() )
224 PopupMenu
* pSubMenu
= new PopupMenu();
225 pMenu
->SetPopupMenu( nItemId
, pSubMenu
);
228 CreateSubMenu( pSubMenu
, nItemId
, rModuleIdentifier
, rMenuItem
.aSubMenu
);
240 bool MenuBarMerger::ReplaceMenuItem(
244 const OUString
& rModuleIdentifier
,
245 const AddonMenuContainer
& rAddonMenuItems
)
247 // There is no replace available. Therfore we first have to
248 // remove the old menu entry,
249 pMenu
->RemoveItem( nPos
);
251 return MergeMenuItems( pMenu
, nPos
, 0, rItemId
, rModuleIdentifier
, rAddonMenuItems
);
254 bool MenuBarMerger::RemoveMenuItems(
257 const OUString
& rMergeCommandParameter
)
259 const sal_uInt16
nParam( sal_uInt16( rMergeCommandParameter
.toInt32() ));
260 sal_uInt16
nCount( 1 );
262 nCount
= std::max( nParam
, nCount
);
265 while (( nPos
< pMenu
->GetItemCount() ) && ( i
< nCount
))
267 pMenu
->RemoveItem( nPos
);
274 bool MenuBarMerger::ProcessMergeOperation(
278 const OUString
& rMergeCommand
,
279 const OUString
& rMergeCommandParameter
,
280 const OUString
& rModuleIdentifier
,
281 const AddonMenuContainer
& rAddonMenuItems
)
283 sal_uInt16
nModIndex( 0 );
285 if ( rMergeCommand
== MERGECOMMAND_ADDBEFORE
)
288 return MergeMenuItems( pMenu
, nPos
, nModIndex
, nItemId
, rModuleIdentifier
, rAddonMenuItems
);
290 else if ( rMergeCommand
== MERGECOMMAND_ADDAFTER
)
293 return MergeMenuItems( pMenu
, nPos
, nModIndex
, nItemId
, rModuleIdentifier
, rAddonMenuItems
);
295 else if ( rMergeCommand
== MERGECOMMAND_REPLACE
)
297 return ReplaceMenuItem( pMenu
, nPos
, nItemId
, rModuleIdentifier
, rAddonMenuItems
);
299 else if ( rMergeCommand
== MERGECOMMAND_REMOVE
)
301 return RemoveMenuItems( pMenu
, nPos
, rMergeCommandParameter
);
307 bool MenuBarMerger::ProcessFallbackOperation(
308 const ReferencePathInfo
& aRefPathInfo
,
310 const OUString
& rMergeCommand
,
311 const OUString
& rMergeFallback
,
312 const ::std::vector
< OUString
>& rReferencePath
,
313 const OUString
& rModuleIdentifier
,
314 const AddonMenuContainer
& rAddonMenuItems
)
316 if (( rMergeFallback
== MERGEFALLBACK_IGNORE
) ||
317 ( rMergeCommand
== MERGECOMMAND_REPLACE
) ||
318 ( rMergeCommand
== MERGECOMMAND_REMOVE
) )
322 else if ( rMergeFallback
== MERGEFALLBACK_ADDPATH
)
324 Menu
* pCurrMenu( aRefPathInfo
.pPopupMenu
);
325 sal_Int32
nLevel( aRefPathInfo
.nLevel
);
326 const sal_Int32
nSize( rReferencePath
.size() );
327 bool bFirstLevel( true );
329 while ( nLevel
< nSize
)
331 if ( nLevel
== nSize
-1 )
333 const sal_uInt32 nCount
= rAddonMenuItems
.size();
334 for ( sal_uInt32 i
= 0; i
< nCount
; ++i
)
336 const AddonMenuItem
& rMenuItem
= rAddonMenuItems
[i
];
337 if ( IsCorrectContext( rMenuItem
.aContext
, rModuleIdentifier
))
339 if ( rMenuItem
.aURL
== SEPARATOR_STRING
)
340 pCurrMenu
->InsertSeparator(OString(), MENU_APPEND
);
343 pCurrMenu
->InsertItem(rItemId
, rMenuItem
.aTitle
);
344 pCurrMenu
->SetItemCommand( rItemId
, rMenuItem
.aURL
);
352 const OUString
aCmd( rReferencePath
[nLevel
] );
354 sal_uInt16
nInsPos( MENU_APPEND
);
355 PopupMenu
* pPopupMenu( new PopupMenu
);
357 if ( bFirstLevel
&& ( aRefPathInfo
.eResult
== RP_MENUITEM_INSTEAD_OF_POPUPMENU_FOUND
))
359 // special case: menu item without popup
360 nInsPos
= aRefPathInfo
.nPos
;
361 sal_uInt16 nSetItemId
= pCurrMenu
->GetItemId( nInsPos
);
362 pCurrMenu
->SetItemCommand( nSetItemId
, aCmd
);
363 pCurrMenu
->SetPopupMenu( nSetItemId
, pPopupMenu
);
367 // normal case: insert a new item with popup
368 pCurrMenu
->InsertItem(rItemId
, OUString());
369 pCurrMenu
->SetItemCommand( rItemId
, aCmd
);
370 pCurrMenu
->SetPopupMenu( rItemId
, pPopupMenu
);
373 pCurrMenu
= pPopupMenu
;
385 void MenuBarMerger::GetMenuEntry(
386 const uno::Sequence
< beans::PropertyValue
>& rAddonMenuEntry
,
387 AddonMenuItem
& rAddonMenuItem
)
389 // Reset submenu member
390 rAddonMenuItem
.aSubMenu
.clear();
392 for ( sal_Int32 i
= 0; i
< rAddonMenuEntry
.getLength(); i
++ )
394 OUString aMenuEntryPropName
= rAddonMenuEntry
[i
].Name
;
395 if ( aMenuEntryPropName
== ADDONSMENUITEM_STRING_URL
)
396 rAddonMenuEntry
[i
].Value
>>= rAddonMenuItem
.aURL
;
397 else if ( aMenuEntryPropName
== ADDONSMENUITEM_STRING_TITLE
)
398 rAddonMenuEntry
[i
].Value
>>= rAddonMenuItem
.aTitle
;
399 else if ( aMenuEntryPropName
== ADDONSMENUITEM_STRING_TARGET
)
400 rAddonMenuEntry
[i
].Value
>>= rAddonMenuItem
.aTarget
;
401 else if ( aMenuEntryPropName
== ADDONSMENUITEM_STRING_SUBMENU
)
403 uno::Sequence
< uno::Sequence
< beans::PropertyValue
> > aSubMenu
;
404 rAddonMenuEntry
[i
].Value
>>= aSubMenu
;
405 GetSubMenu( aSubMenu
, rAddonMenuItem
.aSubMenu
);
407 else if ( aMenuEntryPropName
== ADDONSMENUITEM_STRING_CONTEXT
)
408 rAddonMenuEntry
[i
].Value
>>= rAddonMenuItem
.aContext
;
409 else if ( aMenuEntryPropName
== ADDONSMENUITEM_STRING_IMAGEIDENTIFIER
)
410 rAddonMenuEntry
[i
].Value
>>= rAddonMenuItem
.aImageId
;
414 void MenuBarMerger::GetSubMenu(
415 const uno::Sequence
< uno::Sequence
< beans::PropertyValue
> >& rSubMenuEntries
,
416 AddonMenuContainer
& rSubMenu
)
420 const sal_Int32 nCount
= rSubMenuEntries
.getLength();
421 rSubMenu
.reserve(rSubMenu
.size() + nCount
);
422 for ( sal_Int32 i
= 0; i
< nCount
; i
++ )
424 const uno::Sequence
< beans::PropertyValue
>& rMenuEntry
= rSubMenuEntries
[ i
];
426 AddonMenuItem aMenuItem
;
427 GetMenuEntry( rMenuEntry
, aMenuItem
);
428 rSubMenu
.push_back( aMenuItem
);
432 } // namespace framework
434 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */