tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / framework / source / uielement / menubarmerger.cxx
blobdfdebdc7919aecfbbd3445bc08a55ce176e9cfa1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <com/sun/star/uno/Sequence.hxx>
23 #include <o3tl/string_view.hxx>
25 using namespace ::com::sun::star;
27 const char SEPARATOR_STRING[] = "private:separator";
29 const char16_t MERGECOMMAND_ADDAFTER[] = u"AddAfter";
30 const char16_t MERGECOMMAND_ADDBEFORE[] = u"AddBefore";
31 const char16_t MERGECOMMAND_REPLACE[] = u"Replace";
32 const char16_t MERGECOMMAND_REMOVE[] = u"Remove";
34 const char16_t MERGEFALLBACK_ADDPATH[] = u"AddPath";
35 const char16_t MERGEFALLBACK_IGNORE[] = u"Ignore";
37 namespace framework
40 /**
41 Check whether a module identifier is part of a context
42 defined by a colon separated list of module identifier.
44 @param
45 rContext
47 Describes a context string list where all contexts
48 are delimited by a colon. For more information about
49 the module identifier used as context strings see the
50 IDL description of css::frame::XModuleManager
52 @param
53 rModuleIdentifier
55 A string describing a module identifier. See IDL
56 description of css::frame::XModuleManager.
59 bool MenuBarMerger::IsCorrectContext(
60 std::u16string_view rContext, std::u16string_view rModuleIdentifier )
62 return ( rContext.empty() || ( rContext.find( rModuleIdentifier ) != std::u16string_view::npos ));
65 void MenuBarMerger::RetrieveReferencePath(
66 std::u16string_view rReferencePathString,
67 ::std::vector< OUString >& rReferencePath )
69 const char aDelimiter = '\\';
71 rReferencePath.clear();
72 sal_Int32 nIndex( 0 );
75 OUString aToken( o3tl::getToken(rReferencePathString, 0, aDelimiter, nIndex ) );
76 if ( !aToken.isEmpty() )
77 rReferencePath.push_back( aToken );
79 while ( nIndex >= 0 );
82 ReferencePathInfo MenuBarMerger::FindReferencePath(
83 const ::std::vector< OUString >& rReferencePath,
84 Menu* pMenu )
86 sal_uInt32 i( 0 );
87 const sal_uInt32 nCount( rReferencePath.size() );
89 ReferencePathInfo aResult;
90 if ( !nCount )
92 aResult.pPopupMenu = nullptr;
93 aResult.nPos = 0;
94 aResult.nLevel = -1;
95 aResult.eResult = RP_MENUITEM_NOT_FOUND;
96 return aResult;
99 Menu* pCurrMenu( pMenu );
100 RPResultInfo eResult( RP_OK );
102 sal_Int32 nLevel( - 1 );
103 sal_uInt16 nPos( MENU_ITEM_NOTFOUND );
106 ++nLevel;
107 const OUString& aCmd( rReferencePath[i] );
109 if ( i == nCount-1 )
111 // Check last reference path element. Must be a leave (menu item).
112 sal_uInt16 nTmpPos = FindMenuItem( aCmd, pCurrMenu );
113 if ( nTmpPos != MENU_ITEM_NOTFOUND )
114 nPos = nTmpPos;
115 eResult = ( nTmpPos != MENU_ITEM_NOTFOUND ) ? RP_OK : RP_MENUITEM_NOT_FOUND;
117 else
119 // Check reference path element. Must be a node (popup menu)!
120 sal_uInt16 nTmpPos = FindMenuItem( aCmd, pCurrMenu );
121 if ( nTmpPos != MENU_ITEM_NOTFOUND )
123 sal_uInt16 nItemId = pCurrMenu->GetItemId( nTmpPos );
124 Menu* pTmpMenu = pCurrMenu->GetPopupMenu( nItemId );
125 if ( pTmpMenu != nullptr )
126 pCurrMenu = pTmpMenu;
127 else
129 nPos = nTmpPos;
130 eResult = RP_MENUITEM_INSTEAD_OF_POPUPMENU_FOUND;
133 else
134 eResult = RP_POPUPMENU_NOT_FOUND;
136 i++;
138 while ((i < nCount) && (eResult == RP_OK));
140 aResult.pPopupMenu = pCurrMenu;
141 aResult.nPos = nPos;
142 aResult.nLevel = nLevel;
143 aResult.eResult = eResult;
145 return aResult;
148 sal_uInt16 MenuBarMerger::FindMenuItem( std::u16string_view rCmd, Menu const * pCurrMenu )
150 for ( sal_uInt16 i = 0; i < pCurrMenu->GetItemCount(); i++ )
152 const sal_uInt16 nItemId = pCurrMenu->GetItemId( i );
153 if ( nItemId > 0 )
155 if ( rCmd == pCurrMenu->GetItemCommand( nItemId ) )
156 return i;
160 return MENU_ITEM_NOTFOUND;
163 bool MenuBarMerger::CreateSubMenu(
164 Menu* pSubMenu,
165 sal_uInt16& nItemId,
166 const OUString& rModuleIdentifier,
167 const AddonMenuContainer& rAddonSubMenu )
169 const sal_uInt32 nSize = rAddonSubMenu.size();
170 for ( sal_uInt32 i = 0; i < nSize; i++ )
172 const AddonMenuItem& rMenuItem = rAddonSubMenu[i];
174 if ( IsCorrectContext( rMenuItem.aContext, rModuleIdentifier ))
176 if ( rMenuItem.aURL == SEPARATOR_STRING )
178 pSubMenu->InsertSeparator();
180 else
182 pSubMenu->InsertItem(nItemId, rMenuItem.aTitle);
183 pSubMenu->SetItemCommand( nItemId, rMenuItem.aURL );
184 if ( !rMenuItem.aSubMenu.empty() )
186 VclPtr<PopupMenu> pPopupMenu = VclPtr<PopupMenu>::Create();
187 pSubMenu->SetPopupMenu( nItemId, pPopupMenu );
188 ++nItemId;
190 CreateSubMenu( pPopupMenu, nItemId, rModuleIdentifier, rMenuItem.aSubMenu );
192 else
193 ++nItemId;
198 return true;
201 bool MenuBarMerger::MergeMenuItems(
202 Menu* pMenu,
203 sal_uInt16 nPos,
204 sal_uInt16 nModIndex,
205 sal_uInt16& nItemId,
206 const OUString& rModuleIdentifier,
207 const AddonMenuContainer& rAddonMenuItems )
209 sal_uInt16 nIndex( 0 );
210 const sal_uInt32 nSize = rAddonMenuItems.size();
211 for ( sal_uInt32 i = 0; i < nSize; i++ )
213 const AddonMenuItem& rMenuItem = rAddonMenuItems[i];
215 if ( IsCorrectContext( rMenuItem.aContext, rModuleIdentifier ))
217 if ( rMenuItem.aURL == SEPARATOR_STRING )
219 pMenu->InsertSeparator({}, nPos + nModIndex + nIndex);
221 else
223 pMenu->InsertItem(nItemId, rMenuItem.aTitle, MenuItemBits::NONE, {}, nPos + nModIndex + nIndex);
224 pMenu->SetItemCommand( nItemId, rMenuItem.aURL );
225 if ( !rMenuItem.aSubMenu.empty() )
227 VclPtr<PopupMenu> pSubMenu = VclPtr<PopupMenu>::Create();
228 pMenu->SetPopupMenu( nItemId, pSubMenu );
229 ++nItemId;
231 CreateSubMenu( pSubMenu, nItemId, rModuleIdentifier, rMenuItem.aSubMenu );
233 else
234 ++nItemId;
236 ++nIndex;
240 return true;
243 bool MenuBarMerger::ReplaceMenuItem(
244 Menu* pMenu,
245 sal_uInt16 nPos,
246 sal_uInt16& rItemId,
247 const OUString& rModuleIdentifier,
248 const AddonMenuContainer& rAddonMenuItems )
250 // There is no replace available. Therefore we first have to
251 // remove the old menu entry,
252 pMenu->RemoveItem( nPos );
254 return MergeMenuItems( pMenu, nPos, 0, rItemId, rModuleIdentifier, rAddonMenuItems );
257 bool MenuBarMerger::RemoveMenuItems(
258 Menu* pMenu,
259 sal_uInt16 nPos,
260 std::u16string_view rMergeCommandParameter )
262 const sal_uInt16 nParam( sal_uInt16( o3tl::toInt32(rMergeCommandParameter) ));
263 sal_uInt16 nCount = std::max( nParam, sal_uInt16(1) );
265 sal_uInt16 i = 0;
266 while (( nPos < pMenu->GetItemCount() ) && ( i < nCount ))
268 pMenu->RemoveItem( nPos );
269 ++i;
272 return true;
275 bool MenuBarMerger::ProcessMergeOperation(
276 Menu* pMenu,
277 sal_uInt16 nPos,
278 sal_uInt16& nItemId,
279 std::u16string_view rMergeCommand,
280 std::u16string_view rMergeCommandParameter,
281 const OUString& rModuleIdentifier,
282 const AddonMenuContainer& rAddonMenuItems )
284 sal_uInt16 nModIndex( 0 );
286 if ( rMergeCommand == MERGECOMMAND_ADDBEFORE )
288 nModIndex = 0;
289 return MergeMenuItems( pMenu, nPos, nModIndex, nItemId, rModuleIdentifier, rAddonMenuItems );
291 else if ( rMergeCommand == MERGECOMMAND_ADDAFTER )
293 nModIndex = 1;
294 return MergeMenuItems( pMenu, nPos, nModIndex, nItemId, rModuleIdentifier, rAddonMenuItems );
296 else if ( rMergeCommand == MERGECOMMAND_REPLACE )
298 return ReplaceMenuItem( pMenu, nPos, nItemId, rModuleIdentifier, rAddonMenuItems );
300 else if ( rMergeCommand == MERGECOMMAND_REMOVE )
302 return RemoveMenuItems( pMenu, nPos, rMergeCommandParameter );
305 return false;
308 bool MenuBarMerger::ProcessFallbackOperation(
309 const ReferencePathInfo& aRefPathInfo,
310 sal_uInt16& rItemId,
311 std::u16string_view rMergeCommand,
312 std::u16string_view rMergeFallback,
313 const ::std::vector< OUString >& rReferencePath,
314 const std::u16string_view rModuleIdentifier,
315 const AddonMenuContainer& rAddonMenuItems )
317 if (( rMergeFallback == MERGEFALLBACK_IGNORE ) ||
318 ( rMergeCommand == MERGECOMMAND_REPLACE ) ||
319 ( rMergeCommand == MERGECOMMAND_REMOVE ) )
321 return true;
323 else if ( rMergeFallback == MERGEFALLBACK_ADDPATH )
325 Menu* pCurrMenu( aRefPathInfo.pPopupMenu );
326 sal_Int32 nLevel( aRefPathInfo.nLevel );
327 const sal_Int32 nSize( rReferencePath.size() );
328 bool bFirstLevel( true );
330 while ( nLevel < nSize )
332 if ( nLevel == nSize-1 )
334 const sal_uInt32 nCount = rAddonMenuItems.size();
335 for ( sal_uInt32 i = 0; i < nCount; ++i )
337 const AddonMenuItem& rMenuItem = rAddonMenuItems[i];
338 if ( IsCorrectContext( rMenuItem.aContext, rModuleIdentifier ))
340 if ( rMenuItem.aURL == SEPARATOR_STRING )
341 pCurrMenu->InsertSeparator();
342 else
344 pCurrMenu->InsertItem(rItemId, rMenuItem.aTitle);
345 pCurrMenu->SetItemCommand( rItemId, rMenuItem.aURL );
346 ++rItemId;
351 else
353 const OUString& aCmd( rReferencePath[nLevel] );
355 VclPtr<PopupMenu> pPopupMenu = VclPtr<PopupMenu>::Create();
357 if ( bFirstLevel && ( aRefPathInfo.eResult == RP_MENUITEM_INSTEAD_OF_POPUPMENU_FOUND ))
359 // special case: menu item without popup
360 sal_uInt16 nInsPos = aRefPathInfo.nPos;
361 sal_uInt16 nSetItemId = pCurrMenu->GetItemId( nInsPos );
362 pCurrMenu->SetItemCommand( nSetItemId, aCmd );
363 pCurrMenu->SetPopupMenu( nSetItemId, pPopupMenu );
365 else
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;
374 ++rItemId;
375 bFirstLevel = false;
377 ++nLevel;
379 return true;
382 return false;
385 void MenuBarMerger::GetMenuEntry(
386 const uno::Sequence< beans::PropertyValue >& rAddonMenuEntry,
387 AddonMenuItem& rAddonMenuItem )
389 // Reset submenu member
390 rAddonMenuItem.aSubMenu.clear();
392 for ( const beans::PropertyValue& rProp : rAddonMenuEntry )
394 OUString aMenuEntryPropName = rProp.Name;
395 if ( aMenuEntryPropName == ADDONSMENUITEM_STRING_URL )
396 rProp.Value >>= rAddonMenuItem.aURL;
397 else if ( aMenuEntryPropName == ADDONSMENUITEM_STRING_TITLE )
398 rProp.Value >>= rAddonMenuItem.aTitle;
399 else if ( aMenuEntryPropName == ADDONSMENUITEM_STRING_SUBMENU )
401 uno::Sequence< uno::Sequence< beans::PropertyValue > > aSubMenu;
402 rProp.Value >>= aSubMenu;
403 GetSubMenu( aSubMenu, rAddonMenuItem.aSubMenu );
405 else if ( aMenuEntryPropName == ADDONSMENUITEM_STRING_CONTEXT )
406 rProp.Value >>= rAddonMenuItem.aContext;
410 void MenuBarMerger::GetSubMenu(
411 const uno::Sequence< uno::Sequence< beans::PropertyValue > >& rSubMenuEntries,
412 AddonMenuContainer& rSubMenu )
414 rSubMenu.clear();
416 const sal_Int32 nCount = rSubMenuEntries.getLength();
417 rSubMenu.reserve(rSubMenu.size() + nCount);
418 for ( sal_Int32 i = 0; i < nCount; i++ )
420 const uno::Sequence< beans::PropertyValue >& rMenuEntry = rSubMenuEntries[ i ];
422 AddonMenuItem aMenuItem;
423 GetMenuEntry( rMenuEntry, aMenuItem );
424 rSubMenu.push_back( aMenuItem );
428 } // namespace framework
430 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */