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/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>
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...
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
;
108 throw css::lang::DisposedException();
114 SystemMenuData aSystemMenuData
;
116 m_pVCLMenu
->GetSystemMenuData( &aSystemMenuData
);
118 if( SystemType
== SystemDependent::SYSTEM_WIN32
)
121 reinterpret_cast<sal_IntPtr
>(aSystemMenuData
.hMenu
));
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!" );
141 void MenuBarManager::disposing(std::unique_lock
<std::mutex
>& )
143 Reference
< XComponent
> xThis( this );
147 // stop asynchronous settings timer and
148 // release deferred item container reference
149 m_aAsyncSettingsTimer
.Stop();
150 m_xDeferredItemContainer
.clear();
153 m_aMenuItemHandlerVector
.clear();
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();
191 void SAL_CALL
MenuBarManager::elementInserted( const css::ui::ConfigurationEvent
& Event
)
195 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
199 sal_Int16 nImageType
= sal_Int16();
200 if (( Event
.aInfo
>>= nImageType
) && nImageType
== 0 )
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
)
220 throw css::lang::DisposedException();
222 if ( Action
.Action
!= FrameAction_CONTEXT_CHANGED
)
225 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
227 // Clear dispatch reference as we will requery it later
228 if ( menuItemHandler
->xMenuItemDispatch
.is() )
231 aTargetURL
.Complete
= menuItemHandler
->aMenuItemURL
;
232 m_xURLTransformer
->parseStrict( aTargetURL
);
234 menuItemHandler
->xMenuItemDispatch
->removeStatusListener( this, aTargetURL
);
236 menuItemHandler
->xMenuItemDispatch
.clear();
241 void SAL_CALL
MenuBarManager::statusChanged( const FeatureStateEvent
& Event
)
243 OUString aFeatureURL
= Event
.FeatureURL
.Complete
;
245 SolarMutexGuard aSolarGuard
;
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
);
259 status::Visibility aVisibilityStatus
;
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
270 if ( (menuItemHandler
->aMenuItemURL
== ".uno:Paste" &&
271 m_aModuleIdentifier
!= "com.sun.star.sheet.SpreadsheetDocument")
272 || menuItemHandler
->aMenuItemURL
== ".uno:PasteClipboard" ) // special for draw/impress
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
);
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
)
341 m_pVCLMenu
->ShowItem( menuItemHandler
->nItemId
, aVisibilityStatus
.bVisible
);
342 menuItemHandler
->bMadeInvisible
= !aVisibilityStatus
.bVisible
;
344 else if ( menuItemHandler
->bMadeInvisible
)
345 m_pVCLMenu
->ShowItem( menuItemHandler
->nItemId
);
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
)
362 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
364 if ( menuItemHandler
->nItemId
== nItemId
)
365 return menuItemHandler
.get();
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()
391 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
393 if ( menuItemHandler
->xMenuItemDispatch
.is() )
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
425 Reference
< XComponent
> xComponent( menuItemHandler
->xPopupMenuController
, UNO_QUERY
);
426 if ( xComponent
.is() )
427 xComponent
->dispose();
429 catch ( const RuntimeException
& )
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();
450 m_xFrame
->removeFrameActionListener( Reference
< XFrameActionListener
>(this) );
452 catch ( const Exception
& )
459 void SAL_CALL
MenuBarManager::disposing( const EventObject
& Source
)
461 MenuItemHandler
* pMenuItemDisposing
= nullptr;
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();
476 if ( pMenuItemDisposing
)
478 // Release references to the dispatch object
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
496 m_pVCLMenu
->SetPopupMenu( pMenuItemDisposing
->nItemId
, nullptr );
499 pMenuItemDisposing
->xPopupMenuController
.clear();
500 pMenuItemDisposing
->xPopupMenu
.clear();
504 else if ( Source
.Source
== m_xFrame
)
506 // Our frame gets disposed. We have to remove all our listeners
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 );
525 class QuietInteractionContext
:
526 public cppu::WeakImplHelper
< css::uno::XCurrentContext
>
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;
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
)
546 css::uno::Reference
< css::uno::XCurrentContext
>
552 IMPL_LINK( MenuBarManager
, Activate
, Menu
*, pMenu
, bool )
554 if ( pMenu
!= m_pVCLMenu
)
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();
570 MenuFlags nFlag
= pMenu
->GetMenuFlags();
572 nFlag
&= ~MenuFlags::HideDisabledEntries
;
574 nFlag
|= MenuFlags::HideDisabledEntries
;
575 pMenu
->SetMenuFlags( nFlag
);
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
);
634 // Use provided dispatch provider => fallback to frame as dispatch provider
635 Reference
< XDispatchProvider
> xDispatchProvider
;
636 if ( m_xDispatchProvider
.is() )
637 xDispatchProvider
= m_xDispatchProvider
;
639 xDispatchProvider
.set( m_xFrame
, UNO_QUERY
);
641 if ( !xDispatchProvider
.is() )
644 SvtCommandOptions aCmdOptions
;
645 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
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
);
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();
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
;
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
);
733 IMPL_LINK( MenuBarManager
, Deactivate
, Menu
*, pMenu
, bool )
735 if ( pMenu
== m_pVCLMenu
)
738 if ( pMenu
->IsMenuBar() && m_xDeferredItemContainer
.is() )
740 // Start timer to handle settings asynchronous
741 // Changing the menu inside this handler leads to
743 m_aAsyncSettingsTimer
.SetInvokeHandler(LINK(this, MenuBarManager
, AsyncSettingsHdl
));
744 m_aAsyncSettingsTimer
.SetTimeout(10);
745 m_aAsyncSettingsTimer
.Start();
752 IMPL_LINK_NOARG( MenuBarManager
, AsyncSettingsHdl
, Timer
*, void)
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 )
769 Sequence
<PropertyValue
> aArgs
;
770 Reference
< XDispatch
> xDispatch
;
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);
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.
813 bool MenuBarManager::MustBeHidden( PopupMenu
* pPopupMenu
, const Reference
< XURLTransformer
>& rTransformer
)
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
);
829 PopupMenu
* pSubPopupMenu
= pPopupMenu
->GetPopupMenu( nId
);
832 if ( MustBeHidden( pSubPopupMenu
, rTransformer
))
834 pPopupMenu
->HideItem( nId
);
840 aTargetURL
.Complete
= pPopupMenu
->GetItemCommand( nId
);
841 rTransformer
->parseStrict( aTargetURL
);
843 if ( aCmdOptions
.LookupDisabled( aTargetURL
.Path
))
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() )
875 auto aSeq( comphelper::InitAnyPropertySequence( {
876 { "DispatchProvider", Any(rDispatchProvider
) },
877 { "ModuleIdentifier", Any(rModuleIdentifier
) },
878 { "Frame", Any(m_xFrame
) },
879 { "InToolbar", Any(!m_bHasMenuBar
) }
882 Reference
< XPopupMenuController
> xPopupMenuController(
883 m_xPopupMenuControllerFactory
->createInstanceWithArgumentsAndContext(
889 if ( xPopupMenuController
.is() )
891 // Provide our awt popup menu to the popup menu controller
892 pMenuItemHandler
->xPopupMenuController
= xPopupMenuController
;
893 xPopupMenuController
->setPopupMenu( pMenuItemHandler
->xPopupMenu
);
900 void MenuBarManager::FillMenuManager( Menu
* pMenu
, const Reference
< XFrame
>& rFrame
,
901 const Reference
< XDispatchProvider
>& rDispatchProvider
,
902 const OUString
& rModuleIdentifier
, bool bDelete
)
906 m_bDeleteMenu
= bDelete
;
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
;
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
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
) );
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
;
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
));
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
);
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" );
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
));
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
);
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() )
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();
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
& )
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();
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(
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
)
1248 sal_uInt16 nCount
= pMenu
->GetItemCount();
1249 for ( sal_uInt16 i
= 0; i
< nCount
; i
++ )
1251 sal_uInt16 nID
= pMenu
->GetItemId( i
);
1254 PopupMenu
* pPopupMenu
= pMenu
->GetPopupMenu( nID
);
1257 if ( MustBeHidden( pPopupMenu
, rTransformer
))
1258 pMenu
->HideItem( nId
);
1264 void MenuBarManager::FillMenu(
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
;
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
)
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())
1318 if ( nType
== css::ui::ItemType::DEFAULT
)
1320 pMenu
->InsertItem( nId
, aLabel
);
1321 pMenu
->SetItemCommand( nId
, aCommandURL
);
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
);
1336 pMenu
->HideItem( nId
);
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
);
1358 FillMenu( nId
, pNewPopupMenu
, aModuleIdentifier
, xIndexContainer
, xDispatchProvider
);
1365 pMenu
->InsertSeparator();
1370 catch ( const IndexOutOfBoundsException
& )
1377 void MenuBarManager::MergeAddonMenus(
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
,
1411 rMergeInstruction
.aMergeCommand
,
1412 rMergeInstruction
.aMergeCommandParameter
,
1419 MenuBarMerger::ProcessFallbackOperation( aResult
,
1421 rMergeInstruction
.aMergeCommand
,
1422 rMergeInstruction
.aMergeFallback
,
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
1442 m_xDeferredItemContainer
= rItemContainer
;
1447 m_aMenuItemHandlerVector
.clear();
1448 m_pVCLMenu
->Clear();
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(
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
);
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
);
1560 aImage
= Image(aAddonOptions
.GetImageFromURL(aMenuItemCommand
, false));
1562 _pMenu
->SetItemImage( nId
, aImage
);
1565 _pMenu
->SetItemImage( nId
, Image() );
1572 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */