Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / framework / source / uielement / menubarmanager.cxx
blobedbd88d2250cc3bce58bf1299b688e870e1dcedc
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/menubarmanager.hxx>
21 #include <uielement/styletoolbarcontroller.hxx>
22 #include <menuconfiguration.hxx>
23 #include <addonmenu.hxx>
24 #include <framework/addonsoptions.hxx>
25 #include <classes/fwkresid.hxx>
26 #include <strings.hrc>
28 #include <com/sun/star/frame/XDispatch.hpp>
29 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
30 #include <com/sun/star/lang/DisposedException.hpp>
31 #include <com/sun/star/uno/XComponentContext.hpp>
32 #include <com/sun/star/uno/XCurrentContext.hpp>
33 #include <com/sun/star/frame/XPopupMenuController.hpp>
34 #include <com/sun/star/frame/thePopupMenuControllerFactory.hpp>
35 #include <com/sun/star/lang/SystemDependent.hpp>
36 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
37 #include <com/sun/star/ui/ItemType.hpp>
38 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
39 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
40 #include <com/sun/star/ui/ItemStyle.hpp>
41 #include <com/sun/star/frame/status/Visibility.hpp>
42 #include <com/sun/star/util/URLTransformer.hpp>
44 #include <comphelper/propertysequence.hxx>
45 #include <comphelper/propertyvalue.hxx>
46 #include <officecfg/Office/Common.hxx>
47 #include <svtools/javainteractionhandler.hxx>
48 #include <uno/current_context.hxx>
49 #include <unotools/cmdoptions.hxx>
50 #include <toolkit/awt/vclxmenu.hxx>
51 #include <utility>
52 #include <vcl/svapp.hxx>
53 #include <vcl/sysdata.hxx>
54 #include <vcl/menu.hxx>
55 #include <vcl/settings.hxx>
56 #include <vcl/commandinfoprovider.hxx>
57 #include <sal/log.hxx>
58 #include <svtools/acceleratorexecute.hxx>
59 #include <svtools/miscopt.hxx>
60 #include <uielement/menubarmerger.hxx>
61 #include <tools/urlobj.hxx>
63 using namespace ::cppu;
64 using namespace ::com::sun::star;
65 using namespace ::com::sun::star::uno;
66 using namespace ::com::sun::star::util;
67 using namespace ::com::sun::star::beans;
68 using namespace ::com::sun::star::frame;
69 using namespace ::com::sun::star::container;
70 using namespace ::com::sun::star::lang;
71 using namespace ::com::sun::star::ui;
73 const sal_uInt16 ADDONMENU_MERGE_ITEMID_START = 1500;
74 const sal_uInt16 ITEMID_ADDONLIST = 6678; // used to be a SID in sfx2, now just a unique id...
76 namespace framework
79 constexpr OUStringLiteral aCmdHelpIndex = u".uno:HelpIndex";
80 constexpr OUStringLiteral aCmdToolsMenu = u".uno:ToolsMenu";
81 constexpr OUStringLiteral aCmdHelpMenu = u".uno:HelpMenu";
82 constexpr OUStringLiteral aSpecialWindowCommand = u".uno:WindowList";
84 MenuBarManager::MenuBarManager(
85 const Reference< XComponentContext >& rxContext,
86 const Reference< XFrame >& rFrame,
87 const Reference< XURLTransformer >& _xURLTransformer,
88 const Reference< XDispatchProvider >& rDispatchProvider,
89 const OUString& rModuleIdentifier,
90 Menu* pMenu, bool bDelete, bool bHasMenuBar ):
91 m_bRetrieveImages( false )
92 , m_bAcceleratorCfg( false )
93 , m_bHasMenuBar( bHasMenuBar )
94 , m_xContext(rxContext)
95 , m_xURLTransformer(_xURLTransformer)
96 , m_sIconTheme( SvtMiscOptions::GetIconTheme() )
97 , m_aAsyncSettingsTimer( "framework::MenuBarManager::Deactivate m_aAsyncSettingsTimer" )
99 m_xPopupMenuControllerFactory = frame::thePopupMenuControllerFactory::get(m_xContext);
100 FillMenuManager( pMenu, rFrame, rDispatchProvider, rModuleIdentifier, bDelete );
103 Any SAL_CALL MenuBarManager::getMenuHandle( const Sequence< sal_Int8 >& /*ProcessId*/, sal_Int16 SystemType )
105 SolarMutexGuard aSolarGuard;
107 if ( m_bDisposed )
108 throw css::lang::DisposedException();
110 Any a;
112 if ( m_pVCLMenu )
114 SystemMenuData aSystemMenuData;
116 m_pVCLMenu->GetSystemMenuData( &aSystemMenuData );
117 #ifdef _WIN32
118 if( SystemType == SystemDependent::SYSTEM_WIN32 )
120 a <<= sal_Int64(
121 reinterpret_cast<sal_IntPtr>(aSystemMenuData.hMenu));
123 #else
124 (void) SystemType;
125 #endif
128 return a;
131 MenuBarManager::~MenuBarManager()
133 // stop asynchronous settings timer
134 m_xDeferredItemContainer.clear();
135 m_aAsyncSettingsTimer.Stop();
137 SAL_WARN_IF( OWeakObject::m_refCount != 0, "fwk.uielement", "Who wants to delete an object with refcount > 0!" );
140 // XComponent
141 void MenuBarManager::disposing(std::unique_lock<std::mutex>& )
143 Reference< XComponent > xThis( this );
145 SolarMutexGuard g;
147 // stop asynchronous settings timer and
148 // release deferred item container reference
149 m_aAsyncSettingsTimer.Stop();
150 m_xDeferredItemContainer.clear();
151 RemoveListener();
153 m_aMenuItemHandlerVector.clear();
155 if ( m_bDeleteMenu )
157 m_pVCLMenu.disposeAndClear();
160 if ( m_xDocImageManager.is() )
164 m_xDocImageManager->removeConfigurationListener(
165 Reference< XUIConfigurationListener >(this) );
167 catch ( const Exception& )
171 if ( m_xModuleImageManager.is() )
175 m_xModuleImageManager->removeConfigurationListener(
176 Reference< XUIConfigurationListener >(this) );
178 catch ( const Exception& )
182 m_xDocImageManager.clear();
183 m_xModuleImageManager.clear();
184 m_xGlobalAcceleratorManager.clear();
185 m_xModuleAcceleratorManager.clear();
186 m_xDocAcceleratorManager.clear();
187 m_xPopupMenuControllerFactory.clear();
188 m_xContext.clear();
191 void SAL_CALL MenuBarManager::elementInserted( const css::ui::ConfigurationEvent& Event )
193 SolarMutexGuard g;
195 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
196 if ( m_bDisposed )
197 return;
199 sal_Int16 nImageType = sal_Int16();
200 if (( Event.aInfo >>= nImageType ) && nImageType == 0 )
201 RequestImages();
204 void SAL_CALL MenuBarManager::elementRemoved( const css::ui::ConfigurationEvent& Event )
206 elementInserted(Event);
209 void SAL_CALL MenuBarManager::elementReplaced( const css::ui::ConfigurationEvent& Event )
211 elementInserted(Event);
214 // XFrameActionListener
215 void SAL_CALL MenuBarManager::frameAction( const FrameActionEvent& Action )
217 SolarMutexGuard g;
219 if ( m_bDisposed )
220 throw css::lang::DisposedException();
222 if ( Action.Action != FrameAction_CONTEXT_CHANGED )
223 return;
225 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
227 // Clear dispatch reference as we will requery it later
228 if ( menuItemHandler->xMenuItemDispatch.is() )
230 URL aTargetURL;
231 aTargetURL.Complete = menuItemHandler->aMenuItemURL;
232 m_xURLTransformer->parseStrict( aTargetURL );
234 menuItemHandler->xMenuItemDispatch->removeStatusListener( this, aTargetURL );
236 menuItemHandler->xMenuItemDispatch.clear();
240 // XStatusListener
241 void SAL_CALL MenuBarManager::statusChanged( const FeatureStateEvent& Event )
243 OUString aFeatureURL = Event.FeatureURL.Complete;
245 SolarMutexGuard aSolarGuard;
247 if ( m_bDisposed )
248 return;
250 // We have to check all menu entries as there can be identical entries in a popup menu.
251 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
253 if ( menuItemHandler->aParsedItemURL == aFeatureURL )
255 bool bCheckmark( false );
256 bool bMenuItemEnabled( m_pVCLMenu->IsItemEnabled( menuItemHandler->nItemId ));
257 bool bEnabledItem( Event.IsEnabled );
258 OUString aItemText;
259 status::Visibility aVisibilityStatus;
261 #ifdef UNIX
262 //enable some slots hardly, because UNIX clipboard does not notify all changes
263 // Can be removed if follow up task will be fixed directly within applications.
264 // Note: PasteSpecial is handled specifically by calc
265 // Calc also disables Paste under some circumstances, do not override.
266 /* TODO: is this workaround even needed anymore? Was introduced
267 * in 2009 with commit 426ab2c0e8f6e3fe2b766f74f6b8da873d860260
268 * as some "metropatch" and the other places it touched seem to
269 * be gone. */
270 if ( (menuItemHandler->aMenuItemURL == ".uno:Paste" &&
271 m_aModuleIdentifier != "com.sun.star.sheet.SpreadsheetDocument")
272 || menuItemHandler->aMenuItemURL == ".uno:PasteClipboard" ) // special for draw/impress
273 bEnabledItem = true;
274 #endif
276 // Enable/disable item
277 if ( bEnabledItem != bMenuItemEnabled )
279 m_pVCLMenu->EnableItem( menuItemHandler->nItemId, bEnabledItem );
281 // Remove "checked" mark for disabled menu items.
282 // Initially disabled but checkable menu items do not receive
283 // checked/unchecked state, so can appear inconsistently after
284 // enabling/disabling. Since we can not pass checked state for disabled
285 // items, we will just reset checked state for them, anyway correct state
286 // will be transferred from controller once item enabled.
287 if ( !bEnabledItem && m_pVCLMenu->IsItemChecked( menuItemHandler->nItemId ) )
288 m_pVCLMenu->CheckItem( menuItemHandler->nItemId, false );
291 if ( Event.State >>= bCheckmark )
293 // Checkmark or RadioButton
294 m_pVCLMenu->CheckItem( menuItemHandler->nItemId, bCheckmark );
295 // If not already designated RadioButton set as CheckMark
296 MenuItemBits nBits = m_pVCLMenu->GetItemBits( menuItemHandler->nItemId );
297 if (!(nBits & MenuItemBits::RADIOCHECK))
298 m_pVCLMenu->SetItemBits( menuItemHandler->nItemId, nBits | MenuItemBits::CHECKABLE );
300 if ( menuItemHandler->bMadeInvisible )
301 m_pVCLMenu->ShowItem( menuItemHandler->nItemId );
303 else if ( Event.State >>= aItemText )
305 INetURLObject aURL( aFeatureURL );
306 OUString aEnumPart = aURL.GetURLPath().getToken( 1, '.' );
307 if ( !aEnumPart.isEmpty() && aURL.GetProtocol() == INetProtocol::Uno )
309 // Checkmark or RadioButton
310 m_pVCLMenu->CheckItem( menuItemHandler->nItemId, aItemText == aEnumPart );
311 // If not already designated RadioButton set as CheckMark
312 MenuItemBits nBits = m_pVCLMenu->GetItemBits( menuItemHandler->nItemId );
313 if (!(nBits & MenuItemBits::RADIOCHECK))
314 m_pVCLMenu->SetItemBits( menuItemHandler->nItemId, nBits | MenuItemBits::CHECKABLE );
316 else
318 // Replacement for place holders
319 if ( aItemText.startsWith("($1)") )
321 aItemText = FwkResId(STR_UPDATEDOC) + " " + aItemText.subView( 4 );
323 else if ( aItemText.startsWith("($2)") )
325 aItemText = FwkResId(STR_CLOSEDOC_ANDRETURN) + aItemText.subView( 4 );
327 else if ( aItemText.startsWith("($3)") )
329 aItemText = FwkResId(STR_SAVECOPYDOC) + aItemText.subView( 4 );
332 m_pVCLMenu->SetItemText( menuItemHandler->nItemId, aItemText );
335 if ( menuItemHandler->bMadeInvisible )
336 m_pVCLMenu->ShowItem( menuItemHandler->nItemId );
338 else if ( Event.State >>= aVisibilityStatus )
340 // Visibility
341 m_pVCLMenu->ShowItem( menuItemHandler->nItemId, aVisibilityStatus.bVisible );
342 menuItemHandler->bMadeInvisible = !aVisibilityStatus.bVisible;
344 else if ( menuItemHandler->bMadeInvisible )
345 m_pVCLMenu->ShowItem( menuItemHandler->nItemId );
348 if ( Event.Requery )
350 // Release dispatch object - will be required on the next activate!
351 menuItemHandler->xMenuItemDispatch.clear();
357 // Helper to retrieve own structure from item ID
358 MenuBarManager::MenuItemHandler* MenuBarManager::GetMenuItemHandler( sal_uInt16 nItemId )
360 SolarMutexGuard g;
362 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
364 if ( menuItemHandler->nItemId == nItemId )
365 return menuItemHandler.get();
368 return nullptr;
371 // Helper to set request images flag
372 void MenuBarManager::RequestImages()
375 m_bRetrieveImages = true;
376 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
378 if ( menuItemHandler->xSubMenuManager.is() )
380 MenuBarManager* pMenuBarManager = static_cast<MenuBarManager*>(menuItemHandler->xSubMenuManager.get());
381 pMenuBarManager->RequestImages();
386 // Helper to reset objects to prepare shutdown
387 void MenuBarManager::RemoveListener()
389 SolarMutexGuard g;
391 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
393 if ( menuItemHandler->xMenuItemDispatch.is() )
395 URL aTargetURL;
396 aTargetURL.Complete = menuItemHandler->aMenuItemURL;
397 m_xURLTransformer->parseStrict( aTargetURL );
399 menuItemHandler->xMenuItemDispatch->removeStatusListener(
400 static_cast< XStatusListener* >( this ), aTargetURL );
403 menuItemHandler->xMenuItemDispatch.clear();
405 if ( menuItemHandler->xPopupMenu.is() )
408 // Remove popup menu from menu structure
409 m_pVCLMenu->SetPopupMenu( menuItemHandler->nItemId, nullptr );
412 Reference< css::lang::XEventListener > xEventListener( menuItemHandler->xPopupMenuController, UNO_QUERY );
413 if ( xEventListener.is() )
415 EventObject aEventObject;
416 aEventObject.Source = static_cast<OWeakObject *>(this);
417 xEventListener->disposing( aEventObject );
420 // We now provide a popup menu controller to external code.
421 // Therefore the life-time must be explicitly handled via
422 // dispose!!
425 Reference< XComponent > xComponent( menuItemHandler->xPopupMenuController, UNO_QUERY );
426 if ( xComponent.is() )
427 xComponent->dispose();
429 catch ( const RuntimeException& )
431 throw;
433 catch ( const Exception& )
437 // Release references to controller and popup menu
438 menuItemHandler->xPopupMenuController.clear();
439 menuItemHandler->xPopupMenu.clear();
442 Reference< XComponent > xComponent( menuItemHandler->xSubMenuManager, UNO_QUERY );
443 if ( xComponent.is() )
444 xComponent->dispose();
449 if ( m_xFrame.is() )
450 m_xFrame->removeFrameActionListener( Reference< XFrameActionListener >(this) );
452 catch ( const Exception& )
456 m_xFrame = nullptr;
459 void SAL_CALL MenuBarManager::disposing( const EventObject& Source )
461 MenuItemHandler* pMenuItemDisposing = nullptr;
463 SolarMutexGuard g;
465 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
467 if ( menuItemHandler->xMenuItemDispatch.is() &&
468 menuItemHandler->xMenuItemDispatch == Source.Source )
470 // disposing called from menu item dispatcher, remove listener
471 pMenuItemDisposing = menuItemHandler.get();
472 break;
476 if ( pMenuItemDisposing )
478 // Release references to the dispatch object
479 URL aTargetURL;
480 aTargetURL.Complete = pMenuItemDisposing->aMenuItemURL;
482 m_xURLTransformer->parseStrict( aTargetURL );
484 pMenuItemDisposing->xMenuItemDispatch->removeStatusListener(
485 static_cast< XStatusListener* >( this ), aTargetURL );
486 pMenuItemDisposing->xMenuItemDispatch.clear();
487 if ( pMenuItemDisposing->xPopupMenu.is() )
489 Reference< css::lang::XEventListener > xEventListener( pMenuItemDisposing->xPopupMenuController, UNO_QUERY );
490 if ( xEventListener.is() )
491 xEventListener->disposing( Source );
494 // Remove popup menu from menu structure as we release our reference to
495 // the controller.
496 m_pVCLMenu->SetPopupMenu( pMenuItemDisposing->nItemId, nullptr );
499 pMenuItemDisposing->xPopupMenuController.clear();
500 pMenuItemDisposing->xPopupMenu.clear();
502 return;
504 else if ( Source.Source == m_xFrame )
506 // Our frame gets disposed. We have to remove all our listeners
507 RemoveListener();
509 else if ( Source.Source == Reference< XInterface >( m_xDocImageManager, UNO_QUERY ))
510 m_xDocImageManager.clear();
511 else if ( Source.Source == Reference< XInterface >( m_xModuleImageManager, UNO_QUERY ))
512 m_xModuleImageManager.clear();
515 static void lcl_CheckForChildren(Menu* pMenu, sal_uInt16 nItemId)
517 if (PopupMenu* pThisPopup = pMenu->GetPopupMenu( nItemId ))
518 pMenu->EnableItem( nItemId, pThisPopup->GetItemCount() != 0 );
521 // vcl handler
523 namespace {
525 class QuietInteractionContext:
526 public cppu::WeakImplHelper< css::uno::XCurrentContext >
528 public:
529 explicit QuietInteractionContext(
530 css::uno::Reference< css::uno::XCurrentContext > context):
531 context_(std::move(context)) {}
532 QuietInteractionContext(const QuietInteractionContext&) = delete;
533 QuietInteractionContext& operator=(const QuietInteractionContext&) = delete;
535 private:
536 virtual ~QuietInteractionContext() override {}
538 virtual css::uno::Any SAL_CALL getValueByName(
539 OUString const & Name) override
541 return Name != JAVA_INTERACTION_HANDLER_NAME && context_.is()
542 ? context_->getValueByName(Name)
543 : css::uno::Any();
546 css::uno::Reference< css::uno::XCurrentContext >
547 context_;
552 IMPL_LINK( MenuBarManager, Activate, Menu *, pMenu, bool )
554 if ( pMenu != m_pVCLMenu )
555 return true;
557 css::uno::ContextLayer layer(
558 new QuietInteractionContext(
559 css::uno::getCurrentContext()));
561 // set/unset hiding disabled menu entries
562 bool bDontHide = officecfg::Office::Common::View::Menu::DontHideDisabledEntry::get();
563 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
564 bool bShowMenuImages = rSettings.GetUseImagesInMenus();
565 bool bShowShortcuts = m_bHasMenuBar || rSettings.GetContextMenuShortcuts();
566 bool bHasDisabledEntries = SvtCommandOptions().HasEntriesDisabled();
568 SolarMutexGuard g;
570 MenuFlags nFlag = pMenu->GetMenuFlags();
571 if ( bDontHide )
572 nFlag &= ~MenuFlags::HideDisabledEntries;
573 else
574 nFlag |= MenuFlags::HideDisabledEntries;
575 pMenu->SetMenuFlags( nFlag );
577 if ( m_bActive )
578 return false;
580 m_bActive = true;
582 // Check if some modes have changed so we have to update our menu images
583 OUString sIconTheme = SvtMiscOptions::GetIconTheme();
585 if ( m_bRetrieveImages ||
586 bShowMenuImages != m_bShowMenuImages ||
587 sIconTheme != m_sIconTheme )
589 m_bShowMenuImages = bShowMenuImages;
590 m_bRetrieveImages = false;
591 m_sIconTheme = sIconTheme;
592 FillMenuImages( m_xFrame, pMenu, bShowMenuImages );
595 // Try to map commands to labels
596 for ( sal_uInt16 nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
598 sal_uInt16 nItemId = pMenu->GetItemId( nPos );
599 if (( pMenu->GetItemType( nPos ) != MenuItemType::SEPARATOR ) &&
600 ( pMenu->GetItemText( nItemId ).isEmpty() ))
602 OUString aCommand = pMenu->GetItemCommand( nItemId );
603 if ( !aCommand.isEmpty() ) {
604 pMenu->SetItemText( nItemId, RetrieveLabelFromCommand( aCommand ));
609 // Try to set accelerator keys
611 if ( bShowShortcuts )
612 RetrieveShortcuts( m_aMenuItemHandlerVector );
614 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
616 if ( !bShowShortcuts )
618 pMenu->SetAccelKey( menuItemHandler->nItemId, vcl::KeyCode() );
620 else if ( menuItemHandler->aMenuItemURL == aCmdHelpIndex )
622 // Set key code, workaround for hard-coded shortcut F1 mapped to .uno:HelpIndex
623 // Only non-popup menu items can have a short-cut
624 vcl::KeyCode aKeyCode( KEY_F1 );
625 pMenu->SetAccelKey( menuItemHandler->nItemId, aKeyCode );
627 else if ( pMenu->GetPopupMenu( menuItemHandler->nItemId ) == nullptr )
628 pMenu->SetAccelKey( menuItemHandler->nItemId, menuItemHandler->aKeyCode );
632 URL aTargetURL;
634 // Use provided dispatch provider => fallback to frame as dispatch provider
635 Reference< XDispatchProvider > xDispatchProvider;
636 if ( m_xDispatchProvider.is() )
637 xDispatchProvider = m_xDispatchProvider;
638 else
639 xDispatchProvider.set( m_xFrame, UNO_QUERY );
641 if ( !xDispatchProvider.is() )
642 return true;
644 SvtCommandOptions aCmdOptions;
645 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
647 if (menuItemHandler)
649 if ( !menuItemHandler->xMenuItemDispatch.is() &&
650 !menuItemHandler->xSubMenuManager.is() )
652 Reference< XDispatch > xMenuItemDispatch;
654 aTargetURL.Complete = menuItemHandler->aMenuItemURL;
656 m_xURLTransformer->parseStrict( aTargetURL );
658 if ( bHasDisabledEntries )
660 if ( aCmdOptions.LookupDisabled( aTargetURL.Path ))
661 pMenu->HideItem( menuItemHandler->nItemId );
664 if ( aTargetURL.Complete.startsWith( ".uno:StyleApply?" ) )
665 xMenuItemDispatch = new StyleDispatcher( m_xFrame, m_xURLTransformer, aTargetURL );
666 else
667 xMenuItemDispatch = xDispatchProvider->queryDispatch( aTargetURL, menuItemHandler->aTargetFrame, 0 );
669 bool bPopupMenu( false );
670 if ( !menuItemHandler->xPopupMenuController.is() &&
671 m_xPopupMenuControllerFactory->hasController( menuItemHandler->aMenuItemURL, m_aModuleIdentifier ) )
673 if( xMenuItemDispatch.is() || menuItemHandler->aMenuItemURL != ".uno:RecentFileList" )
674 bPopupMenu = CreatePopupMenuController(menuItemHandler.get(), m_xDispatchProvider, m_aModuleIdentifier);
676 else if ( menuItemHandler->xPopupMenuController.is() )
678 // Force update of popup menu
679 menuItemHandler->xPopupMenuController->updatePopupMenu();
680 bPopupMenu = true;
681 if (PopupMenu* pThisPopup = pMenu->GetPopupMenu( menuItemHandler->nItemId ))
682 pMenu->EnableItem( menuItemHandler->nItemId, pThisPopup->GetItemCount() != 0 );
684 lcl_CheckForChildren(pMenu, menuItemHandler->nItemId);
686 if ( xMenuItemDispatch.is() )
688 menuItemHandler->xMenuItemDispatch = xMenuItemDispatch;
689 menuItemHandler->aParsedItemURL = aTargetURL.Complete;
691 if ( !bPopupMenu )
693 xMenuItemDispatch->addStatusListener( static_cast< XStatusListener* >( this ), aTargetURL );
694 // For the menubar, we have to keep status listening to support Ubuntu's HUD.
695 if ( !m_bHasMenuBar )
696 xMenuItemDispatch->removeStatusListener( static_cast< XStatusListener* >( this ), aTargetURL );
699 else if ( !bPopupMenu )
700 pMenu->EnableItem( menuItemHandler->nItemId, false );
702 else if ( menuItemHandler->xPopupMenuController.is() )
704 // Force update of popup menu
705 menuItemHandler->xPopupMenuController->updatePopupMenu();
706 lcl_CheckForChildren(pMenu, menuItemHandler->nItemId);
708 else if ( menuItemHandler->xMenuItemDispatch.is() )
710 // We need an update to reflect the current state
713 aTargetURL.Complete = menuItemHandler->aMenuItemURL;
714 m_xURLTransformer->parseStrict( aTargetURL );
716 menuItemHandler->xMenuItemDispatch->addStatusListener(
717 static_cast< XStatusListener* >( this ), aTargetURL );
718 menuItemHandler->xMenuItemDispatch->removeStatusListener(
719 static_cast< XStatusListener* >( this ), aTargetURL );
721 catch ( const Exception& )
725 else if ( menuItemHandler->xSubMenuManager.is() )
726 lcl_CheckForChildren(pMenu, menuItemHandler->nItemId);
730 return true;
733 IMPL_LINK( MenuBarManager, Deactivate, Menu *, pMenu, bool )
735 if ( pMenu == m_pVCLMenu )
737 m_bActive = false;
738 if ( pMenu->IsMenuBar() && m_xDeferredItemContainer.is() )
740 // Start timer to handle settings asynchronous
741 // Changing the menu inside this handler leads to
742 // a crash under X!
743 m_aAsyncSettingsTimer.SetInvokeHandler(LINK(this, MenuBarManager, AsyncSettingsHdl));
744 m_aAsyncSettingsTimer.SetTimeout(10);
745 m_aAsyncSettingsTimer.Start();
749 return true;
752 IMPL_LINK_NOARG( MenuBarManager, AsyncSettingsHdl, Timer*, void)
754 SolarMutexGuard g;
755 Reference< XInterface > xSelfHold(
756 static_cast< ::cppu::OWeakObject* >( this ), UNO_QUERY_THROW );
758 m_aAsyncSettingsTimer.Stop();
759 if ( !m_bActive && m_xDeferredItemContainer.is() )
761 SetItemContainer( m_xDeferredItemContainer );
762 m_xDeferredItemContainer.clear();
766 IMPL_LINK( MenuBarManager, Select, Menu *, pMenu, bool )
768 URL aTargetURL;
769 Sequence<PropertyValue> aArgs;
770 Reference< XDispatch > xDispatch;
773 SolarMutexGuard g;
775 sal_uInt16 nCurItemId = pMenu->GetCurItemId();
776 sal_uInt16 nCurPos = pMenu->GetItemPos( nCurItemId );
777 if ( pMenu == m_pVCLMenu &&
778 pMenu->GetItemType( nCurPos ) != MenuItemType::SEPARATOR )
780 MenuItemHandler* pMenuItemHandler = GetMenuItemHandler( nCurItemId );
781 if ( pMenuItemHandler && pMenuItemHandler->xMenuItemDispatch.is() )
783 aTargetURL.Complete = pMenuItemHandler->aMenuItemURL;
784 m_xURLTransformer->parseStrict( aTargetURL );
786 if ( pMenu->GetUserValue( nCurItemId ) )
788 // addon menu item selected
789 aArgs = { comphelper::makePropertyValue("Referer", OUString("private:user")) };
792 xDispatch = pMenuItemHandler->xMenuItemDispatch;
797 // tdf#126054 don't let dispatch destroy this until after function completes
798 rtl::Reference<MenuBarManager> xKeepAlive(this);
799 if (xDispatch.is())
801 SolarMutexReleaser aReleaser;
802 xDispatch->dispatch( aTargetURL, aArgs );
805 if ( !m_bHasMenuBar )
806 // Standalone (non-native) popup menu doesn't fire deactivate event
807 // in this case, so we have to reset the active flag here.
808 m_bActive = false;
810 return true;
813 bool MenuBarManager::MustBeHidden( PopupMenu* pPopupMenu, const Reference< XURLTransformer >& rTransformer )
815 if ( !pPopupMenu )
816 return true;
818 URL aTargetURL;
819 SvtCommandOptions aCmdOptions;
821 sal_uInt16 nCount = pPopupMenu->GetItemCount();
822 sal_uInt16 nHideCount( 0 );
824 for ( sal_uInt16 i = 0; i < nCount; i++ )
826 sal_uInt16 nId = pPopupMenu->GetItemId( i );
827 if ( nId > 0 )
829 PopupMenu* pSubPopupMenu = pPopupMenu->GetPopupMenu( nId );
830 if ( pSubPopupMenu )
832 if ( MustBeHidden( pSubPopupMenu, rTransformer ))
834 pPopupMenu->HideItem( nId );
835 ++nHideCount;
838 else
840 aTargetURL.Complete = pPopupMenu->GetItemCommand( nId );
841 rTransformer->parseStrict( aTargetURL );
843 if ( aCmdOptions.LookupDisabled( aTargetURL.Path ))
844 ++nHideCount;
847 else
848 ++nHideCount;
851 return ( nCount == nHideCount );
854 OUString MenuBarManager::RetrieveLabelFromCommand(const OUString& rCmdURL)
856 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(rCmdURL, m_aModuleIdentifier);
857 if ( !m_bHasMenuBar )
859 // This is a context menu, prefer "PopupLabel" over "Label".
860 return vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
862 return vcl::CommandInfoProvider::GetMenuLabelForCommand(aProperties);
865 bool MenuBarManager::CreatePopupMenuController( MenuItemHandler* pMenuItemHandler,
866 const css::uno::Reference< css::frame::XDispatchProvider >& rDispatchProvider,
867 const OUString& rModuleIdentifier )
869 OUString aItemCommand( pMenuItemHandler->aMenuItemURL );
871 // Try instantiate a popup menu controller. It is stored in the menu item handler.
872 if ( !m_xPopupMenuControllerFactory.is() )
873 return false;
875 auto aSeq( comphelper::InitAnyPropertySequence( {
876 { "DispatchProvider", Any(rDispatchProvider) },
877 { "ModuleIdentifier", Any(rModuleIdentifier) },
878 { "Frame", Any(m_xFrame) },
879 { "InToolbar", Any(!m_bHasMenuBar) }
880 } ) );
882 Reference< XPopupMenuController > xPopupMenuController(
883 m_xPopupMenuControllerFactory->createInstanceWithArgumentsAndContext(
884 aItemCommand,
885 aSeq,
886 m_xContext ),
887 UNO_QUERY );
889 if ( xPopupMenuController.is() )
891 // Provide our awt popup menu to the popup menu controller
892 pMenuItemHandler->xPopupMenuController = xPopupMenuController;
893 xPopupMenuController->setPopupMenu( pMenuItemHandler->xPopupMenu );
894 return true;
897 return false;
900 void MenuBarManager::FillMenuManager( Menu* pMenu, const Reference< XFrame >& rFrame,
901 const Reference< XDispatchProvider >& rDispatchProvider,
902 const OUString& rModuleIdentifier, bool bDelete )
904 m_xFrame = rFrame;
905 m_bActive = false;
906 m_bDeleteMenu = bDelete;
907 m_pVCLMenu = pMenu;
908 m_xDispatchProvider = rDispatchProvider;
910 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
911 m_bShowMenuImages = rSettings.GetUseImagesInMenus();
912 m_bRetrieveImages = false;
914 // Set module identifier when provided from outside
915 if (!rModuleIdentifier.isEmpty())
916 m_aModuleIdentifier = rModuleIdentifier;
917 else
918 m_aModuleIdentifier = vcl::CommandInfoProvider::GetModuleIdentifier(m_xFrame);
920 // Add root as ui configuration listener
921 RetrieveImageManagers();
923 if ( pMenu->IsMenuBar() && rFrame.is() )
925 // First merge all addon popup menus into our structure
926 sal_uInt16 nPos = 0;
927 for ( nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
929 sal_uInt16 nItemId = pMenu->GetItemId( nPos );
930 OUString aCommand = pMenu->GetItemCommand( nItemId );
931 if ( aCommand == aSpecialWindowCommand || aCommand == aCmdHelpMenu )
933 // Retrieve addon popup menus and add them to our menu bar
934 framework::AddonMenuManager::MergeAddonPopupMenus( rFrame, nPos, static_cast<MenuBar *>(pMenu) );
935 break;
939 // Merge the Add-Ons help menu items into the Office help menu
940 framework::AddonMenuManager::MergeAddonHelpMenu( rFrame, static_cast<MenuBar *>(pMenu) );
943 bool bAccessibilityEnabled( Application::GetSettings().GetMiscSettings().GetEnableATToolSupport() );
944 sal_uInt16 nItemCount = pMenu->GetItemCount();
945 OUString aItemCommand;
946 m_aMenuItemHandlerVector.reserve(nItemCount);
947 for ( sal_uInt16 i = 0; i < nItemCount; i++ )
949 sal_uInt16 nItemId = FillItemCommand(aItemCommand,pMenu, i );
951 if (( pMenu->IsMenuBar() || bAccessibilityEnabled ) &&
952 ( pMenu->GetItemText( nItemId ).isEmpty() ))
954 if ( !aItemCommand.isEmpty() )
955 pMenu->SetItemText( nItemId, RetrieveLabelFromCommand( aItemCommand ));
958 // Command can be just an alias to another command.
959 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aItemCommand, m_aModuleIdentifier);
960 OUString aRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties);
961 if ( !aRealCommand.isEmpty() )
962 aItemCommand = aRealCommand;
964 Reference< XDispatch > xDispatch;
965 Reference< XStatusListener > xStatusListener;
966 VclPtr<PopupMenu> pPopup = pMenu->GetPopupMenu( nItemId );
967 // overwrite the show icons on menu option?
968 MenuItemBits nBits = pMenu->GetItemBits( nItemId ) & ( MenuItemBits::ICON | MenuItemBits::TEXT );
969 bool bItemShowMenuImages = ( m_bShowMenuImages && nBits != MenuItemBits::TEXT ) || nBits & MenuItemBits::ICON;
971 if ( pPopup )
973 // Retrieve module identifier from Help Command entry
974 OUString aModuleIdentifier( rModuleIdentifier );
975 if (!pMenu->GetHelpCommand(nItemId).isEmpty())
977 aModuleIdentifier = pMenu->GetHelpCommand( nItemId );
978 pMenu->SetHelpCommand( nItemId, "" );
981 // Retrieve possible attributes struct
982 Reference< XDispatchProvider > xPopupMenuDispatchProvider( rDispatchProvider );
983 MenuAttributes* pAttributes = static_cast<MenuAttributes *>(pMenu->GetUserValue( nItemId ));
984 if ( pAttributes )
985 xPopupMenuDispatchProvider = pAttributes->xDispatchProvider;
987 if ( m_xPopupMenuControllerFactory.is() &&
988 m_xPopupMenuControllerFactory->hasController( aItemCommand, aModuleIdentifier )
991 // Check if we have to create a popup menu for a uno based popup menu controller.
992 // We have to set an empty popup menu into our menu structure so the controller also
993 // works with inplace OLE.
994 MenuItemHandler* pItemHandler = new MenuItemHandler( nItemId, xStatusListener, xDispatch );
995 rtl::Reference<VCLXPopupMenu> pVCLXPopupMenu = new VCLXPopupMenu(pPopup);
996 pItemHandler->xPopupMenu = pVCLXPopupMenu;
997 pItemHandler->aMenuItemURL = aItemCommand;
998 m_aMenuItemHandlerVector.push_back( std::unique_ptr<MenuItemHandler>(pItemHandler) );
1000 if ( bAccessibilityEnabled || pMenu->IsMenuBar())
1002 if ( CreatePopupMenuController( pItemHandler, xPopupMenuDispatchProvider, aModuleIdentifier ))
1003 pItemHandler->xPopupMenuController->updatePopupMenu();
1005 lcl_CheckForChildren(pMenu, nItemId);
1007 else
1009 // Check if this is the tools menu. Add menu item if needed
1010 if ( aItemCommand == aCmdToolsMenu && AddonMenuManager::HasAddonMenuElements() )
1012 // Create addon popup menu if there exist elements and this is the tools popup menu
1013 VclPtr<PopupMenu> pSubMenu = AddonMenuManager::CreateAddonMenu(rFrame);
1014 if ( pSubMenu && ( pSubMenu->GetItemCount() > 0 ))
1016 if ( pPopup->GetItemType( pPopup->GetItemCount() - 1 ) != MenuItemType::SEPARATOR )
1017 pPopup->InsertSeparator();
1019 pPopup->InsertItem( ITEMID_ADDONLIST, OUString() );
1020 pPopup->SetPopupMenu( ITEMID_ADDONLIST, pSubMenu );
1021 pPopup->SetItemCommand( ITEMID_ADDONLIST, ".uno:Addons" );
1023 else
1024 pSubMenu.disposeAndClear();
1027 rtl::Reference<MenuBarManager> pSubMenuManager = new MenuBarManager( m_xContext, rFrame, m_xURLTransformer,
1028 xPopupMenuDispatchProvider, aModuleIdentifier, pPopup, false, m_bHasMenuBar );
1030 AddMenu(pSubMenuManager.get(), aItemCommand, nItemId);
1033 else if ( pMenu->GetItemType( i ) != MenuItemType::SEPARATOR )
1035 if ( bItemShowMenuImages )
1036 m_bRetrieveImages = true;
1038 std::unique_ptr<MenuItemHandler> pItemHandler(new MenuItemHandler( nItemId, xStatusListener, xDispatch ));
1039 // Retrieve possible attributes struct
1040 MenuAttributes* pAttributes = static_cast<MenuAttributes *>(pMenu->GetUserValue( nItemId ));
1041 if ( pAttributes )
1042 pItemHandler->aTargetFrame = pAttributes->aTargetFrame;
1043 pItemHandler->aMenuItemURL = aItemCommand;
1045 if ( m_xPopupMenuControllerFactory.is() &&
1046 m_xPopupMenuControllerFactory->hasController( aItemCommand, m_aModuleIdentifier ) )
1048 // Check if we have to create a popup menu for a uno based popup menu controller.
1049 // We have to set an empty popup menu into our menu structure so the controller also
1050 // works with inplace OLE.
1051 rtl::Reference<VCLXPopupMenu> pVCLXPopupMenu = new VCLXPopupMenu;
1052 PopupMenu* pPopupMenu = static_cast<PopupMenu *>(pVCLXPopupMenu->GetMenu());
1053 pMenu->SetPopupMenu( pItemHandler->nItemId, pPopupMenu );
1054 pItemHandler->xPopupMenu = pVCLXPopupMenu;
1056 if ( bAccessibilityEnabled && CreatePopupMenuController( pItemHandler.get(), m_xDispatchProvider, m_aModuleIdentifier ) )
1058 pItemHandler->xPopupMenuController->updatePopupMenu();
1061 lcl_CheckForChildren(pMenu, pItemHandler->nItemId);
1064 m_aMenuItemHandlerVector.push_back( std::move(pItemHandler) );
1068 if ( m_bHasMenuBar && bAccessibilityEnabled )
1070 RetrieveShortcuts( m_aMenuItemHandlerVector );
1071 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
1073 // Set key code, workaround for hard-coded shortcut F1 mapped to .uno:HelpIndex
1074 // Only non-popup menu items can have a short-cut
1075 if ( menuItemHandler->aMenuItemURL == aCmdHelpIndex )
1077 vcl::KeyCode aKeyCode( KEY_F1 );
1078 pMenu->SetAccelKey( menuItemHandler->nItemId, aKeyCode );
1080 else if ( pMenu->GetPopupMenu( menuItemHandler->nItemId ) == nullptr )
1081 pMenu->SetAccelKey( menuItemHandler->nItemId, menuItemHandler->aKeyCode );
1085 SetHdl();
1088 void MenuBarManager::impl_RetrieveShortcutsFromConfiguration(
1089 const Reference< XAcceleratorConfiguration >& rAccelCfg,
1090 const Sequence< OUString >& rCommands,
1091 std::vector< std::unique_ptr<MenuItemHandler> >& aMenuShortCuts )
1093 if ( !rAccelCfg.is() )
1094 return;
1098 css::awt::KeyEvent aKeyEvent;
1099 Sequence< Any > aSeqKeyCode = rAccelCfg->getPreferredKeyEventsForCommandList( rCommands );
1100 for ( sal_Int32 i = 0; i < aSeqKeyCode.getLength(); i++ )
1102 if ( aSeqKeyCode[i] >>= aKeyEvent )
1103 aMenuShortCuts[i]->aKeyCode = svt::AcceleratorExecute::st_AWTKey2VCLKey( aKeyEvent );
1106 catch ( const IllegalArgumentException& )
1111 void MenuBarManager::RetrieveShortcuts( std::vector< std::unique_ptr<MenuItemHandler> >& aMenuShortCuts )
1113 Reference< XAcceleratorConfiguration > xDocAccelCfg( m_xDocAcceleratorManager );
1114 Reference< XAcceleratorConfiguration > xModuleAccelCfg( m_xModuleAcceleratorManager );
1115 Reference< XAcceleratorConfiguration > xGlobalAccelCfg( m_xGlobalAcceleratorManager );
1117 if ( !m_bAcceleratorCfg )
1119 // Retrieve references on demand
1120 m_bAcceleratorCfg = true;
1121 if ( !xDocAccelCfg.is() )
1123 Reference< XController > xController = m_xFrame->getController();
1124 Reference< XModel > xModel;
1125 if ( xController.is() )
1127 xModel = xController->getModel();
1128 if ( xModel.is() )
1130 Reference< XUIConfigurationManagerSupplier > xSupplier( xModel, UNO_QUERY );
1131 if ( xSupplier.is() )
1133 Reference< XUIConfigurationManager > xDocUICfgMgr = xSupplier->getUIConfigurationManager();
1134 if ( xDocUICfgMgr.is() )
1136 xDocAccelCfg = xDocUICfgMgr->getShortCutManager();
1137 m_xDocAcceleratorManager = xDocAccelCfg;
1144 if ( !xModuleAccelCfg.is() )
1146 Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier =
1147 theModuleUIConfigurationManagerSupplier::get( m_xContext );
1150 Reference< XUIConfigurationManager > xUICfgMgr = xModuleCfgMgrSupplier->getUIConfigurationManager( m_aModuleIdentifier );
1151 if ( xUICfgMgr.is() )
1153 xModuleAccelCfg = xUICfgMgr->getShortCutManager();
1154 m_xModuleAcceleratorManager = xModuleAccelCfg;
1157 catch ( const RuntimeException& )
1159 throw;
1161 catch ( const Exception& )
1166 if ( !xGlobalAccelCfg.is() ) try
1168 xGlobalAccelCfg = GlobalAcceleratorConfiguration::create( m_xContext );
1169 m_xGlobalAcceleratorManager = xGlobalAccelCfg;
1171 catch ( const css::uno::DeploymentException& )
1173 SAL_WARN("fwk.uielement", "GlobalAcceleratorConfiguration"
1174 " not available. This should happen only on mobile platforms.");
1178 vcl::KeyCode aEmptyKeyCode;
1179 Sequence< OUString > aSeq( aMenuShortCuts.size() );
1180 auto aSeqRange = asNonConstRange(aSeq);
1181 const sal_uInt32 nCount = aMenuShortCuts.size();
1182 for ( sal_uInt32 i = 0; i < nCount; ++i )
1184 aSeqRange[i] = aMenuShortCuts[i]->aMenuItemURL;
1185 aMenuShortCuts[i]->aKeyCode = aEmptyKeyCode;
1188 if ( m_xGlobalAcceleratorManager.is() )
1189 impl_RetrieveShortcutsFromConfiguration( xGlobalAccelCfg, aSeq, aMenuShortCuts );
1190 if ( m_xModuleAcceleratorManager.is() )
1191 impl_RetrieveShortcutsFromConfiguration( xModuleAccelCfg, aSeq, aMenuShortCuts );
1192 if ( m_xDocAcceleratorManager.is() )
1193 impl_RetrieveShortcutsFromConfiguration( xDocAccelCfg, aSeq, aMenuShortCuts );
1196 void MenuBarManager::RetrieveImageManagers()
1198 if ( !m_xDocImageManager.is() )
1200 Reference< XController > xController = m_xFrame->getController();
1201 Reference< XModel > xModel;
1202 if ( xController.is() )
1204 xModel = xController->getModel();
1205 if ( xModel.is() )
1207 Reference< XUIConfigurationManagerSupplier > xSupplier( xModel, UNO_QUERY );
1208 if ( xSupplier.is() )
1210 Reference< XUIConfigurationManager > xDocUICfgMgr = xSupplier->getUIConfigurationManager();
1211 m_xDocImageManager.set( xDocUICfgMgr->getImageManager(), UNO_QUERY );
1212 m_xDocImageManager->addConfigurationListener(
1213 Reference< XUIConfigurationListener >(this) );
1219 if ( !m_xModuleImageManager.is() )
1221 Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier =
1222 theModuleUIConfigurationManagerSupplier::get( m_xContext );
1223 Reference< XUIConfigurationManager > xUICfgMgr = xModuleCfgMgrSupplier->getUIConfigurationManager( m_aModuleIdentifier );
1224 m_xModuleImageManager.set( xUICfgMgr->getImageManager(), UNO_QUERY );
1225 m_xModuleImageManager->addConfigurationListener( Reference< XUIConfigurationListener >(this) );
1229 void MenuBarManager::FillMenuWithConfiguration(
1230 sal_uInt16& nId,
1231 Menu* pMenu,
1232 const OUString& rModuleIdentifier,
1233 const Reference< XIndexAccess >& rItemContainer,
1234 const Reference< XURLTransformer >& rTransformer )
1236 Reference< XDispatchProvider > xEmptyDispatchProvider;
1237 MenuBarManager::FillMenu( nId, pMenu, rModuleIdentifier, rItemContainer, xEmptyDispatchProvider );
1239 // Merge add-on menu entries into the menu bar
1240 MenuBarManager::MergeAddonMenus( pMenu,
1241 AddonsOptions().GetMergeMenuInstructions(),
1242 rModuleIdentifier );
1244 bool bHasDisabledEntries = SvtCommandOptions().HasEntriesDisabled();
1245 if ( !bHasDisabledEntries )
1246 return;
1248 sal_uInt16 nCount = pMenu->GetItemCount();
1249 for ( sal_uInt16 i = 0; i < nCount; i++ )
1251 sal_uInt16 nID = pMenu->GetItemId( i );
1252 if ( nID > 0 )
1254 PopupMenu* pPopupMenu = pMenu->GetPopupMenu( nID );
1255 if ( pPopupMenu )
1257 if ( MustBeHidden( pPopupMenu, rTransformer ))
1258 pMenu->HideItem( nId );
1264 void MenuBarManager::FillMenu(
1265 sal_uInt16& nId,
1266 Menu* pMenu,
1267 const OUString& rModuleIdentifier,
1268 const Reference< XIndexAccess >& rItemContainer,
1269 const Reference< XDispatchProvider >& rDispatchProvider )
1271 // Fill menu bar with container contents
1272 for ( sal_Int32 n = 0; n < rItemContainer->getCount(); n++ )
1274 Sequence< PropertyValue > aProps;
1275 OUString aCommandURL;
1276 OUString aLabel;
1277 OUString aModuleIdentifier( rModuleIdentifier );
1278 sal_uInt16 nType = 0;
1279 Reference< XIndexAccess > xIndexContainer;
1280 Reference< XDispatchProvider > xDispatchProvider( rDispatchProvider );
1281 sal_Int16 nStyle = 0;
1284 if ( rItemContainer->getByIndex( n ) >>= aProps )
1286 bool bShow = true;
1287 bool bEnabled = true;
1289 for ( beans::PropertyValue const & rProp : std::as_const(aProps) )
1291 OUString aPropName = rProp.Name;
1292 if ( aPropName == "CommandURL" )
1293 rProp.Value >>= aCommandURL;
1294 else if ( aPropName == "ItemDescriptorContainer" )
1295 rProp.Value >>= xIndexContainer;
1296 else if ( aPropName == "Label" )
1297 rProp.Value >>= aLabel;
1298 else if ( aPropName == "Type" )
1299 rProp.Value >>= nType;
1300 else if ( aPropName == "ModuleIdentifier" )
1301 rProp.Value >>= aModuleIdentifier;
1302 else if ( aPropName == "DispatchProvider" )
1303 rProp.Value >>= xDispatchProvider;
1304 else if ( aPropName == "Style" )
1305 rProp.Value >>= nStyle;
1306 else if ( aPropName == "IsVisible" )
1307 rProp.Value >>= bShow;
1308 else if ( aPropName == "Enabled" )
1309 rProp.Value >>= bEnabled;
1312 if (!aCommandURL.isEmpty() && vcl::CommandInfoProvider::IsExperimental(aCommandURL, rModuleIdentifier) &&
1313 !officecfg::Office::Common::Misc::ExperimentalMode::get())
1315 continue;
1318 if ( nType == css::ui::ItemType::DEFAULT )
1320 pMenu->InsertItem( nId, aLabel );
1321 pMenu->SetItemCommand( nId, aCommandURL );
1323 if ( nStyle )
1325 MenuItemBits nBits = pMenu->GetItemBits( nId );
1326 if ( nStyle & css::ui::ItemStyle::ICON )
1327 nBits |= MenuItemBits::ICON;
1328 if ( nStyle & css::ui::ItemStyle::TEXT )
1329 nBits |= MenuItemBits::TEXT;
1330 if ( nStyle & css::ui::ItemStyle::RADIO_CHECK )
1331 nBits |= MenuItemBits::RADIOCHECK;
1332 pMenu->SetItemBits( nId, nBits );
1335 if ( !bShow )
1336 pMenu->HideItem( nId );
1338 if ( !bEnabled)
1339 pMenu->EnableItem( nId, false );
1341 if ( xIndexContainer.is() )
1343 VclPtr<PopupMenu> pNewPopupMenu = VclPtr<PopupMenu>::Create();
1344 pMenu->SetPopupMenu( nId, pNewPopupMenu );
1346 if ( xDispatchProvider.is() )
1348 // Use attributes struct to transport special dispatch provider
1349 void* nAttributePtr = MenuAttributes::CreateAttribute(xDispatchProvider);
1350 pMenu->SetUserValue(nId, nAttributePtr, MenuAttributes::ReleaseAttribute);
1353 // Use help command to transport module identifier
1354 if ( !aModuleIdentifier.isEmpty() )
1355 pMenu->SetHelpCommand( nId, aModuleIdentifier );
1357 ++nId;
1358 FillMenu( nId, pNewPopupMenu, aModuleIdentifier, xIndexContainer, xDispatchProvider );
1360 else
1361 ++nId;
1363 else
1365 pMenu->InsertSeparator();
1366 ++nId;
1370 catch ( const IndexOutOfBoundsException& )
1372 break;
1377 void MenuBarManager::MergeAddonMenus(
1378 Menu* pMenuBar,
1379 const MergeMenuInstructionContainer& aMergeInstructionContainer,
1380 const OUString& rModuleIdentifier )
1382 // set start value for the item ID for the new addon menu items
1383 sal_uInt16 nItemId = ADDONMENU_MERGE_ITEMID_START;
1385 const sal_uInt32 nCount = aMergeInstructionContainer.size();
1386 for ( sal_uInt32 i = 0; i < nCount; i++ )
1388 const MergeMenuInstruction& rMergeInstruction = aMergeInstructionContainer[i];
1390 if ( MenuBarMerger::IsCorrectContext( rMergeInstruction.aMergeContext, rModuleIdentifier ))
1392 ::std::vector< OUString > aMergePath;
1394 // retrieve the merge path from the merge point string
1395 MenuBarMerger::RetrieveReferencePath( rMergeInstruction.aMergePoint, aMergePath );
1397 // convert the sequence/sequence property value to a more convenient vector<>
1398 AddonMenuContainer aMergeMenuItems;
1399 MenuBarMerger::GetSubMenu( rMergeInstruction.aMergeMenu, aMergeMenuItems );
1401 // try to find the reference point for our merge operation
1402 Menu* pMenu = pMenuBar;
1403 ReferencePathInfo aResult = MenuBarMerger::FindReferencePath( aMergePath, pMenu );
1405 if ( aResult.eResult == RP_OK )
1407 // normal merge operation
1408 MenuBarMerger::ProcessMergeOperation( aResult.pPopupMenu,
1409 aResult.nPos,
1410 nItemId,
1411 rMergeInstruction.aMergeCommand,
1412 rMergeInstruction.aMergeCommandParameter,
1413 rModuleIdentifier,
1414 aMergeMenuItems );
1416 else
1418 // fallback
1419 MenuBarMerger::ProcessFallbackOperation( aResult,
1420 nItemId,
1421 rMergeInstruction.aMergeCommand,
1422 rMergeInstruction.aMergeFallback,
1423 aMergePath,
1424 rModuleIdentifier,
1425 aMergeMenuItems );
1431 void MenuBarManager::SetItemContainer( const Reference< XIndexAccess >& rItemContainer )
1433 SolarMutexGuard aSolarMutexGuard;
1435 Reference< XFrame > xFrame = m_xFrame;
1437 // Clear MenuBarManager structures
1439 // Check active state as we cannot change our VCL menu during activation by the user
1440 if ( m_bActive )
1442 m_xDeferredItemContainer = rItemContainer;
1443 return;
1446 RemoveListener();
1447 m_aMenuItemHandlerVector.clear();
1448 m_pVCLMenu->Clear();
1450 sal_uInt16 nId = 1;
1452 // Fill menu bar with container contents
1453 FillMenuWithConfiguration( nId, m_pVCLMenu, m_aModuleIdentifier, rItemContainer, m_xURLTransformer );
1455 // Refill menu manager again
1456 Reference< XDispatchProvider > xDispatchProvider;
1457 FillMenuManager( m_pVCLMenu, xFrame, xDispatchProvider, m_aModuleIdentifier, false );
1459 // add itself as frame action listener
1460 m_xFrame->addFrameActionListener( Reference< XFrameActionListener >(this) );
1464 void MenuBarManager::GetPopupController( PopupControllerCache& rPopupController )
1467 SolarMutexGuard aSolarMutexGuard;
1469 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
1471 if ( menuItemHandler->xPopupMenuController.is() )
1473 Reference< XDispatchProvider > xDispatchProvider( menuItemHandler->xPopupMenuController, UNO_QUERY );
1475 PopupControllerEntry aPopupControllerEntry;
1476 aPopupControllerEntry.m_xDispatchProvider = xDispatchProvider;
1478 // Just use the main part of the URL for popup menu controllers
1479 sal_Int32 nSchemePart( 0 );
1480 OUString aMenuURL( menuItemHandler->aMenuItemURL );
1482 nSchemePart = aMenuURL.indexOf( ':' );
1483 if (( nSchemePart > 0 ) &&
1484 ( aMenuURL.getLength() > ( nSchemePart+1 )))
1486 OUString aMainURL( "vnd.sun.star.popup:" );
1487 sal_Int32 nQueryPart = aMenuURL.indexOf( '?', nSchemePart );
1488 if ( nQueryPart > 0 )
1489 aMainURL += aMenuURL.subView( nSchemePart, nQueryPart-nSchemePart );
1490 else if ( nQueryPart == -1 )
1491 aMainURL += aMenuURL.subView( nSchemePart+1 );
1493 rPopupController.emplace( aMainURL, aPopupControllerEntry );
1496 if ( menuItemHandler->xSubMenuManager.is() )
1498 MenuBarManager* pMenuBarManager = static_cast<MenuBarManager*>(menuItemHandler->xSubMenuManager.get());
1499 if ( pMenuBarManager )
1500 pMenuBarManager->GetPopupController( rPopupController );
1505 void MenuBarManager::AddMenu(MenuBarManager* pSubMenuManager,const OUString& _sItemCommand,sal_uInt16 _nItemId)
1507 Reference< XStatusListener > xSubMenuManager( pSubMenuManager );
1508 m_xFrame->addFrameActionListener( Reference< XFrameActionListener >( xSubMenuManager, UNO_QUERY ));
1510 Reference< XDispatch > xDispatch;
1511 std::unique_ptr<MenuItemHandler> pMenuItemHandler(new MenuItemHandler(
1512 _nItemId,
1513 xSubMenuManager,
1514 xDispatch ));
1515 pMenuItemHandler->aMenuItemURL = _sItemCommand;
1516 m_aMenuItemHandlerVector.push_back( std::move(pMenuItemHandler) );
1519 sal_uInt16 MenuBarManager::FillItemCommand(OUString& _rItemCommand, Menu* _pMenu,sal_uInt16 _nIndex) const
1521 sal_uInt16 nItemId = _pMenu->GetItemId( _nIndex );
1523 _rItemCommand = _pMenu->GetItemCommand( nItemId );
1524 if ( _rItemCommand.isEmpty() )
1526 _rItemCommand = "slot:" + OUString::number( nItemId );
1527 _pMenu->SetItemCommand( nItemId, _rItemCommand );
1529 return nItemId;
1532 void MenuBarManager::SetHdl()
1534 m_pVCLMenu->SetActivateHdl( LINK( this, MenuBarManager, Activate ));
1535 m_pVCLMenu->SetDeactivateHdl( LINK( this, MenuBarManager, Deactivate ));
1536 m_pVCLMenu->SetSelectHdl( LINK( this, MenuBarManager, Select ));
1538 if ( !m_xURLTransformer.is() && m_xContext.is() )
1539 m_xURLTransformer.set( URLTransformer::create( m_xContext) );
1542 void MenuBarManager::FillMenuImages(Reference< XFrame > const & _xFrame, Menu* _pMenu,bool bShowMenuImages)
1544 AddonsOptions aAddonOptions;
1546 for ( sal_uInt16 nPos = 0; nPos < _pMenu->GetItemCount(); nPos++ )
1548 sal_uInt16 nId = _pMenu->GetItemId( nPos );
1549 if ( _pMenu->GetItemType( nPos ) != MenuItemType::SEPARATOR )
1551 // overwrite the show icons on menu option?
1552 MenuItemBits nBits = _pMenu->GetItemBits( nId ) & ( MenuItemBits::ICON | MenuItemBits::TEXT );
1553 bool bTmpShowMenuImages = ( bShowMenuImages && nBits != MenuItemBits::TEXT ) || nBits & MenuItemBits::ICON;
1555 if ( bTmpShowMenuImages )
1557 OUString aMenuItemCommand = _pMenu->GetItemCommand( nId );
1558 Image aImage = vcl::CommandInfoProvider::GetImageForCommand(aMenuItemCommand, _xFrame);
1559 if ( !aImage )
1560 aImage = Image(aAddonOptions.GetImageFromURL(aMenuItemCommand, false));
1562 _pMenu->SetItemImage( nId, aImage );
1564 else
1565 _pMenu->SetItemImage( nId, Image() );
1572 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */