/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
if ( m_bDisposed ) throw css::lang::DisposedException();
if ( Action.Action != FrameAction_CONTEXT_CHANGED ) return;
for (autoconst& menuItemHandler : m_aMenuItemHandlerVector)
{ // Clear dispatch reference as we will requery it later if ( menuItemHandler->xMenuItemDispatch.is() )
{
URL aTargetURL;
aTargetURL.Complete = menuItemHandler->aMenuItemURL;
m_xURLTransformer->parseStrict( aTargetURL );
SolarMutexGuard aSolarGuard;
{ if ( m_bDisposed ) return;
// We have to check all menu entries as there can be identical entries in a popup menu. for (autoconst& menuItemHandler : m_aMenuItemHandlerVector)
{ if ( menuItemHandler->aParsedItemURL == aFeatureURL )
{ bool bCheckmark( false ); bool bMenuItemEnabled( m_pVCLMenu->IsItemEnabled( menuItemHandler->nItemId )); bool bEnabledItem( Event.IsEnabled );
OUString aItemText;
status::Visibility aVisibilityStatus;
#ifdef UNIX //enable some slots hardly, because UNIX clipboard does not notify all changes // Can be removed if follow up task will be fixed directly within applications. // Note: PasteSpecial is handled specifically by calc // Calc also disables Paste under some circumstances, do not override. /* TODO: is this workaround even needed anymore? Was introduced * in 2009 with commit 426ab2c0e8f6e3fe2b766f74f6b8da873d860260 * as some "metropatch" and the other places it touched seem to
* be gone. */ if ( (menuItemHandler->aMenuItemURL == ".uno:Paste" &&
m_aModuleIdentifier != "com.sun.star.sheet.SpreadsheetDocument")
|| menuItemHandler->aMenuItemURL == ".uno:PasteClipboard" ) // special for draw/impress
bEnabledItem = true; #endif
// Remove "checked" mark for disabled menu items. // Initially disabled but checkable menu items do not receive // checked/unchecked state, so can appear inconsistently after // enabling/disabling. Since we can not pass checked state for disabled // items, we will just reset checked state for them, anyway correct state // will be transferred from controller once item enabled. if ( !bEnabledItem && m_pVCLMenu->IsItemChecked( menuItemHandler->nItemId ) )
m_pVCLMenu->CheckItem( menuItemHandler->nItemId, false );
}
if ( Event.State >>= bCheckmark )
{ // Checkmark or RadioButton
m_pVCLMenu->CheckItem( menuItemHandler->nItemId, bCheckmark ); // If not already designated RadioButton set as CheckMark
MenuItemBits nBits = m_pVCLMenu->GetItemBits( menuItemHandler->nItemId ); if (!(nBits & MenuItemBits::RADIOCHECK))
m_pVCLMenu->SetItemBits( menuItemHandler->nItemId, nBits | MenuItemBits::CHECKABLE );
if ( Event.Requery )
{ // Release dispatch object - will be required on the next activate!
menuItemHandler->xMenuItemDispatch.clear();
}
}
}
}
// Helper to retrieve own structure from item ID
MenuBarManager::MenuItemHandler* MenuBarManager::GetMenuItemHandler( sal_uInt16 nItemId )
{
SolarMutexGuard g;
for (autoconst& menuItemHandler : m_aMenuItemHandlerVector)
{ if ( menuItemHandler->nItemId == nItemId ) return menuItemHandler.get();
}
return nullptr;
}
// Helper to set request images flag void MenuBarManager::RequestImages()
{
m_bRetrieveImages = true; for (autoconst& menuItemHandler : m_aMenuItemHandlerVector)
{ if ( menuItemHandler->xSubMenuManager.is() )
menuItemHandler->xSubMenuManager->RequestImages();
}
}
// Helper to reset objects to prepare shutdown void MenuBarManager::RemoveListener()
{
SolarMutexGuard g;
for (autoconst& menuItemHandler : m_aMenuItemHandlerVector)
{ if ( menuItemHandler->xMenuItemDispatch.is() )
{
URL aTargetURL;
aTargetURL.Complete = menuItemHandler->aMenuItemURL;
m_xURLTransformer->parseStrict( aTargetURL );
menuItemHandler->xMenuItemDispatch->removeStatusListener( static_cast< XStatusListener* >( this ), aTargetURL );
}
menuItemHandler->xMenuItemDispatch.clear();
if ( menuItemHandler->xPopupMenu.is() )
{
{ // Remove popup menu from menu structure
m_pVCLMenu->SetPopupMenu( menuItemHandler->nItemId, nullptr );
}
// We now provide a popup menu controller to external code. // Therefore the life-time must be explicitly handled via // dispose!! try
{
Reference< XComponent > xComponent( menuItemHandler->xPopupMenuController, UNO_QUERY ); if ( xComponent.is() )
xComponent->dispose();
} catch ( const RuntimeException& )
{ throw;
} catch ( const Exception& )
{
}
// Release references to controller and popup menu
menuItemHandler->xPopupMenuController.clear();
menuItemHandler->xPopupMenu.clear();
}
if ( menuItemHandler->xSubMenuManager )
menuItemHandler->xSubMenuManager->dispose();
}
for (autoconst& menuItemHandler : m_aMenuItemHandlerVector)
{ if ( menuItemHandler->xMenuItemDispatch.is() &&
menuItemHandler->xMenuItemDispatch == Source.Source )
{ // disposing called from menu item dispatcher, remove listener
pMenuItemDisposing = menuItemHandler.get(); break;
}
}
if ( pMenuItemDisposing )
{ // Release references to the dispatch object
URL aTargetURL;
aTargetURL.Complete = pMenuItemDisposing->aMenuItemURL;
m_xURLTransformer->parseStrict( aTargetURL );
pMenuItemDisposing->xMenuItemDispatch->removeStatusListener( static_cast< XStatusListener* >( this ), aTargetURL );
pMenuItemDisposing->xMenuItemDispatch.clear(); if ( pMenuItemDisposing->xPopupMenu.is() )
{
Reference< css::lang::XEventListener > xEventListener( pMenuItemDisposing->xPopupMenuController, UNO_QUERY ); if ( xEventListener.is() )
xEventListener->disposing( Source );
{ // Remove popup menu from menu structure as we release our reference to // the controller.
m_pVCLMenu->SetPopupMenu( pMenuItemDisposing->nItemId, nullptr );
}
if ( !bPopupMenu )
{
xMenuItemDispatch->addStatusListener( static_cast< XStatusListener* >( this ), aTargetURL ); // For the menubar, we have to keep status listening to support Ubuntu's HUD. if ( !m_bHasMenuBar )
xMenuItemDispatch->removeStatusListener( static_cast< XStatusListener* >( this ), aTargetURL );
}
} elseif ( !bPopupMenu )
pMenu->EnableItem( menuItemHandler->nItemId, false );
} elseif ( menuItemHandler->xPopupMenuController.is() )
{ // Force update of popup menu
menuItemHandler->xPopupMenuController->updatePopupMenu(); if (PopupMenu* pThisPopup = pMenu->GetPopupMenu(menuItemHandler->nItemId))
{
pThisPopup->Activate();
pThisPopup->Deactivate();
}
lcl_CheckForChildren(pMenu, menuItemHandler->nItemId);
} elseif ( menuItemHandler->xMenuItemDispatch.is() )
{ // We need an update to reflect the current state try
{
aTargetURL.Complete = menuItemHandler->aMenuItemURL;
m_xURLTransformer->parseStrict( aTargetURL );
if (pData->xDispatch.is())
{
Application::PostUserEvent(LINK_NONMEMBER(nullptr, AsyncMenuExecute), pData.release());
}
if ( !m_bHasMenuBar ) // Standalone (non-native) popup menu doesn't fire deactivate event // in this case, so we have to reset the active flag here.
m_bActive = false;
for ( sal_uInt16 i = 0; i < nCount; i++ )
{
sal_uInt16 nId = pPopupMenu->GetItemId( i ); if ( nId > 0 )
{
PopupMenu* pSubPopupMenu = pPopupMenu->GetPopupMenu( nId ); if ( pSubPopupMenu )
{ if ( MustBeHidden( pSubPopupMenu, rTransformer ))
{
pPopupMenu->HideItem( nId );
++nHideCount;
}
} else
{
aTargetURL.Complete = pPopupMenu->GetItemCommand( nId );
rTransformer->parseStrict( aTargetURL );
if ( xPopupMenuController.is() )
{ // Provide our awt popup menu to the popup menu controller
pMenuItemHandler->xPopupMenuController = xPopupMenuController;
xPopupMenuController->setPopupMenu( pMenuItemHandler->xPopupMenu ); returntrue;
}
// Set module identifier when provided from outside if (!rModuleIdentifier.isEmpty())
m_aModuleIdentifier = rModuleIdentifier; else
m_aModuleIdentifier = vcl::CommandInfoProvider::GetModuleIdentifier(m_xFrame);
// Add root as ui configuration listener
RetrieveImageManagers();
if ( pMenu->IsMenuBar() && rFrame.is() )
{ // First merge all addon popup menus into our structure
sal_uInt16 nPos = 0; for ( nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
{
sal_uInt16 nItemId = pMenu->GetItemId( nPos );
OUString aCommand = pMenu->GetItemCommand( nItemId ); if ( aCommand == aSpecialWindowCommand || aCommand == aCmdHelpMenu )
{ // Retrieve addon popup menus and add them to our menu bar
framework::AddonMenuManager::MergeAddonPopupMenus( rFrame, nPos, static_cast<MenuBar *>(pMenu) ); break;
}
}
// Merge the Add-Ons help menu items into the Office help menu
framework::AddonMenuManager::MergeAddonHelpMenu( rFrame, static_cast<MenuBar *>(pMenu) );
}
constbool bAccessibilityEnabled = MiscSettings::GetEnableATToolSupport();
sal_uInt16 nItemCount = pMenu->GetItemCount();
OUString aItemCommand;
m_aMenuItemHandlerVector.reserve(nItemCount); for ( sal_uInt16 i = 0; i < nItemCount; i++ )
{
sal_uInt16 nItemId = FillItemCommand(aItemCommand,pMenu, i );
// Command can be just an alias to another command. auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aItemCommand, m_aModuleIdentifier);
OUString aRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties); if ( !aRealCommand.isEmpty() )
aItemCommand = aRealCommand;
if ( m_xPopupMenuControllerFactory.is() &&
m_xPopupMenuControllerFactory->hasController( aItemCommand, aModuleIdentifier )
)
{ // Check if we have to create a popup menu for a uno based popup menu controller. // We have to set an empty popup menu into our menu structure so the controller also // works with inplace OLE.
MenuItemHandler* pItemHandler = new MenuItemHandler( nItemId, nullptr, xDispatch );
pItemHandler->xPopupMenu = new VCLXPopupMenu(pPopup);
pItemHandler->aMenuItemURL = aItemCommand;
m_aMenuItemHandlerVector.push_back( std::unique_ptr<MenuItemHandler>(pItemHandler) );
if ( bAccessibilityEnabled || pMenu->IsMenuBar())
{ if ( CreatePopupMenuController( pItemHandler, xPopupMenuDispatchProvider, aModuleIdentifier ))
pItemHandler->xPopupMenuController->updatePopupMenu();
}
lcl_CheckForChildren(pMenu, nItemId);
} else
{ // Check if this is the tools menu. Add menu item if needed if ( aItemCommand == aCmdToolsMenu && AddonMenuManager::HasAddonMenuElements() )
{ // Create addon popup menu if there exist elements and this is the tools popup menu
VclPtr<PopupMenu> pSubMenu = AddonMenuManager::CreateAddonMenu(rFrame); if ( pSubMenu && ( pSubMenu->GetItemCount() > 0 ))
{ if ( pPopup->GetItemType( pPopup->GetItemCount() - 1 ) != MenuItemType::SEPARATOR )
pPopup->InsertSeparator();
if ( m_xPopupMenuControllerFactory.is() &&
m_xPopupMenuControllerFactory->hasController( aItemCommand, m_aModuleIdentifier ) )
{ // Check if we have to create a popup menu for a uno based popup menu controller. // We have to set an empty popup menu into our menu structure so the controller also // works with inplace OLE.
pItemHandler->xPopupMenu = new VCLXPopupMenu;
PopupMenu* pPopupMenu = static_cast<PopupMenu*>(pItemHandler->xPopupMenu->GetMenu());
pMenu->SetPopupMenu( pItemHandler->nItemId, pPopupMenu );
if ( !xGlobalAccelCfg.is() ) try
{
xGlobalAccelCfg = GlobalAcceleratorConfiguration::create( m_xContext );
m_xGlobalAcceleratorManager = xGlobalAccelCfg;
} catch ( const css::uno::DeploymentException& )
{
SAL_WARN("fwk.uielement", "GlobalAcceleratorConfiguration" " not available. This should happen only on mobile platforms.");
}
}
vcl::KeyCode aEmptyKeyCode;
Sequence< OUString > aSeq( aMenuShortCuts.size() ); auto aSeqRange = asNonConstRange(aSeq); const sal_uInt32 nCount = aMenuShortCuts.size(); for ( sal_uInt32 i = 0; i < nCount; ++i )
{
aSeqRange[i] = aMenuShortCuts[i]->aMenuItemURL;
aMenuShortCuts[i]->aKeyCode = aEmptyKeyCode;
}
if ( m_xGlobalAcceleratorManager.is() )
impl_RetrieveShortcutsFromConfiguration( xGlobalAccelCfg, aSeq, aMenuShortCuts ); if ( m_xModuleAcceleratorManager.is() )
impl_RetrieveShortcutsFromConfiguration( xModuleAccelCfg, aSeq, aMenuShortCuts ); if ( m_xDocAcceleratorManager.is() )
impl_RetrieveShortcutsFromConfiguration( xDocAccelCfg, aSeq, aMenuShortCuts );
}
// Merge add-on menu entries into the menu bar
MenuBarManager::MergeAddonMenus( pMenu,
AddonsOptions().GetMergeMenuInstructions(),
rModuleIdentifier );
bool bHasDisabledEntries = SvtCommandOptions().HasEntriesDisabled(); if ( !bHasDisabledEntries ) return;
sal_uInt16 nCount = pMenu->GetItemCount(); for ( sal_uInt16 i = 0; i < nCount; i++ )
{
sal_uInt16 nID = pMenu->GetItemId( i ); if ( nID > 0 )
{
PopupMenu* pPopupMenu = pMenu->GetPopupMenu( nID ); if ( pPopupMenu )
{ if ( MustBeHidden( pPopupMenu, rTransformer ))
pMenu->HideItem( nId );
}
}
}
}
void MenuBarManager::FillMenu(
sal_uInt16& nId,
Menu* pMenu, const OUString& rModuleIdentifier, const Reference< XIndexAccess >& rItemContainer, const Reference< XDispatchProvider >& rDispatchProvider )
{ // Fill menu bar with container contents for ( sal_Int32 n = 0; n < rItemContainer->getCount(); n++ )
{
Sequence< PropertyValue > aProps;
OUString aCommandURL;
OUString aLabel;
OUString aModuleIdentifier( rModuleIdentifier );
sal_uInt16 nType = 0;
Reference< XIndexAccess > xIndexContainer;
Reference< XDispatchProvider > xDispatchProvider( rDispatchProvider );
sal_Int16 nStyle = 0; try
{ if ( rItemContainer->getByIndex( n ) >>= aProps )
{ bool bShow = true; bool bEnabled = true;
if ( nStyle )
{
MenuItemBits nBits = pMenu->GetItemBits( nId ); if ( nStyle & css::ui::ItemStyle::ICON )
nBits |= MenuItemBits::ICON; if ( nStyle & css::ui::ItemStyle::TEXT )
nBits |= MenuItemBits::TEXT; if ( nStyle & css::ui::ItemStyle::RADIO_CHECK )
nBits |= MenuItemBits::RADIOCHECK;
pMenu->SetItemBits( nId, nBits );
}
if ( !bShow )
pMenu->HideItem( nId );
if ( !bEnabled)
pMenu->EnableItem( nId, false );
if ( xIndexContainer.is() )
{
VclPtr<PopupMenu> pNewPopupMenu = VclPtr<PopupMenu>::Create();
pMenu->SetPopupMenu( nId, pNewPopupMenu ); // Use the command URL as the Help ID for the sub menu
pNewPopupMenu->SetHelpId(aCommandURL);
if ( xDispatchProvider.is() )
{ // Use attributes struct to transport special dispatch provider void* nAttributePtr = MenuAttributes::CreateAttribute(xDispatchProvider);
pMenu->SetUserValue(nId, nAttributePtr, MenuAttributes::ReleaseAttribute);
}
// Use help command to transport module identifier if ( !aModuleIdentifier.isEmpty() )
pMenu->SetHelpCommand( nId, aModuleIdentifier );
void MenuBarManager::MergeAddonMenus(
Menu* pMenuBar, const MergeMenuInstructionContainer& aMergeInstructionContainer, const OUString& rModuleIdentifier )
{ // set start value for the item ID for the new addon menu items
sal_uInt16 nItemId = ADDONMENU_MERGE_ITEMID_START;
const sal_uInt32 nCount = aMergeInstructionContainer.size(); for ( sal_uInt32 i = 0; i < nCount; i++ )
{ const MergeMenuInstruction& rMergeInstruction = aMergeInstructionContainer[i];
// retrieve the merge path from the merge point string
MenuBarMerger::RetrieveReferencePath( rMergeInstruction.aMergePoint, aMergePath );
// convert the sequence/sequence property value to a more convenient vector<>
AddonMenuContainer aMergeMenuItems;
MenuBarMerger::GetSubMenu( rMergeInstruction.aMergeMenu, aMergeMenuItems );
// try to find the reference point for our merge operation
Menu* pMenu = pMenuBar;
ReferencePathInfo aResult = MenuBarMerger::FindReferencePath( aMergePath, pMenu );
// Clear MenuBarManager structures
{ // Check active state as we cannot change our VCL menu during activation by the user if ( m_bActive )
{
m_xDeferredItemContainer = rItemContainer; return;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.