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 OUString aCmdHelpIndex
= u
".uno:HelpIndex"_ustr
;
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() )
379 menuItemHandler
->xSubMenuManager
->RequestImages();
383 // Helper to reset objects to prepare shutdown
384 void MenuBarManager::RemoveListener()
388 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
390 if ( menuItemHandler
->xMenuItemDispatch
.is() )
393 aTargetURL
.Complete
= menuItemHandler
->aMenuItemURL
;
394 m_xURLTransformer
->parseStrict( aTargetURL
);
396 menuItemHandler
->xMenuItemDispatch
->removeStatusListener(
397 static_cast< XStatusListener
* >( this ), aTargetURL
);
400 menuItemHandler
->xMenuItemDispatch
.clear();
402 if ( menuItemHandler
->xPopupMenu
.is() )
405 // Remove popup menu from menu structure
406 m_pVCLMenu
->SetPopupMenu( menuItemHandler
->nItemId
, nullptr );
409 Reference
< css::lang::XEventListener
> xEventListener( menuItemHandler
->xPopupMenuController
, UNO_QUERY
);
410 if ( xEventListener
.is() )
412 EventObject aEventObject
;
413 aEventObject
.Source
= static_cast<OWeakObject
*>(this);
414 xEventListener
->disposing( aEventObject
);
417 // We now provide a popup menu controller to external code.
418 // Therefore the life-time must be explicitly handled via
422 Reference
< XComponent
> xComponent( menuItemHandler
->xPopupMenuController
, UNO_QUERY
);
423 if ( xComponent
.is() )
424 xComponent
->dispose();
426 catch ( const RuntimeException
& )
430 catch ( const Exception
& )
434 // Release references to controller and popup menu
435 menuItemHandler
->xPopupMenuController
.clear();
436 menuItemHandler
->xPopupMenu
.clear();
439 if ( menuItemHandler
->xSubMenuManager
)
440 menuItemHandler
->xSubMenuManager
->dispose();
446 m_xFrame
->removeFrameActionListener( Reference
< XFrameActionListener
>(this) );
448 catch ( const Exception
& )
455 void SAL_CALL
MenuBarManager::disposing( const EventObject
& Source
)
457 MenuItemHandler
* pMenuItemDisposing
= nullptr;
461 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
463 if ( menuItemHandler
->xMenuItemDispatch
.is() &&
464 menuItemHandler
->xMenuItemDispatch
== Source
.Source
)
466 // disposing called from menu item dispatcher, remove listener
467 pMenuItemDisposing
= menuItemHandler
.get();
472 if ( pMenuItemDisposing
)
474 // Release references to the dispatch object
476 aTargetURL
.Complete
= pMenuItemDisposing
->aMenuItemURL
;
478 m_xURLTransformer
->parseStrict( aTargetURL
);
480 pMenuItemDisposing
->xMenuItemDispatch
->removeStatusListener(
481 static_cast< XStatusListener
* >( this ), aTargetURL
);
482 pMenuItemDisposing
->xMenuItemDispatch
.clear();
483 if ( pMenuItemDisposing
->xPopupMenu
.is() )
485 Reference
< css::lang::XEventListener
> xEventListener( pMenuItemDisposing
->xPopupMenuController
, UNO_QUERY
);
486 if ( xEventListener
.is() )
487 xEventListener
->disposing( Source
);
490 // Remove popup menu from menu structure as we release our reference to
492 m_pVCLMenu
->SetPopupMenu( pMenuItemDisposing
->nItemId
, nullptr );
495 pMenuItemDisposing
->xPopupMenuController
.clear();
496 pMenuItemDisposing
->xPopupMenu
.clear();
500 else if ( Source
.Source
== m_xFrame
)
502 // Our frame gets disposed. We have to remove all our listeners
505 else if ( Source
.Source
== Reference
< XInterface
>( m_xDocImageManager
, UNO_QUERY
))
506 m_xDocImageManager
.clear();
507 else if ( Source
.Source
== Reference
< XInterface
>( m_xModuleImageManager
, UNO_QUERY
))
508 m_xModuleImageManager
.clear();
511 static void lcl_CheckForChildren(Menu
* pMenu
, sal_uInt16 nItemId
)
513 if (PopupMenu
* pThisPopup
= pMenu
->GetPopupMenu( nItemId
))
514 pMenu
->EnableItem( nItemId
, pThisPopup
->GetItemCount() != 0 && pThisPopup
->HasValidEntries(true));
521 class QuietInteractionContext
:
522 public cppu::WeakImplHelper
< css::uno::XCurrentContext
>
525 explicit QuietInteractionContext(
526 css::uno::Reference
< css::uno::XCurrentContext
> context
):
527 context_(std::move(context
)) {}
528 QuietInteractionContext(const QuietInteractionContext
&) = delete;
529 QuietInteractionContext
& operator=(const QuietInteractionContext
&) = delete;
532 virtual ~QuietInteractionContext() override
{}
534 virtual css::uno::Any SAL_CALL
getValueByName(
535 OUString
const & Name
) override
537 return Name
!= JAVA_INTERACTION_HANDLER_NAME
&& context_
.is()
538 ? context_
->getValueByName(Name
)
542 css::uno::Reference
< css::uno::XCurrentContext
>
548 IMPL_LINK( MenuBarManager
, Activate
, Menu
*, pMenu
, bool )
550 if ( pMenu
!= m_pVCLMenu
)
553 css::uno::ContextLayer
layer(
554 new QuietInteractionContext(
555 css::uno::getCurrentContext()));
557 // set/unset hiding disabled menu entries
558 bool bDontHide
= officecfg::Office::Common::View::Menu::DontHideDisabledEntry::get();
559 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
560 bool bShowMenuImages
= rSettings
.GetUseImagesInMenus();
561 bool bShowShortcuts
= m_bHasMenuBar
|| rSettings
.GetContextMenuShortcuts();
562 bool bHasDisabledEntries
= SvtCommandOptions().HasEntriesDisabled();
566 MenuFlags nFlag
= pMenu
->GetMenuFlags();
568 nFlag
&= ~MenuFlags::HideDisabledEntries
;
570 nFlag
|= MenuFlags::HideDisabledEntries
;
571 pMenu
->SetMenuFlags( nFlag
);
578 // Check if some modes have changed so we have to update our menu images
579 OUString sIconTheme
= SvtMiscOptions::GetIconTheme();
581 if ( m_bRetrieveImages
||
582 bShowMenuImages
!= m_bShowMenuImages
||
583 sIconTheme
!= m_sIconTheme
)
585 m_bShowMenuImages
= bShowMenuImages
;
586 m_bRetrieveImages
= false;
587 m_sIconTheme
= sIconTheme
;
588 FillMenuImages( m_xFrame
, pMenu
, bShowMenuImages
);
591 // Try to map commands to labels
592 for ( sal_uInt16 nPos
= 0; nPos
< pMenu
->GetItemCount(); nPos
++ )
594 sal_uInt16 nItemId
= pMenu
->GetItemId( nPos
);
595 if (( pMenu
->GetItemType( nPos
) != MenuItemType::SEPARATOR
) &&
596 ( pMenu
->GetItemText( nItemId
).isEmpty() ))
598 OUString aCommand
= pMenu
->GetItemCommand( nItemId
);
599 if ( !aCommand
.isEmpty() ) {
600 pMenu
->SetItemText( nItemId
, RetrieveLabelFromCommand( aCommand
));
605 // Try to set accelerator keys
607 if ( bShowShortcuts
)
608 RetrieveShortcuts( m_aMenuItemHandlerVector
);
610 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
612 if ( !bShowShortcuts
)
614 pMenu
->SetAccelKey( menuItemHandler
->nItemId
, vcl::KeyCode() );
616 else if ( menuItemHandler
->aMenuItemURL
== aCmdHelpIndex
)
618 // Set key code, workaround for hard-coded shortcut F1 mapped to .uno:HelpIndex
619 // Only non-popup menu items can have a short-cut
620 vcl::KeyCode
aKeyCode( KEY_F1
);
621 pMenu
->SetAccelKey( menuItemHandler
->nItemId
, aKeyCode
);
623 else if ( pMenu
->GetPopupMenu( menuItemHandler
->nItemId
) == nullptr )
624 pMenu
->SetAccelKey( menuItemHandler
->nItemId
, menuItemHandler
->aKeyCode
);
630 // Use provided dispatch provider => fallback to frame as dispatch provider
631 Reference
< XDispatchProvider
> xDispatchProvider
;
632 if ( m_xDispatchProvider
.is() )
633 xDispatchProvider
= m_xDispatchProvider
;
635 xDispatchProvider
.set( m_xFrame
, UNO_QUERY
);
637 if ( !xDispatchProvider
.is() )
640 SvtCommandOptions aCmdOptions
;
641 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
645 if ( !menuItemHandler
->xMenuItemDispatch
.is() &&
646 !menuItemHandler
->xSubMenuManager
.is() )
648 Reference
< XDispatch
> xMenuItemDispatch
;
650 aTargetURL
.Complete
= menuItemHandler
->aMenuItemURL
;
652 m_xURLTransformer
->parseStrict( aTargetURL
);
654 if ( bHasDisabledEntries
)
656 if ( aCmdOptions
.LookupDisabled( aTargetURL
.Path
))
657 pMenu
->HideItem( menuItemHandler
->nItemId
);
660 if ( aTargetURL
.Complete
.startsWith( ".uno:StyleApply?" ) )
661 xMenuItemDispatch
= new StyleDispatcher( m_xFrame
, m_xURLTransformer
, aTargetURL
);
663 xMenuItemDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, menuItemHandler
->aTargetFrame
, 0 );
665 bool bPopupMenu( false );
666 if ( !menuItemHandler
->xPopupMenuController
.is() &&
667 m_xPopupMenuControllerFactory
->hasController( menuItemHandler
->aMenuItemURL
, m_aModuleIdentifier
) )
669 if( xMenuItemDispatch
.is() || menuItemHandler
->aMenuItemURL
!= ".uno:RecentFileList" )
670 bPopupMenu
= CreatePopupMenuController(menuItemHandler
.get(), m_xDispatchProvider
, m_aModuleIdentifier
);
672 if (bPopupMenu
&& menuItemHandler
->xPopupMenuController
.is())
674 if (PopupMenu
* pThisPopup
= pMenu
->GetPopupMenu(menuItemHandler
->nItemId
))
676 pThisPopup
->Activate();
677 pThisPopup
->Deactivate();
681 else if ( menuItemHandler
->xPopupMenuController
.is() )
683 // Force update of popup menu
684 menuItemHandler
->xPopupMenuController
->updatePopupMenu();
686 if (PopupMenu
* pThisPopup
= pMenu
->GetPopupMenu( menuItemHandler
->nItemId
))
688 pThisPopup
->Activate();
689 pThisPopup
->Deactivate();
692 lcl_CheckForChildren(pMenu
, menuItemHandler
->nItemId
);
694 if ( xMenuItemDispatch
.is() )
696 menuItemHandler
->xMenuItemDispatch
= xMenuItemDispatch
;
697 menuItemHandler
->aParsedItemURL
= aTargetURL
.Complete
;
701 xMenuItemDispatch
->addStatusListener( static_cast< XStatusListener
* >( this ), aTargetURL
);
702 // For the menubar, we have to keep status listening to support Ubuntu's HUD.
703 if ( !m_bHasMenuBar
)
704 xMenuItemDispatch
->removeStatusListener( static_cast< XStatusListener
* >( this ), aTargetURL
);
707 else if ( !bPopupMenu
)
708 pMenu
->EnableItem( menuItemHandler
->nItemId
, false );
710 else if ( menuItemHandler
->xPopupMenuController
.is() )
712 // Force update of popup menu
713 menuItemHandler
->xPopupMenuController
->updatePopupMenu();
714 if (PopupMenu
* pThisPopup
= pMenu
->GetPopupMenu(menuItemHandler
->nItemId
))
716 pThisPopup
->Activate();
717 pThisPopup
->Deactivate();
719 lcl_CheckForChildren(pMenu
, menuItemHandler
->nItemId
);
721 else if ( menuItemHandler
->xMenuItemDispatch
.is() )
723 // We need an update to reflect the current state
726 aTargetURL
.Complete
= menuItemHandler
->aMenuItemURL
;
727 m_xURLTransformer
->parseStrict( aTargetURL
);
729 menuItemHandler
->xMenuItemDispatch
->addStatusListener(
730 static_cast< XStatusListener
* >( this ), aTargetURL
);
731 menuItemHandler
->xMenuItemDispatch
->removeStatusListener(
732 static_cast< XStatusListener
* >( this ), aTargetURL
);
734 catch ( const Exception
& )
738 else if (menuItemHandler
->xSubMenuManager
.is())
740 MenuBarManager
* pMenuBarManager
= menuItemHandler
->xSubMenuManager
.get();
743 pMenuBarManager
->Activate(pMenuBarManager
->GetMenuBar());
744 pMenuBarManager
->Deactivate(pMenuBarManager
->GetMenuBar());
746 lcl_CheckForChildren(pMenu
, menuItemHandler
->nItemId
);
754 IMPL_LINK( MenuBarManager
, Deactivate
, Menu
*, pMenu
, bool )
756 if ( pMenu
== m_pVCLMenu
)
759 if ( pMenu
->IsMenuBar() && m_xDeferredItemContainer
.is() )
761 // Start timer to handle settings asynchronous
762 // Changing the menu inside this handler leads to
764 m_aAsyncSettingsTimer
.SetInvokeHandler(LINK(this, MenuBarManager
, AsyncSettingsHdl
));
765 m_aAsyncSettingsTimer
.SetTimeout(10);
766 m_aAsyncSettingsTimer
.Start();
773 IMPL_LINK_NOARG( MenuBarManager
, AsyncSettingsHdl
, Timer
*, void)
776 Reference
< XInterface
> xSelfHold(
777 static_cast< ::cppu::OWeakObject
* >( this ), UNO_QUERY_THROW
);
779 m_aAsyncSettingsTimer
.Stop();
780 if ( !m_bActive
&& m_xDeferredItemContainer
.is() )
782 SetItemContainer( m_xDeferredItemContainer
);
783 m_xDeferredItemContainer
.clear();
787 IMPL_LINK( MenuBarManager
, Select
, Menu
*, pMenu
, bool )
790 Sequence
<PropertyValue
> aArgs
;
791 Reference
< XDispatch
> xDispatch
;
796 sal_uInt16 nCurItemId
= pMenu
->GetCurItemId();
797 sal_uInt16 nCurPos
= pMenu
->GetItemPos( nCurItemId
);
798 if ( pMenu
== m_pVCLMenu
&&
799 pMenu
->GetItemType( nCurPos
) != MenuItemType::SEPARATOR
)
801 MenuItemHandler
* pMenuItemHandler
= GetMenuItemHandler( nCurItemId
);
802 if ( pMenuItemHandler
&& pMenuItemHandler
->xMenuItemDispatch
.is() )
804 aTargetURL
.Complete
= pMenuItemHandler
->aMenuItemURL
;
805 m_xURLTransformer
->parseStrict( aTargetURL
);
807 if ( pMenu
->GetUserValue( nCurItemId
) )
809 // addon menu item selected
810 aArgs
= { comphelper::makePropertyValue("Referer", OUString("private:user")) };
813 xDispatch
= pMenuItemHandler
->xMenuItemDispatch
;
818 // tdf#126054 don't let dispatch destroy this until after function completes
819 rtl::Reference
<MenuBarManager
> xKeepAlive(this);
822 SolarMutexReleaser aReleaser
;
823 xDispatch
->dispatch( aTargetURL
, aArgs
);
826 if ( !m_bHasMenuBar
)
827 // Standalone (non-native) popup menu doesn't fire deactivate event
828 // in this case, so we have to reset the active flag here.
834 bool MenuBarManager::MustBeHidden( PopupMenu
* pPopupMenu
, const Reference
< XURLTransformer
>& rTransformer
)
840 SvtCommandOptions aCmdOptions
;
842 sal_uInt16 nCount
= pPopupMenu
->GetItemCount();
843 sal_uInt16
nHideCount( 0 );
845 for ( sal_uInt16 i
= 0; i
< nCount
; i
++ )
847 sal_uInt16 nId
= pPopupMenu
->GetItemId( i
);
850 PopupMenu
* pSubPopupMenu
= pPopupMenu
->GetPopupMenu( nId
);
853 if ( MustBeHidden( pSubPopupMenu
, rTransformer
))
855 pPopupMenu
->HideItem( nId
);
861 aTargetURL
.Complete
= pPopupMenu
->GetItemCommand( nId
);
862 rTransformer
->parseStrict( aTargetURL
);
864 if ( aCmdOptions
.LookupDisabled( aTargetURL
.Path
))
872 return ( nCount
== nHideCount
);
875 OUString
MenuBarManager::RetrieveLabelFromCommand(const OUString
& rCmdURL
)
877 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(rCmdURL
, m_aModuleIdentifier
);
878 if ( !m_bHasMenuBar
)
880 // This is a context menu, prefer "PopupLabel" over "Label".
881 return vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties
);
883 return vcl::CommandInfoProvider::GetMenuLabelForCommand(aProperties
);
886 bool MenuBarManager::CreatePopupMenuController( MenuItemHandler
* pMenuItemHandler
,
887 const css::uno::Reference
< css::frame::XDispatchProvider
>& rDispatchProvider
,
888 const OUString
& rModuleIdentifier
)
890 OUString
aItemCommand( pMenuItemHandler
->aMenuItemURL
);
892 // Try instantiate a popup menu controller. It is stored in the menu item handler.
893 if ( !m_xPopupMenuControllerFactory
.is() )
896 auto aSeq( comphelper::InitAnyPropertySequence( {
897 { "DispatchProvider", Any(rDispatchProvider
) },
898 { "ModuleIdentifier", Any(rModuleIdentifier
) },
899 { "Frame", Any(m_xFrame
) },
900 { "InToolbar", Any(!m_bHasMenuBar
) }
903 Reference
< XPopupMenuController
> xPopupMenuController(
904 m_xPopupMenuControllerFactory
->createInstanceWithArgumentsAndContext(
910 if ( xPopupMenuController
.is() )
912 // Provide our awt popup menu to the popup menu controller
913 pMenuItemHandler
->xPopupMenuController
= xPopupMenuController
;
914 xPopupMenuController
->setPopupMenu( pMenuItemHandler
->xPopupMenu
);
921 void MenuBarManager::FillMenuManager( Menu
* pMenu
, const Reference
< XFrame
>& rFrame
,
922 const Reference
< XDispatchProvider
>& rDispatchProvider
,
923 const OUString
& rModuleIdentifier
, bool bDelete
)
927 m_bDeleteMenu
= bDelete
;
929 m_xDispatchProvider
= rDispatchProvider
;
931 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
932 m_bShowMenuImages
= rSettings
.GetUseImagesInMenus();
933 m_bRetrieveImages
= false;
935 // Set module identifier when provided from outside
936 if (!rModuleIdentifier
.isEmpty())
937 m_aModuleIdentifier
= rModuleIdentifier
;
939 m_aModuleIdentifier
= vcl::CommandInfoProvider::GetModuleIdentifier(m_xFrame
);
941 // Add root as ui configuration listener
942 RetrieveImageManagers();
944 if ( pMenu
->IsMenuBar() && rFrame
.is() )
946 // First merge all addon popup menus into our structure
948 for ( nPos
= 0; nPos
< pMenu
->GetItemCount(); nPos
++ )
950 sal_uInt16 nItemId
= pMenu
->GetItemId( nPos
);
951 OUString aCommand
= pMenu
->GetItemCommand( nItemId
);
952 if ( aCommand
== aSpecialWindowCommand
|| aCommand
== aCmdHelpMenu
)
954 // Retrieve addon popup menus and add them to our menu bar
955 framework::AddonMenuManager::MergeAddonPopupMenus( rFrame
, nPos
, static_cast<MenuBar
*>(pMenu
) );
960 // Merge the Add-Ons help menu items into the Office help menu
961 framework::AddonMenuManager::MergeAddonHelpMenu( rFrame
, static_cast<MenuBar
*>(pMenu
) );
964 bool bAccessibilityEnabled( Application::GetSettings().GetMiscSettings().GetEnableATToolSupport() );
965 sal_uInt16 nItemCount
= pMenu
->GetItemCount();
966 OUString aItemCommand
;
967 m_aMenuItemHandlerVector
.reserve(nItemCount
);
968 for ( sal_uInt16 i
= 0; i
< nItemCount
; i
++ )
970 sal_uInt16 nItemId
= FillItemCommand(aItemCommand
,pMenu
, i
);
972 if (( pMenu
->IsMenuBar() || bAccessibilityEnabled
) &&
973 ( pMenu
->GetItemText( nItemId
).isEmpty() ))
975 if ( !aItemCommand
.isEmpty() )
976 pMenu
->SetItemText( nItemId
, RetrieveLabelFromCommand( aItemCommand
));
979 // Command can be just an alias to another command.
980 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(aItemCommand
, m_aModuleIdentifier
);
981 OUString aRealCommand
= vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties
);
982 if ( !aRealCommand
.isEmpty() )
983 aItemCommand
= aRealCommand
;
985 Reference
< XDispatch
> xDispatch
;
986 VclPtr
<PopupMenu
> pPopup
= pMenu
->GetPopupMenu( nItemId
);
987 // overwrite the show icons on menu option?
988 MenuItemBits nBits
= pMenu
->GetItemBits( nItemId
) & ( MenuItemBits::ICON
| MenuItemBits::TEXT
);
989 bool bItemShowMenuImages
= ( m_bShowMenuImages
&& nBits
!= MenuItemBits::TEXT
) || nBits
& MenuItemBits::ICON
;
993 // Retrieve module identifier from Help Command entry
994 OUString
aModuleIdentifier( rModuleIdentifier
);
995 if (!pMenu
->GetHelpCommand(nItemId
).isEmpty())
997 aModuleIdentifier
= pMenu
->GetHelpCommand( nItemId
);
998 pMenu
->SetHelpCommand( nItemId
, "" );
1001 // Retrieve possible attributes struct
1002 Reference
< XDispatchProvider
> xPopupMenuDispatchProvider( rDispatchProvider
);
1003 MenuAttributes
* pAttributes
= static_cast<MenuAttributes
*>(pMenu
->GetUserValue( nItemId
));
1005 xPopupMenuDispatchProvider
= pAttributes
->xDispatchProvider
;
1007 if ( m_xPopupMenuControllerFactory
.is() &&
1008 m_xPopupMenuControllerFactory
->hasController( aItemCommand
, aModuleIdentifier
)
1011 // Check if we have to create a popup menu for a uno based popup menu controller.
1012 // We have to set an empty popup menu into our menu structure so the controller also
1013 // works with inplace OLE.
1014 MenuItemHandler
* pItemHandler
= new MenuItemHandler( nItemId
, nullptr, xDispatch
);
1015 rtl::Reference
<VCLXPopupMenu
> pVCLXPopupMenu
= new VCLXPopupMenu(pPopup
);
1016 pItemHandler
->xPopupMenu
= pVCLXPopupMenu
;
1017 pItemHandler
->aMenuItemURL
= aItemCommand
;
1018 m_aMenuItemHandlerVector
.push_back( std::unique_ptr
<MenuItemHandler
>(pItemHandler
) );
1020 if ( bAccessibilityEnabled
|| pMenu
->IsMenuBar())
1022 if ( CreatePopupMenuController( pItemHandler
, xPopupMenuDispatchProvider
, aModuleIdentifier
))
1023 pItemHandler
->xPopupMenuController
->updatePopupMenu();
1025 lcl_CheckForChildren(pMenu
, nItemId
);
1029 // Check if this is the tools menu. Add menu item if needed
1030 if ( aItemCommand
== aCmdToolsMenu
&& AddonMenuManager::HasAddonMenuElements() )
1032 // Create addon popup menu if there exist elements and this is the tools popup menu
1033 VclPtr
<PopupMenu
> pSubMenu
= AddonMenuManager::CreateAddonMenu(rFrame
);
1034 if ( pSubMenu
&& ( pSubMenu
->GetItemCount() > 0 ))
1036 if ( pPopup
->GetItemType( pPopup
->GetItemCount() - 1 ) != MenuItemType::SEPARATOR
)
1037 pPopup
->InsertSeparator();
1039 pPopup
->InsertItem( ITEMID_ADDONLIST
, OUString() );
1040 pPopup
->SetPopupMenu( ITEMID_ADDONLIST
, pSubMenu
);
1041 pPopup
->SetItemCommand( ITEMID_ADDONLIST
, ".uno:Addons" );
1044 pSubMenu
.disposeAndClear();
1047 rtl::Reference
<MenuBarManager
> pSubMenuManager
= new MenuBarManager( m_xContext
, rFrame
, m_xURLTransformer
,
1048 xPopupMenuDispatchProvider
, aModuleIdentifier
, pPopup
, false, m_bHasMenuBar
);
1050 AddMenu(pSubMenuManager
.get(), aItemCommand
, nItemId
);
1053 else if ( pMenu
->GetItemType( i
) != MenuItemType::SEPARATOR
)
1055 if ( bItemShowMenuImages
)
1056 m_bRetrieveImages
= true;
1058 std::unique_ptr
<MenuItemHandler
> pItemHandler(new MenuItemHandler( nItemId
, nullptr, xDispatch
));
1059 // Retrieve possible attributes struct
1060 MenuAttributes
* pAttributes
= static_cast<MenuAttributes
*>(pMenu
->GetUserValue( nItemId
));
1062 pItemHandler
->aTargetFrame
= pAttributes
->aTargetFrame
;
1063 pItemHandler
->aMenuItemURL
= aItemCommand
;
1065 if ( m_xPopupMenuControllerFactory
.is() &&
1066 m_xPopupMenuControllerFactory
->hasController( aItemCommand
, m_aModuleIdentifier
) )
1068 // Check if we have to create a popup menu for a uno based popup menu controller.
1069 // We have to set an empty popup menu into our menu structure so the controller also
1070 // works with inplace OLE.
1071 rtl::Reference
<VCLXPopupMenu
> pVCLXPopupMenu
= new VCLXPopupMenu
;
1072 PopupMenu
* pPopupMenu
= static_cast<PopupMenu
*>(pVCLXPopupMenu
->GetMenu());
1073 pMenu
->SetPopupMenu( pItemHandler
->nItemId
, pPopupMenu
);
1074 pItemHandler
->xPopupMenu
= pVCLXPopupMenu
;
1076 if ( bAccessibilityEnabled
&& CreatePopupMenuController( pItemHandler
.get(), m_xDispatchProvider
, m_aModuleIdentifier
) )
1078 pItemHandler
->xPopupMenuController
->updatePopupMenu();
1081 lcl_CheckForChildren(pMenu
, pItemHandler
->nItemId
);
1084 m_aMenuItemHandlerVector
.push_back( std::move(pItemHandler
) );
1088 if ( m_bHasMenuBar
&& bAccessibilityEnabled
)
1090 RetrieveShortcuts( m_aMenuItemHandlerVector
);
1091 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
1093 // Set key code, workaround for hard-coded shortcut F1 mapped to .uno:HelpIndex
1094 // Only non-popup menu items can have a short-cut
1095 if ( menuItemHandler
->aMenuItemURL
== aCmdHelpIndex
)
1097 vcl::KeyCode
aKeyCode( KEY_F1
);
1098 pMenu
->SetAccelKey( menuItemHandler
->nItemId
, aKeyCode
);
1100 else if ( pMenu
->GetPopupMenu( menuItemHandler
->nItemId
) == nullptr )
1101 pMenu
->SetAccelKey( menuItemHandler
->nItemId
, menuItemHandler
->aKeyCode
);
1108 void MenuBarManager::impl_RetrieveShortcutsFromConfiguration(
1109 const Reference
< XAcceleratorConfiguration
>& rAccelCfg
,
1110 const Sequence
< OUString
>& rCommands
,
1111 std::vector
< std::unique_ptr
<MenuItemHandler
> >& aMenuShortCuts
)
1113 if ( !rAccelCfg
.is() )
1118 css::awt::KeyEvent aKeyEvent
;
1119 Sequence
< Any
> aSeqKeyCode
= rAccelCfg
->getPreferredKeyEventsForCommandList( rCommands
);
1120 for ( sal_Int32 i
= 0; i
< aSeqKeyCode
.getLength(); i
++ )
1122 if ( aSeqKeyCode
[i
] >>= aKeyEvent
)
1123 aMenuShortCuts
[i
]->aKeyCode
= svt::AcceleratorExecute::st_AWTKey2VCLKey( aKeyEvent
);
1126 catch ( const IllegalArgumentException
& )
1131 void MenuBarManager::RetrieveShortcuts( std::vector
< std::unique_ptr
<MenuItemHandler
> >& aMenuShortCuts
)
1133 Reference
< XAcceleratorConfiguration
> xDocAccelCfg( m_xDocAcceleratorManager
);
1134 Reference
< XAcceleratorConfiguration
> xModuleAccelCfg( m_xModuleAcceleratorManager
);
1135 Reference
< XAcceleratorConfiguration
> xGlobalAccelCfg( m_xGlobalAcceleratorManager
);
1137 if ( !m_bAcceleratorCfg
)
1139 // Retrieve references on demand
1140 m_bAcceleratorCfg
= true;
1141 if ( !xDocAccelCfg
.is() )
1143 Reference
< XController
> xController
= m_xFrame
->getController();
1144 Reference
< XModel
> xModel
;
1145 if ( xController
.is() )
1147 xModel
= xController
->getModel();
1150 Reference
< XUIConfigurationManagerSupplier
> xSupplier( xModel
, UNO_QUERY
);
1151 if ( xSupplier
.is() )
1153 Reference
< XUIConfigurationManager
> xDocUICfgMgr
= xSupplier
->getUIConfigurationManager();
1154 if ( xDocUICfgMgr
.is() )
1156 xDocAccelCfg
= xDocUICfgMgr
->getShortCutManager();
1157 m_xDocAcceleratorManager
= xDocAccelCfg
;
1164 if ( !xModuleAccelCfg
.is() )
1166 Reference
< XModuleUIConfigurationManagerSupplier
> xModuleCfgMgrSupplier
=
1167 theModuleUIConfigurationManagerSupplier::get( m_xContext
);
1170 Reference
< XUIConfigurationManager
> xUICfgMgr
= xModuleCfgMgrSupplier
->getUIConfigurationManager( m_aModuleIdentifier
);
1171 if ( xUICfgMgr
.is() )
1173 xModuleAccelCfg
= xUICfgMgr
->getShortCutManager();
1174 m_xModuleAcceleratorManager
= xModuleAccelCfg
;
1177 catch ( const RuntimeException
& )
1181 catch ( const Exception
& )
1186 if ( !xGlobalAccelCfg
.is() ) try
1188 xGlobalAccelCfg
= GlobalAcceleratorConfiguration::create( m_xContext
);
1189 m_xGlobalAcceleratorManager
= xGlobalAccelCfg
;
1191 catch ( const css::uno::DeploymentException
& )
1193 SAL_WARN("fwk.uielement", "GlobalAcceleratorConfiguration"
1194 " not available. This should happen only on mobile platforms.");
1198 vcl::KeyCode aEmptyKeyCode
;
1199 Sequence
< OUString
> aSeq( aMenuShortCuts
.size() );
1200 auto aSeqRange
= asNonConstRange(aSeq
);
1201 const sal_uInt32 nCount
= aMenuShortCuts
.size();
1202 for ( sal_uInt32 i
= 0; i
< nCount
; ++i
)
1204 aSeqRange
[i
] = aMenuShortCuts
[i
]->aMenuItemURL
;
1205 aMenuShortCuts
[i
]->aKeyCode
= aEmptyKeyCode
;
1208 if ( m_xGlobalAcceleratorManager
.is() )
1209 impl_RetrieveShortcutsFromConfiguration( xGlobalAccelCfg
, aSeq
, aMenuShortCuts
);
1210 if ( m_xModuleAcceleratorManager
.is() )
1211 impl_RetrieveShortcutsFromConfiguration( xModuleAccelCfg
, aSeq
, aMenuShortCuts
);
1212 if ( m_xDocAcceleratorManager
.is() )
1213 impl_RetrieveShortcutsFromConfiguration( xDocAccelCfg
, aSeq
, aMenuShortCuts
);
1216 void MenuBarManager::RetrieveImageManagers()
1218 if ( !m_xDocImageManager
.is() )
1220 Reference
< XController
> xController
= m_xFrame
->getController();
1221 Reference
< XModel
> xModel
;
1222 if ( xController
.is() )
1224 xModel
= xController
->getModel();
1227 Reference
< XUIConfigurationManagerSupplier
> xSupplier( xModel
, UNO_QUERY
);
1228 if ( xSupplier
.is() )
1230 Reference
< XUIConfigurationManager
> xDocUICfgMgr
= xSupplier
->getUIConfigurationManager();
1231 m_xDocImageManager
.set( xDocUICfgMgr
->getImageManager(), UNO_QUERY
);
1232 m_xDocImageManager
->addConfigurationListener(
1233 Reference
< XUIConfigurationListener
>(this) );
1239 if ( !m_xModuleImageManager
.is() )
1241 Reference
< XModuleUIConfigurationManagerSupplier
> xModuleCfgMgrSupplier
=
1242 theModuleUIConfigurationManagerSupplier::get( m_xContext
);
1243 Reference
< XUIConfigurationManager
> xUICfgMgr
= xModuleCfgMgrSupplier
->getUIConfigurationManager( m_aModuleIdentifier
);
1244 m_xModuleImageManager
.set( xUICfgMgr
->getImageManager(), UNO_QUERY
);
1245 m_xModuleImageManager
->addConfigurationListener( Reference
< XUIConfigurationListener
>(this) );
1249 void MenuBarManager::FillMenuWithConfiguration(
1252 const OUString
& rModuleIdentifier
,
1253 const Reference
< XIndexAccess
>& rItemContainer
,
1254 const Reference
< XURLTransformer
>& rTransformer
)
1256 Reference
< XDispatchProvider
> xEmptyDispatchProvider
;
1257 MenuBarManager::FillMenu( nId
, pMenu
, rModuleIdentifier
, rItemContainer
, xEmptyDispatchProvider
);
1259 // Merge add-on menu entries into the menu bar
1260 MenuBarManager::MergeAddonMenus( pMenu
,
1261 AddonsOptions().GetMergeMenuInstructions(),
1262 rModuleIdentifier
);
1264 bool bHasDisabledEntries
= SvtCommandOptions().HasEntriesDisabled();
1265 if ( !bHasDisabledEntries
)
1268 sal_uInt16 nCount
= pMenu
->GetItemCount();
1269 for ( sal_uInt16 i
= 0; i
< nCount
; i
++ )
1271 sal_uInt16 nID
= pMenu
->GetItemId( i
);
1274 PopupMenu
* pPopupMenu
= pMenu
->GetPopupMenu( nID
);
1277 if ( MustBeHidden( pPopupMenu
, rTransformer
))
1278 pMenu
->HideItem( nId
);
1284 void MenuBarManager::FillMenu(
1287 const OUString
& rModuleIdentifier
,
1288 const Reference
< XIndexAccess
>& rItemContainer
,
1289 const Reference
< XDispatchProvider
>& rDispatchProvider
)
1291 // Fill menu bar with container contents
1292 for ( sal_Int32 n
= 0; n
< rItemContainer
->getCount(); n
++ )
1294 Sequence
< PropertyValue
> aProps
;
1295 OUString aCommandURL
;
1297 OUString
aModuleIdentifier( rModuleIdentifier
);
1298 sal_uInt16 nType
= 0;
1299 Reference
< XIndexAccess
> xIndexContainer
;
1300 Reference
< XDispatchProvider
> xDispatchProvider( rDispatchProvider
);
1301 sal_Int16 nStyle
= 0;
1304 if ( rItemContainer
->getByIndex( n
) >>= aProps
)
1307 bool bEnabled
= true;
1309 for (beans::PropertyValue
const& rProp
: aProps
)
1311 OUString aPropName
= rProp
.Name
;
1312 if ( aPropName
== "CommandURL" )
1313 rProp
.Value
>>= aCommandURL
;
1314 else if ( aPropName
== "ItemDescriptorContainer" )
1315 rProp
.Value
>>= xIndexContainer
;
1316 else if ( aPropName
== "Label" )
1317 rProp
.Value
>>= aLabel
;
1318 else if ( aPropName
== "Type" )
1319 rProp
.Value
>>= nType
;
1320 else if ( aPropName
== "ModuleIdentifier" )
1321 rProp
.Value
>>= aModuleIdentifier
;
1322 else if ( aPropName
== "DispatchProvider" )
1323 rProp
.Value
>>= xDispatchProvider
;
1324 else if ( aPropName
== "Style" )
1325 rProp
.Value
>>= nStyle
;
1326 else if ( aPropName
== "IsVisible" )
1327 rProp
.Value
>>= bShow
;
1328 else if ( aPropName
== "Enabled" )
1329 rProp
.Value
>>= bEnabled
;
1332 if (!aCommandURL
.isEmpty() && vcl::CommandInfoProvider::IsExperimental(aCommandURL
, rModuleIdentifier
) &&
1333 !officecfg::Office::Common::Misc::ExperimentalMode::get())
1338 if ( nType
== css::ui::ItemType::DEFAULT
)
1340 pMenu
->InsertItem( nId
, aLabel
);
1341 pMenu
->SetItemCommand( nId
, aCommandURL
);
1345 MenuItemBits nBits
= pMenu
->GetItemBits( nId
);
1346 if ( nStyle
& css::ui::ItemStyle::ICON
)
1347 nBits
|= MenuItemBits::ICON
;
1348 if ( nStyle
& css::ui::ItemStyle::TEXT
)
1349 nBits
|= MenuItemBits::TEXT
;
1350 if ( nStyle
& css::ui::ItemStyle::RADIO_CHECK
)
1351 nBits
|= MenuItemBits::RADIOCHECK
;
1352 pMenu
->SetItemBits( nId
, nBits
);
1356 pMenu
->HideItem( nId
);
1359 pMenu
->EnableItem( nId
, false );
1361 if ( xIndexContainer
.is() )
1363 VclPtr
<PopupMenu
> pNewPopupMenu
= VclPtr
<PopupMenu
>::Create();
1364 pMenu
->SetPopupMenu( nId
, pNewPopupMenu
);
1365 // Use the command URL as the Help ID for the sub menu
1366 pNewPopupMenu
->SetHelpId(aCommandURL
);
1368 if ( xDispatchProvider
.is() )
1370 // Use attributes struct to transport special dispatch provider
1371 void* nAttributePtr
= MenuAttributes::CreateAttribute(xDispatchProvider
);
1372 pMenu
->SetUserValue(nId
, nAttributePtr
, MenuAttributes::ReleaseAttribute
);
1375 // Use help command to transport module identifier
1376 if ( !aModuleIdentifier
.isEmpty() )
1377 pMenu
->SetHelpCommand( nId
, aModuleIdentifier
);
1380 FillMenu( nId
, pNewPopupMenu
, aModuleIdentifier
, xIndexContainer
, xDispatchProvider
);
1387 pMenu
->InsertSeparator();
1392 catch ( const IndexOutOfBoundsException
& )
1399 void MenuBarManager::MergeAddonMenus(
1401 const MergeMenuInstructionContainer
& aMergeInstructionContainer
,
1402 const OUString
& rModuleIdentifier
)
1404 // set start value for the item ID for the new addon menu items
1405 sal_uInt16 nItemId
= ADDONMENU_MERGE_ITEMID_START
;
1407 const sal_uInt32 nCount
= aMergeInstructionContainer
.size();
1408 for ( sal_uInt32 i
= 0; i
< nCount
; i
++ )
1410 const MergeMenuInstruction
& rMergeInstruction
= aMergeInstructionContainer
[i
];
1412 if ( MenuBarMerger::IsCorrectContext( rMergeInstruction
.aMergeContext
, rModuleIdentifier
))
1414 ::std::vector
< OUString
> aMergePath
;
1416 // retrieve the merge path from the merge point string
1417 MenuBarMerger::RetrieveReferencePath( rMergeInstruction
.aMergePoint
, aMergePath
);
1419 // convert the sequence/sequence property value to a more convenient vector<>
1420 AddonMenuContainer aMergeMenuItems
;
1421 MenuBarMerger::GetSubMenu( rMergeInstruction
.aMergeMenu
, aMergeMenuItems
);
1423 // try to find the reference point for our merge operation
1424 Menu
* pMenu
= pMenuBar
;
1425 ReferencePathInfo aResult
= MenuBarMerger::FindReferencePath( aMergePath
, pMenu
);
1427 if ( aResult
.eResult
== RP_OK
)
1429 // normal merge operation
1430 MenuBarMerger::ProcessMergeOperation( aResult
.pPopupMenu
,
1433 rMergeInstruction
.aMergeCommand
,
1434 rMergeInstruction
.aMergeCommandParameter
,
1441 MenuBarMerger::ProcessFallbackOperation( aResult
,
1443 rMergeInstruction
.aMergeCommand
,
1444 rMergeInstruction
.aMergeFallback
,
1453 void MenuBarManager::SetItemContainer( const Reference
< XIndexAccess
>& rItemContainer
)
1455 SolarMutexGuard aSolarMutexGuard
;
1457 Reference
< XFrame
> xFrame
= m_xFrame
;
1459 // Clear MenuBarManager structures
1461 // Check active state as we cannot change our VCL menu during activation by the user
1464 m_xDeferredItemContainer
= rItemContainer
;
1469 m_aMenuItemHandlerVector
.clear();
1470 m_pVCLMenu
->Clear();
1474 // Fill menu bar with container contents
1475 FillMenuWithConfiguration( nId
, m_pVCLMenu
, m_aModuleIdentifier
, rItemContainer
, m_xURLTransformer
);
1477 // Refill menu manager again
1478 Reference
< XDispatchProvider
> xDispatchProvider
;
1479 FillMenuManager( m_pVCLMenu
, xFrame
, xDispatchProvider
, m_aModuleIdentifier
, false );
1481 // add itself as frame action listener
1482 m_xFrame
->addFrameActionListener( Reference
< XFrameActionListener
>(this) );
1486 void MenuBarManager::GetPopupController( PopupControllerCache
& rPopupController
)
1489 SolarMutexGuard aSolarMutexGuard
;
1491 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
1493 if ( menuItemHandler
->xPopupMenuController
.is() )
1495 Reference
< XDispatchProvider
> xDispatchProvider( menuItemHandler
->xPopupMenuController
, UNO_QUERY
);
1497 PopupControllerEntry aPopupControllerEntry
;
1498 aPopupControllerEntry
.m_xDispatchProvider
= xDispatchProvider
;
1500 // Just use the main part of the URL for popup menu controllers
1501 sal_Int32
nSchemePart( 0 );
1502 OUString
aMenuURL( menuItemHandler
->aMenuItemURL
);
1504 nSchemePart
= aMenuURL
.indexOf( ':' );
1505 if (( nSchemePart
> 0 ) &&
1506 ( aMenuURL
.getLength() > ( nSchemePart
+1 )))
1508 OUString
aMainURL( "vnd.sun.star.popup:" );
1509 sal_Int32 nQueryPart
= aMenuURL
.indexOf( '?', nSchemePart
);
1510 if ( nQueryPart
> 0 )
1511 aMainURL
+= aMenuURL
.subView( nSchemePart
, nQueryPart
-nSchemePart
);
1512 else if ( nQueryPart
== -1 )
1513 aMainURL
+= aMenuURL
.subView( nSchemePart
+1 );
1515 rPopupController
.emplace( aMainURL
, aPopupControllerEntry
);
1518 if ( menuItemHandler
->xSubMenuManager
)
1520 menuItemHandler
->xSubMenuManager
->GetPopupController( rPopupController
);
1525 void MenuBarManager::AddMenu(MenuBarManager
* pSubMenuManager
,const OUString
& _sItemCommand
,sal_uInt16 _nItemId
)
1527 Reference
< XStatusListener
> xSubMenuManager( pSubMenuManager
);
1528 m_xFrame
->addFrameActionListener( Reference
< XFrameActionListener
>( xSubMenuManager
, UNO_QUERY
));
1530 std::unique_ptr
<MenuItemHandler
> pMenuItemHandler(new MenuItemHandler(
1533 Reference
<XDispatch
>() ));
1534 pMenuItemHandler
->aMenuItemURL
= _sItemCommand
;
1535 m_aMenuItemHandlerVector
.push_back( std::move(pMenuItemHandler
) );
1538 sal_uInt16
MenuBarManager::FillItemCommand(OUString
& _rItemCommand
, Menu
* _pMenu
,sal_uInt16 _nIndex
) const
1540 sal_uInt16 nItemId
= _pMenu
->GetItemId( _nIndex
);
1542 _rItemCommand
= _pMenu
->GetItemCommand( nItemId
);
1543 if ( _rItemCommand
.isEmpty() )
1545 _rItemCommand
= "slot:" + OUString::number( nItemId
);
1546 _pMenu
->SetItemCommand( nItemId
, _rItemCommand
);
1551 void MenuBarManager::SetHdl()
1553 m_pVCLMenu
->SetActivateHdl( LINK( this, MenuBarManager
, Activate
));
1554 m_pVCLMenu
->SetDeactivateHdl( LINK( this, MenuBarManager
, Deactivate
));
1555 m_pVCLMenu
->SetSelectHdl( LINK( this, MenuBarManager
, Select
));
1557 if ( !m_xURLTransformer
.is() && m_xContext
.is() )
1558 m_xURLTransformer
.set( URLTransformer::create( m_xContext
) );
1561 void MenuBarManager::FillMenuImages(Reference
< XFrame
> const & _xFrame
, Menu
* _pMenu
,bool bShowMenuImages
)
1563 AddonsOptions aAddonOptions
;
1565 for ( sal_uInt16 nPos
= 0; nPos
< _pMenu
->GetItemCount(); nPos
++ )
1567 sal_uInt16 nId
= _pMenu
->GetItemId( nPos
);
1568 if ( _pMenu
->GetItemType( nPos
) != MenuItemType::SEPARATOR
)
1570 // overwrite the show icons on menu option?
1571 MenuItemBits nBits
= _pMenu
->GetItemBits( nId
) & ( MenuItemBits::ICON
| MenuItemBits::TEXT
);
1572 bool bTmpShowMenuImages
= ( bShowMenuImages
&& nBits
!= MenuItemBits::TEXT
) || nBits
& MenuItemBits::ICON
;
1574 if ( bTmpShowMenuImages
)
1576 OUString aMenuItemCommand
= _pMenu
->GetItemCommand( nId
);
1577 Image aImage
= vcl::CommandInfoProvider::GetImageForCommand(aMenuItemCommand
, _xFrame
);
1579 aImage
= Image(aAddonOptions
.GetImageFromURL(aMenuItemCommand
, false));
1581 _pMenu
->SetItemImage( nId
, aImage
);
1584 _pMenu
->SetItemImage( nId
, Image() );
1591 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */