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>
51 #include <toolkit/helper/vclunohelper.hxx>
53 #include <vcl/svapp.hxx>
54 #include <vcl/sysdata.hxx>
55 #include <vcl/menu.hxx>
56 #include <vcl/settings.hxx>
57 #include <vcl/commandinfoprovider.hxx>
58 #include <vcl/window.hxx>
59 #include <sal/log.hxx>
60 #include <svtools/acceleratorexecute.hxx>
61 #include <svtools/miscopt.hxx>
62 #include <uielement/menubarmerger.hxx>
63 #include <tools/urlobj.hxx>
65 using namespace ::cppu
;
66 using namespace ::com::sun::star
;
67 using namespace ::com::sun::star::uno
;
68 using namespace ::com::sun::star::util
;
69 using namespace ::com::sun::star::beans
;
70 using namespace ::com::sun::star::frame
;
71 using namespace ::com::sun::star::container
;
72 using namespace ::com::sun::star::lang
;
73 using namespace ::com::sun::star::ui
;
75 const sal_uInt16 ADDONMENU_MERGE_ITEMID_START
= 1500;
76 const sal_uInt16 ITEMID_ADDONLIST
= 6678; // used to be a SID in sfx2, now just a unique id...
81 constexpr OUString aCmdHelpIndex
= u
".uno:HelpIndex"_ustr
;
82 constexpr OUStringLiteral aCmdToolsMenu
= u
".uno:ToolsMenu";
83 constexpr OUStringLiteral aCmdHelpMenu
= u
".uno:HelpMenu";
84 constexpr OUStringLiteral aSpecialWindowCommand
= u
".uno:WindowList";
86 MenuBarManager::MenuBarManager(
87 const Reference
< XComponentContext
>& rxContext
,
88 const Reference
< XFrame
>& rFrame
,
89 const Reference
< XURLTransformer
>& _xURLTransformer
,
90 const Reference
< XDispatchProvider
>& rDispatchProvider
,
91 const OUString
& rModuleIdentifier
,
92 Menu
* pMenu
, bool bDelete
, bool bHasMenuBar
):
93 m_bRetrieveImages( false )
94 , m_bAcceleratorCfg( false )
95 , m_bHasMenuBar( bHasMenuBar
)
96 , m_xContext(rxContext
)
97 , m_xURLTransformer(_xURLTransformer
)
98 , m_sIconTheme( SvtMiscOptions::GetIconTheme() )
99 , m_aAsyncSettingsTimer( "framework::MenuBarManager::Deactivate m_aAsyncSettingsTimer" )
101 m_xPopupMenuControllerFactory
= frame::thePopupMenuControllerFactory::get(m_xContext
);
102 FillMenuManager( pMenu
, rFrame
, rDispatchProvider
, rModuleIdentifier
, bDelete
);
105 Any SAL_CALL
MenuBarManager::getMenuHandle( const Sequence
< sal_Int8
>& /*ProcessId*/, sal_Int16 SystemType
)
107 SolarMutexGuard aSolarGuard
;
110 throw css::lang::DisposedException();
116 SystemMenuData aSystemMenuData
;
118 m_pVCLMenu
->GetSystemMenuData(aSystemMenuData
);
120 if( SystemType
== SystemDependent::SYSTEM_WIN32
)
123 reinterpret_cast<sal_IntPtr
>(aSystemMenuData
.hMenu
));
133 MenuBarManager::~MenuBarManager()
135 // stop asynchronous settings timer
136 m_xDeferredItemContainer
.clear();
137 m_aAsyncSettingsTimer
.Stop();
139 SAL_WARN_IF( OWeakObject::m_refCount
!= 0, "fwk.uielement", "Who wants to delete an object with refcount > 0!" );
143 void MenuBarManager::disposing(std::unique_lock
<std::mutex
>& )
145 Reference
< XComponent
> xThis( this );
149 // stop asynchronous settings timer and
150 // release deferred item container reference
151 m_aAsyncSettingsTimer
.Stop();
152 m_xDeferredItemContainer
.clear();
155 m_aMenuItemHandlerVector
.clear();
159 m_pVCLMenu
.disposeAndClear();
162 if ( m_xDocImageManager
.is() )
166 m_xDocImageManager
->removeConfigurationListener(
167 Reference
< XUIConfigurationListener
>(this) );
169 catch ( const Exception
& )
173 if ( m_xModuleImageManager
.is() )
177 m_xModuleImageManager
->removeConfigurationListener(
178 Reference
< XUIConfigurationListener
>(this) );
180 catch ( const Exception
& )
184 m_xDocImageManager
.clear();
185 m_xModuleImageManager
.clear();
186 m_xGlobalAcceleratorManager
.clear();
187 m_xModuleAcceleratorManager
.clear();
188 m_xDocAcceleratorManager
.clear();
189 m_xPopupMenuControllerFactory
.clear();
193 void SAL_CALL
MenuBarManager::elementInserted( const css::ui::ConfigurationEvent
& Event
)
197 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
201 sal_Int16 nImageType
= sal_Int16();
202 if (( Event
.aInfo
>>= nImageType
) && nImageType
== 0 )
206 void SAL_CALL
MenuBarManager::elementRemoved( const css::ui::ConfigurationEvent
& Event
)
208 elementInserted(Event
);
211 void SAL_CALL
MenuBarManager::elementReplaced( const css::ui::ConfigurationEvent
& Event
)
213 elementInserted(Event
);
216 // XFrameActionListener
217 void SAL_CALL
MenuBarManager::frameAction( const FrameActionEvent
& Action
)
222 throw css::lang::DisposedException();
224 if ( Action
.Action
!= FrameAction_CONTEXT_CHANGED
)
227 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
229 // Clear dispatch reference as we will requery it later
230 if ( menuItemHandler
->xMenuItemDispatch
.is() )
233 aTargetURL
.Complete
= menuItemHandler
->aMenuItemURL
;
234 m_xURLTransformer
->parseStrict( aTargetURL
);
236 menuItemHandler
->xMenuItemDispatch
->removeStatusListener( this, aTargetURL
);
238 menuItemHandler
->xMenuItemDispatch
.clear();
243 void SAL_CALL
MenuBarManager::statusChanged( const FeatureStateEvent
& Event
)
245 OUString aFeatureURL
= Event
.FeatureURL
.Complete
;
247 SolarMutexGuard aSolarGuard
;
252 // We have to check all menu entries as there can be identical entries in a popup menu.
253 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
255 if ( menuItemHandler
->aParsedItemURL
== aFeatureURL
)
257 bool bCheckmark( false );
258 bool bMenuItemEnabled( m_pVCLMenu
->IsItemEnabled( menuItemHandler
->nItemId
));
259 bool bEnabledItem( Event
.IsEnabled
);
261 status::Visibility aVisibilityStatus
;
264 //enable some slots hardly, because UNIX clipboard does not notify all changes
265 // Can be removed if follow up task will be fixed directly within applications.
266 // Note: PasteSpecial is handled specifically by calc
267 // Calc also disables Paste under some circumstances, do not override.
268 /* TODO: is this workaround even needed anymore? Was introduced
269 * in 2009 with commit 426ab2c0e8f6e3fe2b766f74f6b8da873d860260
270 * as some "metropatch" and the other places it touched seem to
272 if ( (menuItemHandler
->aMenuItemURL
== ".uno:Paste" &&
273 m_aModuleIdentifier
!= "com.sun.star.sheet.SpreadsheetDocument")
274 || menuItemHandler
->aMenuItemURL
== ".uno:PasteClipboard" ) // special for draw/impress
278 // Enable/disable item
279 if ( bEnabledItem
!= bMenuItemEnabled
)
281 m_pVCLMenu
->EnableItem( menuItemHandler
->nItemId
, bEnabledItem
);
283 // Remove "checked" mark for disabled menu items.
284 // Initially disabled but checkable menu items do not receive
285 // checked/unchecked state, so can appear inconsistently after
286 // enabling/disabling. Since we can not pass checked state for disabled
287 // items, we will just reset checked state for them, anyway correct state
288 // will be transferred from controller once item enabled.
289 if ( !bEnabledItem
&& m_pVCLMenu
->IsItemChecked( menuItemHandler
->nItemId
) )
290 m_pVCLMenu
->CheckItem( menuItemHandler
->nItemId
, false );
293 if ( Event
.State
>>= bCheckmark
)
295 // Checkmark or RadioButton
296 m_pVCLMenu
->CheckItem( menuItemHandler
->nItemId
, bCheckmark
);
297 // If not already designated RadioButton set as CheckMark
298 MenuItemBits nBits
= m_pVCLMenu
->GetItemBits( menuItemHandler
->nItemId
);
299 if (!(nBits
& MenuItemBits::RADIOCHECK
))
300 m_pVCLMenu
->SetItemBits( menuItemHandler
->nItemId
, nBits
| MenuItemBits::CHECKABLE
);
302 if ( menuItemHandler
->bMadeInvisible
)
303 m_pVCLMenu
->ShowItem( menuItemHandler
->nItemId
);
305 else if ( Event
.State
>>= aItemText
)
307 INetURLObject
aURL( aFeatureURL
);
308 OUString aEnumPart
= aURL
.GetURLPath().getToken( 1, '.' );
309 if ( !aEnumPart
.isEmpty() && aURL
.GetProtocol() == INetProtocol::Uno
)
311 // Checkmark or RadioButton
312 m_pVCLMenu
->CheckItem( menuItemHandler
->nItemId
, aItemText
== aEnumPart
);
313 // If not already designated RadioButton set as CheckMark
314 MenuItemBits nBits
= m_pVCLMenu
->GetItemBits( menuItemHandler
->nItemId
);
315 if (!(nBits
& MenuItemBits::RADIOCHECK
))
316 m_pVCLMenu
->SetItemBits( menuItemHandler
->nItemId
, nBits
| MenuItemBits::CHECKABLE
);
320 // Replacement for place holders
321 if ( aItemText
.startsWith("($1)") )
323 aItemText
= FwkResId(STR_UPDATEDOC
) + " " + aItemText
.subView( 4 );
325 else if ( aItemText
.startsWith("($2)") )
327 aItemText
= FwkResId(STR_CLOSEDOC_ANDRETURN
) + aItemText
.subView( 4 );
329 else if ( aItemText
.startsWith("($3)") )
331 aItemText
= FwkResId(STR_SAVECOPYDOC
) + aItemText
.subView( 4 );
334 m_pVCLMenu
->SetItemText( menuItemHandler
->nItemId
, aItemText
);
337 if ( menuItemHandler
->bMadeInvisible
)
338 m_pVCLMenu
->ShowItem( menuItemHandler
->nItemId
);
340 else if ( Event
.State
>>= aVisibilityStatus
)
343 m_pVCLMenu
->ShowItem( menuItemHandler
->nItemId
, aVisibilityStatus
.bVisible
);
344 menuItemHandler
->bMadeInvisible
= !aVisibilityStatus
.bVisible
;
346 else if ( menuItemHandler
->bMadeInvisible
)
347 m_pVCLMenu
->ShowItem( menuItemHandler
->nItemId
);
352 // Release dispatch object - will be required on the next activate!
353 menuItemHandler
->xMenuItemDispatch
.clear();
359 // Helper to retrieve own structure from item ID
360 MenuBarManager::MenuItemHandler
* MenuBarManager::GetMenuItemHandler( sal_uInt16 nItemId
)
364 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
366 if ( menuItemHandler
->nItemId
== nItemId
)
367 return menuItemHandler
.get();
373 // Helper to set request images flag
374 void MenuBarManager::RequestImages()
377 m_bRetrieveImages
= true;
378 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
380 if ( menuItemHandler
->xSubMenuManager
.is() )
381 menuItemHandler
->xSubMenuManager
->RequestImages();
385 // Helper to reset objects to prepare shutdown
386 void MenuBarManager::RemoveListener()
390 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
392 if ( menuItemHandler
->xMenuItemDispatch
.is() )
395 aTargetURL
.Complete
= menuItemHandler
->aMenuItemURL
;
396 m_xURLTransformer
->parseStrict( aTargetURL
);
398 menuItemHandler
->xMenuItemDispatch
->removeStatusListener(
399 static_cast< XStatusListener
* >( this ), aTargetURL
);
402 menuItemHandler
->xMenuItemDispatch
.clear();
404 if ( menuItemHandler
->xPopupMenu
.is() )
407 // Remove popup menu from menu structure
408 m_pVCLMenu
->SetPopupMenu( menuItemHandler
->nItemId
, nullptr );
411 Reference
< css::lang::XEventListener
> xEventListener( menuItemHandler
->xPopupMenuController
, UNO_QUERY
);
412 if ( xEventListener
.is() )
414 EventObject aEventObject
;
415 aEventObject
.Source
= static_cast<OWeakObject
*>(this);
416 xEventListener
->disposing( aEventObject
);
419 // We now provide a popup menu controller to external code.
420 // Therefore the life-time must be explicitly handled via
424 Reference
< XComponent
> xComponent( menuItemHandler
->xPopupMenuController
, UNO_QUERY
);
425 if ( xComponent
.is() )
426 xComponent
->dispose();
428 catch ( const RuntimeException
& )
432 catch ( const Exception
& )
436 // Release references to controller and popup menu
437 menuItemHandler
->xPopupMenuController
.clear();
438 menuItemHandler
->xPopupMenu
.clear();
441 if ( menuItemHandler
->xSubMenuManager
)
442 menuItemHandler
->xSubMenuManager
->dispose();
448 m_xFrame
->removeFrameActionListener( Reference
< XFrameActionListener
>(this) );
450 catch ( const Exception
& )
457 void SAL_CALL
MenuBarManager::disposing( const EventObject
& Source
)
459 MenuItemHandler
* pMenuItemDisposing
= nullptr;
463 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
465 if ( menuItemHandler
->xMenuItemDispatch
.is() &&
466 menuItemHandler
->xMenuItemDispatch
== Source
.Source
)
468 // disposing called from menu item dispatcher, remove listener
469 pMenuItemDisposing
= menuItemHandler
.get();
474 if ( pMenuItemDisposing
)
476 // Release references to the dispatch object
478 aTargetURL
.Complete
= pMenuItemDisposing
->aMenuItemURL
;
480 m_xURLTransformer
->parseStrict( aTargetURL
);
482 pMenuItemDisposing
->xMenuItemDispatch
->removeStatusListener(
483 static_cast< XStatusListener
* >( this ), aTargetURL
);
484 pMenuItemDisposing
->xMenuItemDispatch
.clear();
485 if ( pMenuItemDisposing
->xPopupMenu
.is() )
487 Reference
< css::lang::XEventListener
> xEventListener( pMenuItemDisposing
->xPopupMenuController
, UNO_QUERY
);
488 if ( xEventListener
.is() )
489 xEventListener
->disposing( Source
);
492 // Remove popup menu from menu structure as we release our reference to
494 m_pVCLMenu
->SetPopupMenu( pMenuItemDisposing
->nItemId
, nullptr );
497 pMenuItemDisposing
->xPopupMenuController
.clear();
498 pMenuItemDisposing
->xPopupMenu
.clear();
502 else if ( Source
.Source
== m_xFrame
)
504 // Our frame gets disposed. We have to remove all our listeners
507 else if ( Source
.Source
== Reference
< XInterface
>( m_xDocImageManager
, UNO_QUERY
))
508 m_xDocImageManager
.clear();
509 else if ( Source
.Source
== Reference
< XInterface
>( m_xModuleImageManager
, UNO_QUERY
))
510 m_xModuleImageManager
.clear();
513 static void lcl_CheckForChildren(Menu
* pMenu
, sal_uInt16 nItemId
)
515 if (PopupMenu
* pThisPopup
= pMenu
->GetPopupMenu( nItemId
))
516 pMenu
->EnableItem( nItemId
, pThisPopup
->GetItemCount() != 0 && pThisPopup
->HasValidEntries(true));
523 class QuietInteractionContext
:
524 public cppu::WeakImplHelper
< css::uno::XCurrentContext
>
527 explicit QuietInteractionContext(
528 css::uno::Reference
< css::uno::XCurrentContext
> context
):
529 context_(std::move(context
)) {}
530 QuietInteractionContext(const QuietInteractionContext
&) = delete;
531 QuietInteractionContext
& operator=(const QuietInteractionContext
&) = delete;
534 virtual ~QuietInteractionContext() override
{}
536 virtual css::uno::Any SAL_CALL
getValueByName(
537 OUString
const & Name
) override
539 return Name
!= JAVA_INTERACTION_HANDLER_NAME
&& context_
.is()
540 ? context_
->getValueByName(Name
)
544 css::uno::Reference
< css::uno::XCurrentContext
>
550 IMPL_LINK( MenuBarManager
, Activate
, Menu
*, pMenu
, bool )
552 if ( pMenu
!= m_pVCLMenu
)
555 css::uno::ContextLayer
layer(
556 new QuietInteractionContext(
557 css::uno::getCurrentContext()));
559 // set/unset hiding disabled menu entries
560 bool bDontHide
= officecfg::Office::Common::View::Menu::DontHideDisabledEntry::get();
561 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
562 bool bShowMenuImages
= rSettings
.GetUseImagesInMenus();
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
606 SetAcceleratorKeys(pMenu
);
610 // Use provided dispatch provider => fallback to frame as dispatch provider
611 Reference
< XDispatchProvider
> xDispatchProvider
;
612 if ( m_xDispatchProvider
.is() )
613 xDispatchProvider
= m_xDispatchProvider
;
615 xDispatchProvider
.set( m_xFrame
, UNO_QUERY
);
617 if ( !xDispatchProvider
.is() )
620 SvtCommandOptions aCmdOptions
;
621 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
625 if ( !menuItemHandler
->xMenuItemDispatch
.is() &&
626 !menuItemHandler
->xSubMenuManager
.is() )
628 Reference
< XDispatch
> xMenuItemDispatch
;
630 aTargetURL
.Complete
= menuItemHandler
->aMenuItemURL
;
632 m_xURLTransformer
->parseStrict( aTargetURL
);
634 if (SvtCommandOptions().HasEntriesDisabled())
636 if ( aCmdOptions
.LookupDisabled( aTargetURL
.Path
))
637 pMenu
->HideItem( menuItemHandler
->nItemId
);
640 if ( aTargetURL
.Complete
.startsWith( ".uno:StyleApply?" ) )
641 xMenuItemDispatch
= new StyleDispatcher( m_xFrame
, m_xURLTransformer
, aTargetURL
);
646 xMenuItemDispatch
= xDispatchProvider
->queryDispatch( aTargetURL
, menuItemHandler
->aTargetFrame
, 0 );
648 catch (uno::Exception
const&)
650 TOOLS_WARN_EXCEPTION("fwk.uielement", "MenuBarManager::Activate(): exception from queryDispatch()");
654 bool bPopupMenu( false );
655 if ( !menuItemHandler
->xPopupMenuController
.is() &&
656 m_xPopupMenuControllerFactory
->hasController( menuItemHandler
->aMenuItemURL
, m_aModuleIdentifier
) )
658 if( xMenuItemDispatch
.is() || menuItemHandler
->aMenuItemURL
!= ".uno:RecentFileList" )
659 bPopupMenu
= CreatePopupMenuController(menuItemHandler
.get(), m_xDispatchProvider
, m_aModuleIdentifier
);
661 if (bPopupMenu
&& menuItemHandler
->xPopupMenuController
.is())
663 if (PopupMenu
* pThisPopup
= pMenu
->GetPopupMenu(menuItemHandler
->nItemId
))
665 pThisPopup
->Activate();
666 pThisPopup
->Deactivate();
670 else if ( menuItemHandler
->xPopupMenuController
.is() )
672 // Force update of popup menu
673 menuItemHandler
->xPopupMenuController
->updatePopupMenu();
675 if (PopupMenu
* pThisPopup
= pMenu
->GetPopupMenu( menuItemHandler
->nItemId
))
677 pThisPopup
->Activate();
678 pThisPopup
->Deactivate();
681 lcl_CheckForChildren(pMenu
, menuItemHandler
->nItemId
);
683 if ( xMenuItemDispatch
.is() )
685 menuItemHandler
->xMenuItemDispatch
= xMenuItemDispatch
;
686 menuItemHandler
->aParsedItemURL
= aTargetURL
.Complete
;
690 xMenuItemDispatch
->addStatusListener( static_cast< XStatusListener
* >( this ), aTargetURL
);
691 // For the menubar, we have to keep status listening to support Ubuntu's HUD.
692 if ( !m_bHasMenuBar
)
693 xMenuItemDispatch
->removeStatusListener( static_cast< XStatusListener
* >( this ), aTargetURL
);
696 else if ( !bPopupMenu
)
697 pMenu
->EnableItem( menuItemHandler
->nItemId
, false );
699 else if ( menuItemHandler
->xPopupMenuController
.is() )
701 // Force update of popup menu
702 menuItemHandler
->xPopupMenuController
->updatePopupMenu();
703 if (PopupMenu
* pThisPopup
= pMenu
->GetPopupMenu(menuItemHandler
->nItemId
))
705 pThisPopup
->Activate();
706 pThisPopup
->Deactivate();
708 lcl_CheckForChildren(pMenu
, menuItemHandler
->nItemId
);
710 else if ( menuItemHandler
->xMenuItemDispatch
.is() )
712 // We need an update to reflect the current state
715 aTargetURL
.Complete
= menuItemHandler
->aMenuItemURL
;
716 m_xURLTransformer
->parseStrict( aTargetURL
);
718 menuItemHandler
->xMenuItemDispatch
->addStatusListener(
719 static_cast< XStatusListener
* >( this ), aTargetURL
);
720 menuItemHandler
->xMenuItemDispatch
->removeStatusListener(
721 static_cast< XStatusListener
* >( this ), aTargetURL
);
723 catch ( const Exception
& )
727 else if (menuItemHandler
->xSubMenuManager
.is())
729 MenuBarManager
* pMenuBarManager
= menuItemHandler
->xSubMenuManager
.get();
732 pMenuBarManager
->Activate(pMenuBarManager
->GetMenuBar());
733 pMenuBarManager
->Deactivate(pMenuBarManager
->GetMenuBar());
735 lcl_CheckForChildren(pMenu
, menuItemHandler
->nItemId
);
743 IMPL_LINK( MenuBarManager
, Deactivate
, Menu
*, pMenu
, bool )
745 if ( pMenu
== m_pVCLMenu
)
748 if ( pMenu
->IsMenuBar() && m_xDeferredItemContainer
.is() )
750 // Start timer to handle settings asynchronous
751 // Changing the menu inside this handler leads to
753 m_aAsyncSettingsTimer
.SetInvokeHandler(LINK(this, MenuBarManager
, AsyncSettingsHdl
));
754 m_aAsyncSettingsTimer
.SetTimeout(10);
755 m_aAsyncSettingsTimer
.Start();
762 IMPL_LINK_NOARG( MenuBarManager
, AsyncSettingsHdl
, Timer
*, void)
765 Reference
< XInterface
> xSelfHold(
766 static_cast< ::cppu::OWeakObject
* >( this ), UNO_QUERY_THROW
);
768 m_aAsyncSettingsTimer
.Stop();
769 if ( !m_bActive
&& m_xDeferredItemContainer
.is() )
771 SetItemContainer( m_xDeferredItemContainer
);
772 m_xDeferredItemContainer
.clear();
776 IMPL_LINK( MenuBarManager
, Select
, Menu
*, pMenu
, bool )
779 std::vector
<beans::PropertyValue
> aArgs
;
780 Reference
< XDispatch
> xDispatch
;
785 sal_uInt16 nCurItemId
= pMenu
->GetCurItemId();
786 sal_uInt16 nCurPos
= pMenu
->GetItemPos( nCurItemId
);
787 if ( pMenu
== m_pVCLMenu
&&
788 pMenu
->GetItemType( nCurPos
) != MenuItemType::SEPARATOR
)
790 MenuItemHandler
* pMenuItemHandler
= GetMenuItemHandler( nCurItemId
);
791 if ( pMenuItemHandler
&& pMenuItemHandler
->xMenuItemDispatch
.is() )
793 aTargetURL
.Complete
= pMenuItemHandler
->aMenuItemURL
;
794 m_xURLTransformer
->parseStrict( aTargetURL
);
796 if ( pMenu
->GetUserValue( nCurItemId
) )
798 // addon menu item selected
800 comphelper::makePropertyValue(u
"Referer"_ustr
, u
"private:user"_ustr
));
803 // pass along if SHIFT/CTRL/ALT/CMD keys are pressed down
804 const VclPtr
<vcl::Window
> pWindow
805 = VCLUnoHelper::GetWindow(m_xFrame
->getContainerWindow());
806 const sal_Int16 nKeys
807 = pWindow
? pWindow
->GetPointerState().mnState
& KEY_MODIFIERS_MASK
: 0;
809 aArgs
.push_back(comphelper::makePropertyValue(u
"KeyModifier"_ustr
, nKeys
));
811 xDispatch
= pMenuItemHandler
->xMenuItemDispatch
;
816 // tdf#126054 don't let dispatch destroy this until after function completes
817 rtl::Reference
<MenuBarManager
> xKeepAlive(this);
820 SolarMutexReleaser aReleaser
;
821 xDispatch
->dispatch(aTargetURL
, comphelper::containerToSequence(aArgs
));
824 if ( !m_bHasMenuBar
)
825 // Standalone (non-native) popup menu doesn't fire deactivate event
826 // in this case, so we have to reset the active flag here.
832 bool MenuBarManager::MustBeHidden( PopupMenu
* pPopupMenu
, const Reference
< XURLTransformer
>& rTransformer
)
838 SvtCommandOptions aCmdOptions
;
840 sal_uInt16 nCount
= pPopupMenu
->GetItemCount();
841 sal_uInt16
nHideCount( 0 );
843 for ( sal_uInt16 i
= 0; i
< nCount
; i
++ )
845 sal_uInt16 nId
= pPopupMenu
->GetItemId( i
);
848 PopupMenu
* pSubPopupMenu
= pPopupMenu
->GetPopupMenu( nId
);
851 if ( MustBeHidden( pSubPopupMenu
, rTransformer
))
853 pPopupMenu
->HideItem( nId
);
859 aTargetURL
.Complete
= pPopupMenu
->GetItemCommand( nId
);
860 rTransformer
->parseStrict( aTargetURL
);
862 if ( aCmdOptions
.LookupDisabled( aTargetURL
.Path
))
870 return ( nCount
== nHideCount
);
873 OUString
MenuBarManager::RetrieveLabelFromCommand(const OUString
& rCmdURL
)
875 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(rCmdURL
, m_aModuleIdentifier
);
876 if ( !m_bHasMenuBar
)
878 // This is a context menu, prefer "PopupLabel" over "Label".
879 return vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties
);
881 return vcl::CommandInfoProvider::GetMenuLabelForCommand(aProperties
);
884 bool MenuBarManager::CreatePopupMenuController( MenuItemHandler
* pMenuItemHandler
,
885 const css::uno::Reference
< css::frame::XDispatchProvider
>& rDispatchProvider
,
886 const OUString
& rModuleIdentifier
)
888 OUString
aItemCommand( pMenuItemHandler
->aMenuItemURL
);
890 // Try instantiate a popup menu controller. It is stored in the menu item handler.
891 if ( !m_xPopupMenuControllerFactory
.is() )
894 auto aSeq( comphelper::InitAnyPropertySequence( {
895 { "DispatchProvider", Any(rDispatchProvider
) },
896 { "ModuleIdentifier", Any(rModuleIdentifier
) },
897 { "Frame", Any(m_xFrame
) },
898 { "InToolbar", Any(!m_bHasMenuBar
) }
901 Reference
< XPopupMenuController
> xPopupMenuController(
902 m_xPopupMenuControllerFactory
->createInstanceWithArgumentsAndContext(
908 if ( xPopupMenuController
.is() )
910 // Provide our awt popup menu to the popup menu controller
911 pMenuItemHandler
->xPopupMenuController
= xPopupMenuController
;
912 xPopupMenuController
->setPopupMenu( pMenuItemHandler
->xPopupMenu
);
919 void MenuBarManager::FillMenuManager( Menu
* pMenu
, const Reference
< XFrame
>& rFrame
,
920 const Reference
< XDispatchProvider
>& rDispatchProvider
,
921 const OUString
& rModuleIdentifier
, bool bDelete
)
925 m_bDeleteMenu
= bDelete
;
927 m_xDispatchProvider
= rDispatchProvider
;
929 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
930 m_bShowMenuImages
= rSettings
.GetUseImagesInMenus();
931 m_bRetrieveImages
= false;
933 // Set module identifier when provided from outside
934 if (!rModuleIdentifier
.isEmpty())
935 m_aModuleIdentifier
= rModuleIdentifier
;
937 m_aModuleIdentifier
= vcl::CommandInfoProvider::GetModuleIdentifier(m_xFrame
);
939 // Add root as ui configuration listener
940 RetrieveImageManagers();
942 if ( pMenu
->IsMenuBar() && rFrame
.is() )
944 // First merge all addon popup menus into our structure
946 for ( nPos
= 0; nPos
< pMenu
->GetItemCount(); nPos
++ )
948 sal_uInt16 nItemId
= pMenu
->GetItemId( nPos
);
949 OUString aCommand
= pMenu
->GetItemCommand( nItemId
);
950 if ( aCommand
== aSpecialWindowCommand
|| aCommand
== aCmdHelpMenu
)
952 // Retrieve addon popup menus and add them to our menu bar
953 framework::AddonMenuManager::MergeAddonPopupMenus( rFrame
, nPos
, static_cast<MenuBar
*>(pMenu
) );
958 // Merge the Add-Ons help menu items into the Office help menu
959 framework::AddonMenuManager::MergeAddonHelpMenu( rFrame
, static_cast<MenuBar
*>(pMenu
) );
962 const bool bAccessibilityEnabled
= MiscSettings::GetEnableATToolSupport();
963 sal_uInt16 nItemCount
= pMenu
->GetItemCount();
964 OUString aItemCommand
;
965 m_aMenuItemHandlerVector
.reserve(nItemCount
);
966 for ( sal_uInt16 i
= 0; i
< nItemCount
; i
++ )
968 sal_uInt16 nItemId
= FillItemCommand(aItemCommand
,pMenu
, i
);
970 if (( pMenu
->IsMenuBar() || bAccessibilityEnabled
) &&
971 ( pMenu
->GetItemText( nItemId
).isEmpty() ))
973 if ( !aItemCommand
.isEmpty() )
974 pMenu
->SetItemText( nItemId
, RetrieveLabelFromCommand( aItemCommand
));
977 // Command can be just an alias to another command.
978 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(aItemCommand
, m_aModuleIdentifier
);
979 OUString aRealCommand
= vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties
);
980 if ( !aRealCommand
.isEmpty() )
981 aItemCommand
= aRealCommand
;
983 Reference
< XDispatch
> xDispatch
;
984 VclPtr
<PopupMenu
> pPopup
= pMenu
->GetPopupMenu( nItemId
);
985 // overwrite the show icons on menu option?
986 MenuItemBits nBits
= pMenu
->GetItemBits( nItemId
) & ( MenuItemBits::ICON
| MenuItemBits::TEXT
);
987 bool bItemShowMenuImages
= ( m_bShowMenuImages
&& nBits
!= MenuItemBits::TEXT
) || nBits
& MenuItemBits::ICON
;
991 // Retrieve module identifier from Help Command entry
992 OUString
aModuleIdentifier( rModuleIdentifier
);
993 if (!pMenu
->GetHelpCommand(nItemId
).isEmpty())
995 aModuleIdentifier
= pMenu
->GetHelpCommand( nItemId
);
996 pMenu
->SetHelpCommand( nItemId
, u
""_ustr
);
999 // Retrieve possible attributes struct
1000 Reference
< XDispatchProvider
> xPopupMenuDispatchProvider( rDispatchProvider
);
1001 MenuAttributes
* pAttributes
= static_cast<MenuAttributes
*>(pMenu
->GetUserValue( nItemId
));
1003 xPopupMenuDispatchProvider
= pAttributes
->xDispatchProvider
;
1005 if ( m_xPopupMenuControllerFactory
.is() &&
1006 m_xPopupMenuControllerFactory
->hasController( aItemCommand
, aModuleIdentifier
)
1009 // Check if we have to create a popup menu for a uno based popup menu controller.
1010 // We have to set an empty popup menu into our menu structure so the controller also
1011 // works with inplace OLE.
1012 MenuItemHandler
* pItemHandler
= new MenuItemHandler( nItemId
, nullptr, xDispatch
);
1013 pItemHandler
->xPopupMenu
= new VCLXPopupMenu(pPopup
);
1014 pItemHandler
->aMenuItemURL
= aItemCommand
;
1015 m_aMenuItemHandlerVector
.push_back( std::unique_ptr
<MenuItemHandler
>(pItemHandler
) );
1017 if ( bAccessibilityEnabled
|| pMenu
->IsMenuBar())
1019 if ( CreatePopupMenuController( pItemHandler
, xPopupMenuDispatchProvider
, aModuleIdentifier
))
1020 pItemHandler
->xPopupMenuController
->updatePopupMenu();
1022 lcl_CheckForChildren(pMenu
, nItemId
);
1026 // Check if this is the tools menu. Add menu item if needed
1027 if ( aItemCommand
== aCmdToolsMenu
&& AddonMenuManager::HasAddonMenuElements() )
1029 // Create addon popup menu if there exist elements and this is the tools popup menu
1030 VclPtr
<PopupMenu
> pSubMenu
= AddonMenuManager::CreateAddonMenu(rFrame
);
1031 if ( pSubMenu
&& ( pSubMenu
->GetItemCount() > 0 ))
1033 if ( pPopup
->GetItemType( pPopup
->GetItemCount() - 1 ) != MenuItemType::SEPARATOR
)
1034 pPopup
->InsertSeparator();
1036 pPopup
->InsertItem( ITEMID_ADDONLIST
, OUString() );
1037 pPopup
->SetPopupMenu( ITEMID_ADDONLIST
, pSubMenu
);
1038 pPopup
->SetItemCommand( ITEMID_ADDONLIST
, u
".uno:Addons"_ustr
);
1041 pSubMenu
.disposeAndClear();
1044 rtl::Reference
<MenuBarManager
> pSubMenuManager
= new MenuBarManager( m_xContext
, rFrame
, m_xURLTransformer
,
1045 xPopupMenuDispatchProvider
, aModuleIdentifier
, pPopup
, false, m_bHasMenuBar
);
1047 AddMenu(pSubMenuManager
.get(), aItemCommand
, nItemId
);
1050 else if ( pMenu
->GetItemType( i
) != MenuItemType::SEPARATOR
)
1052 if ( bItemShowMenuImages
)
1053 m_bRetrieveImages
= true;
1055 std::unique_ptr
<MenuItemHandler
> pItemHandler(new MenuItemHandler( nItemId
, nullptr, xDispatch
));
1056 // Retrieve possible attributes struct
1057 MenuAttributes
* pAttributes
= static_cast<MenuAttributes
*>(pMenu
->GetUserValue( nItemId
));
1059 pItemHandler
->aTargetFrame
= pAttributes
->aTargetFrame
;
1060 pItemHandler
->aMenuItemURL
= aItemCommand
;
1062 if ( m_xPopupMenuControllerFactory
.is() &&
1063 m_xPopupMenuControllerFactory
->hasController( aItemCommand
, m_aModuleIdentifier
) )
1065 // Check if we have to create a popup menu for a uno based popup menu controller.
1066 // We have to set an empty popup menu into our menu structure so the controller also
1067 // works with inplace OLE.
1068 pItemHandler
->xPopupMenu
= new VCLXPopupMenu
;
1069 PopupMenu
* pPopupMenu
= static_cast<PopupMenu
*>(pItemHandler
->xPopupMenu
->GetMenu());
1070 pMenu
->SetPopupMenu( pItemHandler
->nItemId
, pPopupMenu
);
1072 if ( bAccessibilityEnabled
&& CreatePopupMenuController( pItemHandler
.get(), m_xDispatchProvider
, m_aModuleIdentifier
) )
1074 pItemHandler
->xPopupMenuController
->updatePopupMenu();
1077 lcl_CheckForChildren(pMenu
, pItemHandler
->nItemId
);
1080 m_aMenuItemHandlerVector
.push_back( std::move(pItemHandler
) );
1084 if ( m_bHasMenuBar
&& bAccessibilityEnabled
)
1085 SetAcceleratorKeys(pMenu
);
1090 void MenuBarManager::impl_RetrieveShortcutsFromConfiguration(
1091 const Reference
< XAcceleratorConfiguration
>& rAccelCfg
,
1092 const Sequence
< OUString
>& rCommands
,
1093 std::vector
< std::unique_ptr
<MenuItemHandler
> >& aMenuShortCuts
)
1095 if ( !rAccelCfg
.is() )
1100 css::awt::KeyEvent aKeyEvent
;
1101 Sequence
< Any
> aSeqKeyCode
= rAccelCfg
->getPreferredKeyEventsForCommandList( rCommands
);
1102 for ( sal_Int32 i
= 0; i
< aSeqKeyCode
.getLength(); i
++ )
1104 if ( aSeqKeyCode
[i
] >>= aKeyEvent
)
1105 aMenuShortCuts
[i
]->aKeyCode
= svt::AcceleratorExecute::st_AWTKey2VCLKey( aKeyEvent
);
1108 catch ( const IllegalArgumentException
& )
1113 void MenuBarManager::RetrieveShortcuts( std::vector
< std::unique_ptr
<MenuItemHandler
> >& aMenuShortCuts
)
1115 Reference
< XAcceleratorConfiguration
> xDocAccelCfg( m_xDocAcceleratorManager
);
1116 Reference
< XAcceleratorConfiguration
> xModuleAccelCfg( m_xModuleAcceleratorManager
);
1117 Reference
< XAcceleratorConfiguration
> xGlobalAccelCfg( m_xGlobalAcceleratorManager
);
1119 if ( !m_bAcceleratorCfg
)
1121 // Retrieve references on demand
1122 m_bAcceleratorCfg
= true;
1123 if ( !xDocAccelCfg
.is() )
1125 Reference
< XController
> xController
= m_xFrame
->getController();
1126 Reference
< XModel
> xModel
;
1127 if ( xController
.is() )
1129 xModel
= xController
->getModel();
1132 Reference
< XUIConfigurationManagerSupplier
> xSupplier( xModel
, UNO_QUERY
);
1133 if ( xSupplier
.is() )
1135 Reference
< XUIConfigurationManager
> xDocUICfgMgr
= xSupplier
->getUIConfigurationManager();
1136 if ( xDocUICfgMgr
.is() )
1138 xDocAccelCfg
= xDocUICfgMgr
->getShortCutManager();
1139 m_xDocAcceleratorManager
= xDocAccelCfg
;
1146 if ( !xModuleAccelCfg
.is() )
1148 Reference
< XModuleUIConfigurationManagerSupplier
> xModuleCfgMgrSupplier
=
1149 theModuleUIConfigurationManagerSupplier::get( m_xContext
);
1152 Reference
< XUIConfigurationManager
> xUICfgMgr
= xModuleCfgMgrSupplier
->getUIConfigurationManager( m_aModuleIdentifier
);
1153 if ( xUICfgMgr
.is() )
1155 xModuleAccelCfg
= xUICfgMgr
->getShortCutManager();
1156 m_xModuleAcceleratorManager
= xModuleAccelCfg
;
1159 catch ( const RuntimeException
& )
1163 catch ( const Exception
& )
1168 if ( !xGlobalAccelCfg
.is() ) try
1170 xGlobalAccelCfg
= GlobalAcceleratorConfiguration::create( m_xContext
);
1171 m_xGlobalAcceleratorManager
= xGlobalAccelCfg
;
1173 catch ( const css::uno::DeploymentException
& )
1175 SAL_WARN("fwk.uielement", "GlobalAcceleratorConfiguration"
1176 " not available. This should happen only on mobile platforms.");
1180 vcl::KeyCode aEmptyKeyCode
;
1181 Sequence
< OUString
> aSeq( aMenuShortCuts
.size() );
1182 auto aSeqRange
= asNonConstRange(aSeq
);
1183 const sal_uInt32 nCount
= aMenuShortCuts
.size();
1184 for ( sal_uInt32 i
= 0; i
< nCount
; ++i
)
1186 aSeqRange
[i
] = aMenuShortCuts
[i
]->aMenuItemURL
;
1187 aMenuShortCuts
[i
]->aKeyCode
= aEmptyKeyCode
;
1190 if ( m_xGlobalAcceleratorManager
.is() )
1191 impl_RetrieveShortcutsFromConfiguration( xGlobalAccelCfg
, aSeq
, aMenuShortCuts
);
1192 if ( m_xModuleAcceleratorManager
.is() )
1193 impl_RetrieveShortcutsFromConfiguration( xModuleAccelCfg
, aSeq
, aMenuShortCuts
);
1194 if ( m_xDocAcceleratorManager
.is() )
1195 impl_RetrieveShortcutsFromConfiguration( xDocAccelCfg
, aSeq
, aMenuShortCuts
);
1198 void MenuBarManager::SetAcceleratorKeys(Menu
* pMenu
)
1200 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
1201 bool bShowShortcuts
= m_bHasMenuBar
|| rSettings
.GetContextMenuShortcuts();
1202 if ( bShowShortcuts
)
1203 RetrieveShortcuts( m_aMenuItemHandlerVector
);
1205 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
1207 if ( !bShowShortcuts
)
1209 pMenu
->SetAccelKey( menuItemHandler
->nItemId
, vcl::KeyCode() );
1211 else if ( menuItemHandler
->aMenuItemURL
== aCmdHelpIndex
)
1213 // Set key code, workaround for hard-coded shortcut F1 mapped to .uno:HelpIndex
1214 // Only non-popup menu items can have a short-cut
1215 vcl::KeyCode
aKeyCode( KEY_F1
);
1216 pMenu
->SetAccelKey( menuItemHandler
->nItemId
, aKeyCode
);
1218 else if ( pMenu
->GetPopupMenu( menuItemHandler
->nItemId
) == nullptr )
1219 pMenu
->SetAccelKey( menuItemHandler
->nItemId
, menuItemHandler
->aKeyCode
);
1223 void MenuBarManager::RetrieveImageManagers()
1225 if ( !m_xDocImageManager
.is() )
1227 Reference
< XController
> xController
= m_xFrame
->getController();
1228 Reference
< XModel
> xModel
;
1229 if ( xController
.is() )
1231 xModel
= xController
->getModel();
1234 Reference
< XUIConfigurationManagerSupplier
> xSupplier( xModel
, UNO_QUERY
);
1235 if ( xSupplier
.is() )
1237 Reference
< XUIConfigurationManager
> xDocUICfgMgr
= xSupplier
->getUIConfigurationManager();
1238 m_xDocImageManager
.set( xDocUICfgMgr
->getImageManager(), UNO_QUERY
);
1239 m_xDocImageManager
->addConfigurationListener(
1240 Reference
< XUIConfigurationListener
>(this) );
1246 if ( !m_xModuleImageManager
.is() )
1248 Reference
< XModuleUIConfigurationManagerSupplier
> xModuleCfgMgrSupplier
=
1249 theModuleUIConfigurationManagerSupplier::get( m_xContext
);
1250 Reference
< XUIConfigurationManager
> xUICfgMgr
= xModuleCfgMgrSupplier
->getUIConfigurationManager( m_aModuleIdentifier
);
1251 m_xModuleImageManager
.set( xUICfgMgr
->getImageManager(), UNO_QUERY
);
1252 m_xModuleImageManager
->addConfigurationListener( Reference
< XUIConfigurationListener
>(this) );
1256 void MenuBarManager::FillMenuWithConfiguration(
1259 const OUString
& rModuleIdentifier
,
1260 const Reference
< XIndexAccess
>& rItemContainer
,
1261 const Reference
< XURLTransformer
>& rTransformer
)
1263 Reference
< XDispatchProvider
> xEmptyDispatchProvider
;
1264 MenuBarManager::FillMenu( nId
, pMenu
, rModuleIdentifier
, rItemContainer
, xEmptyDispatchProvider
);
1266 // Merge add-on menu entries into the menu bar
1267 MenuBarManager::MergeAddonMenus( pMenu
,
1268 AddonsOptions().GetMergeMenuInstructions(),
1269 rModuleIdentifier
);
1271 bool bHasDisabledEntries
= SvtCommandOptions().HasEntriesDisabled();
1272 if ( !bHasDisabledEntries
)
1275 sal_uInt16 nCount
= pMenu
->GetItemCount();
1276 for ( sal_uInt16 i
= 0; i
< nCount
; i
++ )
1278 sal_uInt16 nID
= pMenu
->GetItemId( i
);
1281 PopupMenu
* pPopupMenu
= pMenu
->GetPopupMenu( nID
);
1284 if ( MustBeHidden( pPopupMenu
, rTransformer
))
1285 pMenu
->HideItem( nId
);
1291 void MenuBarManager::FillMenu(
1294 const OUString
& rModuleIdentifier
,
1295 const Reference
< XIndexAccess
>& rItemContainer
,
1296 const Reference
< XDispatchProvider
>& rDispatchProvider
)
1298 // Fill menu bar with container contents
1299 for ( sal_Int32 n
= 0; n
< rItemContainer
->getCount(); n
++ )
1301 Sequence
< PropertyValue
> aProps
;
1302 OUString aCommandURL
;
1304 OUString
aModuleIdentifier( rModuleIdentifier
);
1305 sal_uInt16 nType
= 0;
1306 Reference
< XIndexAccess
> xIndexContainer
;
1307 Reference
< XDispatchProvider
> xDispatchProvider( rDispatchProvider
);
1308 sal_Int16 nStyle
= 0;
1311 if ( rItemContainer
->getByIndex( n
) >>= aProps
)
1314 bool bEnabled
= true;
1316 for (beans::PropertyValue
const& rProp
: aProps
)
1318 OUString aPropName
= rProp
.Name
;
1319 if ( aPropName
== "CommandURL" )
1320 rProp
.Value
>>= aCommandURL
;
1321 else if ( aPropName
== "ItemDescriptorContainer" )
1322 rProp
.Value
>>= xIndexContainer
;
1323 else if ( aPropName
== "Label" )
1324 rProp
.Value
>>= aLabel
;
1325 else if ( aPropName
== "Type" )
1326 rProp
.Value
>>= nType
;
1327 else if ( aPropName
== "ModuleIdentifier" )
1328 rProp
.Value
>>= aModuleIdentifier
;
1329 else if ( aPropName
== "DispatchProvider" )
1330 rProp
.Value
>>= xDispatchProvider
;
1331 else if ( aPropName
== "Style" )
1332 rProp
.Value
>>= nStyle
;
1333 else if ( aPropName
== "IsVisible" )
1334 rProp
.Value
>>= bShow
;
1335 else if ( aPropName
== "Enabled" )
1336 rProp
.Value
>>= bEnabled
;
1339 if (!aCommandURL
.isEmpty() && vcl::CommandInfoProvider::IsExperimental(aCommandURL
, rModuleIdentifier
) &&
1340 !officecfg::Office::Common::Misc::ExperimentalMode::get())
1344 if (aCommandURL
== ".uno:SafeMode"
1345 && !officecfg::Office::Common::Misc::OfferSafeMode::get())
1350 if ( nType
== css::ui::ItemType::DEFAULT
)
1352 pMenu
->InsertItem( nId
, aLabel
);
1353 pMenu
->SetItemCommand( nId
, aCommandURL
);
1357 MenuItemBits nBits
= pMenu
->GetItemBits( nId
);
1358 if ( nStyle
& css::ui::ItemStyle::ICON
)
1359 nBits
|= MenuItemBits::ICON
;
1360 if ( nStyle
& css::ui::ItemStyle::TEXT
)
1361 nBits
|= MenuItemBits::TEXT
;
1362 if ( nStyle
& css::ui::ItemStyle::RADIO_CHECK
)
1363 nBits
|= MenuItemBits::RADIOCHECK
;
1364 pMenu
->SetItemBits( nId
, nBits
);
1368 pMenu
->HideItem( nId
);
1371 pMenu
->EnableItem( nId
, false );
1373 if ( xIndexContainer
.is() )
1375 VclPtr
<PopupMenu
> pNewPopupMenu
= VclPtr
<PopupMenu
>::Create();
1376 pMenu
->SetPopupMenu( nId
, pNewPopupMenu
);
1377 // Use the command URL as the Help ID for the sub menu
1378 pNewPopupMenu
->SetHelpId(aCommandURL
);
1380 if ( xDispatchProvider
.is() )
1382 // Use attributes struct to transport special dispatch provider
1383 void* nAttributePtr
= MenuAttributes::CreateAttribute(xDispatchProvider
);
1384 pMenu
->SetUserValue(nId
, nAttributePtr
, MenuAttributes::ReleaseAttribute
);
1387 // Use help command to transport module identifier
1388 if ( !aModuleIdentifier
.isEmpty() )
1389 pMenu
->SetHelpCommand( nId
, aModuleIdentifier
);
1392 FillMenu( nId
, pNewPopupMenu
, aModuleIdentifier
, xIndexContainer
, xDispatchProvider
);
1399 pMenu
->InsertSeparator();
1404 catch ( const IndexOutOfBoundsException
& )
1411 void MenuBarManager::MergeAddonMenus(
1413 const MergeMenuInstructionContainer
& aMergeInstructionContainer
,
1414 const OUString
& rModuleIdentifier
)
1416 // set start value for the item ID for the new addon menu items
1417 sal_uInt16 nItemId
= ADDONMENU_MERGE_ITEMID_START
;
1419 const sal_uInt32 nCount
= aMergeInstructionContainer
.size();
1420 for ( sal_uInt32 i
= 0; i
< nCount
; i
++ )
1422 const MergeMenuInstruction
& rMergeInstruction
= aMergeInstructionContainer
[i
];
1424 if ( MenuBarMerger::IsCorrectContext( rMergeInstruction
.aMergeContext
, rModuleIdentifier
))
1426 ::std::vector
< OUString
> aMergePath
;
1428 // retrieve the merge path from the merge point string
1429 MenuBarMerger::RetrieveReferencePath( rMergeInstruction
.aMergePoint
, aMergePath
);
1431 // convert the sequence/sequence property value to a more convenient vector<>
1432 AddonMenuContainer aMergeMenuItems
;
1433 MenuBarMerger::GetSubMenu( rMergeInstruction
.aMergeMenu
, aMergeMenuItems
);
1435 // try to find the reference point for our merge operation
1436 Menu
* pMenu
= pMenuBar
;
1437 ReferencePathInfo aResult
= MenuBarMerger::FindReferencePath( aMergePath
, pMenu
);
1439 if ( aResult
.eResult
== RP_OK
)
1441 // normal merge operation
1442 MenuBarMerger::ProcessMergeOperation( aResult
.pPopupMenu
,
1445 rMergeInstruction
.aMergeCommand
,
1446 rMergeInstruction
.aMergeCommandParameter
,
1453 MenuBarMerger::ProcessFallbackOperation( aResult
,
1455 rMergeInstruction
.aMergeCommand
,
1456 rMergeInstruction
.aMergeFallback
,
1465 void MenuBarManager::SetItemContainer( const Reference
< XIndexAccess
>& rItemContainer
)
1467 SolarMutexGuard aSolarMutexGuard
;
1469 Reference
< XFrame
> xFrame
= m_xFrame
;
1471 // Clear MenuBarManager structures
1473 // Check active state as we cannot change our VCL menu during activation by the user
1476 m_xDeferredItemContainer
= rItemContainer
;
1481 m_aMenuItemHandlerVector
.clear();
1482 m_pVCLMenu
->Clear();
1486 // Fill menu bar with container contents
1487 FillMenuWithConfiguration( nId
, m_pVCLMenu
, m_aModuleIdentifier
, rItemContainer
, m_xURLTransformer
);
1489 // Refill menu manager again
1490 Reference
< XDispatchProvider
> xDispatchProvider
;
1491 FillMenuManager( m_pVCLMenu
, xFrame
, xDispatchProvider
, m_aModuleIdentifier
, false );
1493 // add itself as frame action listener
1494 m_xFrame
->addFrameActionListener( Reference
< XFrameActionListener
>(this) );
1498 void MenuBarManager::GetPopupController( PopupControllerCache
& rPopupController
)
1501 SolarMutexGuard aSolarMutexGuard
;
1503 for (auto const& menuItemHandler
: m_aMenuItemHandlerVector
)
1505 if ( menuItemHandler
->xPopupMenuController
.is() )
1507 Reference
< XDispatchProvider
> xDispatchProvider( menuItemHandler
->xPopupMenuController
, UNO_QUERY
);
1509 PopupControllerEntry aPopupControllerEntry
;
1510 aPopupControllerEntry
.m_xDispatchProvider
= xDispatchProvider
;
1512 // Just use the main part of the URL for popup menu controllers
1513 sal_Int32
nSchemePart( 0 );
1514 OUString
aMenuURL( menuItemHandler
->aMenuItemURL
);
1516 nSchemePart
= aMenuURL
.indexOf( ':' );
1517 if (( nSchemePart
> 0 ) &&
1518 ( aMenuURL
.getLength() > ( nSchemePart
+1 )))
1520 OUString
aMainURL( u
"vnd.sun.star.popup:"_ustr
);
1521 sal_Int32 nQueryPart
= aMenuURL
.indexOf( '?', nSchemePart
);
1522 if ( nQueryPart
> 0 )
1523 aMainURL
+= aMenuURL
.subView( nSchemePart
, nQueryPart
-nSchemePart
);
1524 else if ( nQueryPart
== -1 )
1525 aMainURL
+= aMenuURL
.subView( nSchemePart
+1 );
1527 rPopupController
.emplace( aMainURL
, aPopupControllerEntry
);
1530 if ( menuItemHandler
->xSubMenuManager
)
1532 menuItemHandler
->xSubMenuManager
->GetPopupController( rPopupController
);
1537 void MenuBarManager::AddMenu(MenuBarManager
* pSubMenuManager
,const OUString
& _sItemCommand
,sal_uInt16 _nItemId
)
1539 Reference
< XStatusListener
> xSubMenuManager( pSubMenuManager
);
1540 m_xFrame
->addFrameActionListener( Reference
< XFrameActionListener
>( xSubMenuManager
, UNO_QUERY
));
1542 std::unique_ptr
<MenuItemHandler
> pMenuItemHandler(new MenuItemHandler(
1545 Reference
<XDispatch
>() ));
1546 pMenuItemHandler
->aMenuItemURL
= _sItemCommand
;
1547 m_aMenuItemHandlerVector
.push_back( std::move(pMenuItemHandler
) );
1551 sal_uInt16
MenuBarManager::FillItemCommand(OUString
& _rItemCommand
, Menu
* _pMenu
,sal_uInt16 _nIndex
)
1553 sal_uInt16 nItemId
= _pMenu
->GetItemId( _nIndex
);
1555 _rItemCommand
= _pMenu
->GetItemCommand( nItemId
);
1556 if ( _rItemCommand
.isEmpty() )
1558 _rItemCommand
= "slot:" + OUString::number( nItemId
);
1559 _pMenu
->SetItemCommand( nItemId
, _rItemCommand
);
1564 void MenuBarManager::SetHdl()
1566 m_pVCLMenu
->SetActivateHdl( LINK( this, MenuBarManager
, Activate
));
1567 m_pVCLMenu
->SetDeactivateHdl( LINK( this, MenuBarManager
, Deactivate
));
1568 m_pVCLMenu
->SetSelectHdl( LINK( this, MenuBarManager
, Select
));
1570 if ( !m_xURLTransformer
.is() && m_xContext
.is() )
1571 m_xURLTransformer
.set( URLTransformer::create( m_xContext
) );
1574 void MenuBarManager::FillMenuImages(Reference
< XFrame
> const & _xFrame
, Menu
* _pMenu
,bool bShowMenuImages
)
1576 AddonsOptions aAddonOptions
;
1578 for ( sal_uInt16 nPos
= 0; nPos
< _pMenu
->GetItemCount(); nPos
++ )
1580 sal_uInt16 nId
= _pMenu
->GetItemId( nPos
);
1581 if ( _pMenu
->GetItemType( nPos
) != MenuItemType::SEPARATOR
)
1583 // overwrite the show icons on menu option?
1584 MenuItemBits nBits
= _pMenu
->GetItemBits( nId
) & ( MenuItemBits::ICON
| MenuItemBits::TEXT
);
1585 bool bTmpShowMenuImages
= ( bShowMenuImages
&& nBits
!= MenuItemBits::TEXT
) || nBits
& MenuItemBits::ICON
;
1587 if ( bTmpShowMenuImages
)
1589 OUString aMenuItemCommand
= _pMenu
->GetItemCommand( nId
);
1590 Image aImage
= vcl::CommandInfoProvider::GetImageForCommand(aMenuItemCommand
, _xFrame
);
1592 aImage
= Image(aAddonOptions
.GetImageFromURL(aMenuItemCommand
, false));
1594 _pMenu
->SetItemImage( nId
, aImage
);
1597 _pMenu
->SetItemImage( nId
, Image() );
1604 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */