/* -*- 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 .
*/
#include <memory>
#include <svtools/popupmenucontrollerbase.hxx>
#include <svx/SmartTagItem.hxx>
#include <toolkit/awt/vclxmenu.hxx>
#include <utility>
#include <vcl/commandinfoprovider.hxx>
const sal_uInt16 MN_ST_INSERT_START = 500;
namespace {
class SmartTagMenuController : public svt::PopupMenuControllerBase
{
public:
explicit SmartTagMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
// XStatusListener
virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
// XMenuListener
virtual void SAL_CALL itemSelected( const css::awt::MenuEvent& rEvent ) override;
// XServiceInfo
virtual OUString SAL_CALL getImplementationName() override;
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
private:
void FillMenu();
bool MenuSelect(sal_uInt16 nMyId);
struct InvokeAction
{
css::uno::Reference< css::smarttags::XSmartTagAction > m_xAction;
css::uno::Reference< css::container::XStringKeyMap > m_xSmartTagProperties;
sal_uInt32 m_nActionID;
InvokeAction( css::uno::Reference< css::smarttags::XSmartTagAction > xAction,
css::uno::Reference< css::container::XStringKeyMap > xSmartTagProperties,
sal_uInt32 nActionID ) : m_xAction(std::move( xAction )), m_xSmartTagProperties(std::move( xSmartTagProperties )), m_nActionID( nActionID ) {}
};
std::vector< InvokeAction > m_aInvokeActions;
std::unique_ptr< const SvxSmartTagItem > m_pSmartTagItem;
};
}
SmartTagMenuController::SmartTagMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext )
: svt::PopupMenuControllerBase( rxContext )
{
}
void SmartTagMenuController::statusChanged( const css::frame::FeatureStateEvent& rEvent )
{
resetPopupMenu( m_xPopupMenu );
css::uno::Sequence< css::beans::PropertyValue > aProperties;
if ( !rEvent.IsEnabled || !( rEvent.State >>= aProperties ) )
return;
css::uno::Sequence< css::uno::Sequence< css::uno::Reference< css::smarttags::XSmartTagAction > > > aActionComponents;
css::uno::Sequence< css::uno::Sequence< sal_Int32 > > aActionIndices;
css::uno::Sequence< css::uno::Reference< css::container::XStringKeyMap > > aStringKeyMaps;
css::uno::Reference< css::text::XTextRange > xTextRange;
css::uno::Reference< css::frame::XController > xController;
css::lang::Locale aLocale;
OUString aApplicationName;
OUString aRangeText;
for (const auto& aProperty : aProperties)
{
if ( aProperty.Name == "ActionComponents" )
aProperty.Value >>= aActionComponents;
else if ( aProperty.Name == "ActionIndices" )
aProperty.Value >>= aActionIndices;
else if ( aProperty.Name == "StringKeyMaps" )
aProperty.Value >>= aStringKeyMaps;
else if ( aProperty.Name == "TextRange" )
aProperty.Value >>= xTextRange;
else if ( aProperty.Name == "Controller" )
aProperty.Value >>= xController;
else if ( aProperty.Name == "Locale" )
aProperty.Value >>= aLocale;
else if ( aProperty.Name == "ApplicationName" )
aProperty.Value >>= aApplicationName;
else if ( aProperty.Name == "RangeText" )
aProperty.Value >>= aRangeText;
}
m_pSmartTagItem.reset( new SvxSmartTagItem( TypedWhichId<SvxSmartTagItem>(0), aActionComponents, aActionIndices, aStringKeyMaps, xTextRange, xController, std::move(aLocale), aApplicationName, aRangeText ) );
FillMenu();
}
void SmartTagMenuController::FillMenu()
{
if ( !m_pSmartTagItem )
return;
sal_uInt16 nMenuId = 1;
sal_uInt16 nSubMenuId = MN_ST_INSERT_START;
const css::uno::Sequence< css::uno::Sequence< css::uno::Reference< css::smarttags::XSmartTagAction > > >& rActionComponentsSequence = m_pSmartTagItem->GetActionComponentsSequence();
const css::uno::Sequence< css::uno::Sequence< sal_Int32 > >& rActionIndicesSequence = m_pSmartTagItem->GetActionIndicesSequence();
const css::uno::Sequence< css::uno::Reference< css::container::XStringKeyMap > >& rStringKeyMaps = m_pSmartTagItem->GetStringKeyMaps();
const css::lang::Locale& rLocale = m_pSmartTagItem->GetLocale();
const OUString aApplicationName = m_pSmartTagItem->GetApplicationName();
const OUString aRangeText = m_pSmartTagItem->GetRangeText();
const css::uno::Reference< css::text::XTextRange >& xTextRange = m_pSmartTagItem->GetTextRange();
const css::uno::Reference< css::frame::XController >& xController = m_pSmartTagItem->GetController();
for ( sal_Int32 i = 0; i < rActionComponentsSequence.getLength(); ++i )
{
css::uno::Reference< css::container::XStringKeyMap > xSmartTagProperties = rStringKeyMaps[i];
// Get all actions references associated with the current smart tag type
const css::uno::Sequence< css::uno::Reference< css::smarttags::XSmartTagAction > >& rActionComponents = rActionComponentsSequence[i];
const css::uno::Sequence< sal_Int32 >& rActionIndices = rActionIndicesSequence[i];
if ( !rActionComponents.hasElements() || !rActionIndices.hasElements() )
continue;
// Ask first entry for the smart tag type caption
css::uno::Reference< css::smarttags::XSmartTagAction > xFirstAction = rActionComponents[0];
if ( !xFirstAction.is() )
continue;
const sal_Int32 nSmartTagIndex = rActionIndices[0];
const OUString aSmartTagType = xFirstAction->getSmartTagName( nSmartTagIndex );
const OUString aSmartTagCaption = xFirstAction->getSmartTagCaption( nSmartTagIndex, rLocale );
// No sub-menus if there's only one smart tag type listed
css::uno::Reference<css::awt::XPopupMenu> xSubMenu = m_xPopupMenu;
if ( 1 < rActionComponentsSequence.getLength() )
{
m_xPopupMenu->insertItem(nMenuId, aSmartTagCaption, 0, -1);
xSubMenu.set(new VCLXPopupMenu);
m_xPopupMenu->setPopupMenu(nMenuId++, xSubMenu);
}
// Sub-menu starts with smart tag caption and separator
const OUString aSmartTagCaption2 = aSmartTagCaption + ": " + aRangeText;
xSubMenu->insertItem(nMenuId++, aSmartTagCaption2, static_cast<sal_Int16>(MenuItemBits::NOSELECT), -1);
xSubMenu->insertSeparator(-1);
// Add subitem for every action reference for the current smart tag type
for ( const auto& xAction : rActionComponents )
{
for ( sal_Int32 j = 0; j < xAction->getActionCount( aSmartTagType, xController, xSmartTagProperties ); ++j )
{
const sal_uInt32 nActionID = xAction->getActionID( aSmartTagType, j, xController );
OUString aActionCaption = xAction->getActionCaptionFromID( nActionID,
aApplicationName,
rLocale,
xSmartTagProperties,
aRangeText,
OUString(),
xController,
xTextRange );
xSubMenu->insertItem(nSubMenuId++, aActionCaption, 0, -1);
InvokeAction aEntry( xAction, xSmartTagProperties, nActionID );
m_aInvokeActions.push_back( aEntry );
}
}
}
sal_Int16 nItemCount = m_xPopupMenu->getItemCount();
if (nItemCount > 0)
{
static constexpr OUString aCommand = u".uno:AutoCorrectDlg?OpenSmartTag:bool=true"_ustr;
m_xPopupMenu->insertSeparator(nItemCount++);
auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommand, m_aModuleName);
m_xPopupMenu->insertItem(nMenuId, vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties),
0, nItemCount);
m_xPopupMenu->setCommand(nMenuId, aCommand);
}
}
void SmartTagMenuController::itemSelected(const css::awt::MenuEvent& rEvent)
{
if (MenuSelect(rEvent.MenuId))
return;
svt::PopupMenuControllerBase::itemSelected(rEvent);
}
bool SmartTagMenuController::MenuSelect(sal_uInt16 nMyId)
{
if ( !m_pSmartTagItem )
return false;
if ( nMyId < MN_ST_INSERT_START )
return false;
nMyId -= MN_ST_INSERT_START;
// Compute SmartTag lib index and action index
css::uno::Reference< css::smarttags::XSmartTagAction > xSmartTagAction = m_aInvokeActions[nMyId].m_xAction;
if (!xSmartTagAction.is())
return false;
// Execute action
xSmartTagAction->invokeAction( m_aInvokeActions[nMyId].m_nActionID,
m_pSmartTagItem->GetApplicationName(),
m_pSmartTagItem->GetController(),
m_pSmartTagItem->GetTextRange(),
m_aInvokeActions[nMyId].m_xSmartTagProperties,
m_pSmartTagItem->GetRangeText(),
OUString(),
m_pSmartTagItem->GetLocale() );
return true;
}
OUString SmartTagMenuController::getImplementationName()
{
return u"com.sun.star.comp.svx.SmartTagMenuController"_ustr;
}
css::uno::Sequence< OUString > SmartTagMenuController::getSupportedServiceNames()
{
return { u"com.sun.star.frame.PopupMenuController"_ustr };
}
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_svx_SmartTagMenuController_get_implementation(
css::uno::XComponentContext* xContext,
css::uno::Sequence< css::uno::Any > const & )
{
return cppu::acquire( new SmartTagMenuController( xContext ) );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1019 Compound assignment expression 'rEvent.State >>= aProperties' is used inside condition.