LibreOffice Module svx (master)  1
smarttagmenu.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <memory>
22 #include <svx/SmartTagItem.hxx>
23 #include <toolkit/awt/vclxmenu.hxx>
25 #include <vcl/menu.hxx>
26 
27 const sal_uInt16 MN_ST_INSERT_START = 500;
28 
29 namespace {
30 
31 class SmartTagMenuController : public svt::PopupMenuControllerBase
32 {
33 public:
34  explicit SmartTagMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
35 
36  // XStatusListener
37  virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
38 
39  // XServiceInfo
40  virtual OUString SAL_CALL getImplementationName() override;
41  virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
42 
43 private:
44  void FillMenu();
45  DECL_LINK( MenuSelect, Menu*, bool );
46  struct InvokeAction
47  {
48  css::uno::Reference< css::smarttags::XSmartTagAction > m_xAction;
49  css::uno::Reference< css::container::XStringKeyMap > m_xSmartTagProperties;
50  sal_uInt32 m_nActionID;
51  InvokeAction( css::uno::Reference< css::smarttags::XSmartTagAction > const & xAction,
52  css::uno::Reference< css::container::XStringKeyMap > const & xSmartTagProperties,
53  sal_uInt32 nActionID ) : m_xAction( xAction ), m_xSmartTagProperties( xSmartTagProperties ), m_nActionID( nActionID ) {}
54  };
55  std::vector< InvokeAction > m_aInvokeActions;
56  std::unique_ptr< const SvxSmartTagItem > m_pSmartTagItem;
57 };
58 
59 }
60 
61 SmartTagMenuController::SmartTagMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext )
62  : svt::PopupMenuControllerBase( rxContext )
63 {
64 }
65 
66 void SmartTagMenuController::statusChanged( const css::frame::FeatureStateEvent& rEvent )
67 {
68  resetPopupMenu( m_xPopupMenu );
69 
70  css::uno::Sequence< css::beans::PropertyValue > aProperties;
71  if ( !rEvent.IsEnabled || !( rEvent.State >>= aProperties ) )
72  return;
73 
74  css::uno::Sequence< css::uno::Sequence< css::uno::Reference< css::smarttags::XSmartTagAction > > > aActionComponents;
75  css::uno::Sequence< css::uno::Sequence< sal_Int32 > > aActionIndices;
76  css::uno::Sequence< css::uno::Reference< css::container::XStringKeyMap > > aStringKeyMaps;
77  css::uno::Reference< css::text::XTextRange > xTextRange;
78  css::uno::Reference< css::frame::XController > xController;
79  css::lang::Locale aLocale;
80  OUString aApplicationName;
81  OUString aRangeText;
82 
83  for ( const auto& aProperty : std::as_const(aProperties) )
84  {
85  if ( aProperty.Name == "ActionComponents" )
86  aProperty.Value >>= aActionComponents;
87  else if ( aProperty.Name == "ActionIndices" )
88  aProperty.Value >>= aActionIndices;
89  else if ( aProperty.Name == "StringKeyMaps" )
90  aProperty.Value >>= aStringKeyMaps;
91  else if ( aProperty.Name == "TextRange" )
92  aProperty.Value >>= xTextRange;
93  else if ( aProperty.Name == "Controller" )
94  aProperty.Value >>= xController;
95  else if ( aProperty.Name == "Locale" )
96  aProperty.Value >>= aLocale;
97  else if ( aProperty.Name == "ApplicationName" )
98  aProperty.Value >>= aApplicationName;
99  else if ( aProperty.Name == "RangeText" )
100  aProperty.Value >>= aRangeText;
101  }
102  m_pSmartTagItem.reset( new SvxSmartTagItem( 0, aActionComponents, aActionIndices, aStringKeyMaps, xTextRange, xController, aLocale, aApplicationName, aRangeText ) );
103  FillMenu();
104 }
105 
106 void SmartTagMenuController::FillMenu()
107 {
108  if ( !m_pSmartTagItem )
109  return;
110 
111  sal_uInt16 nMenuId = 1;
112  sal_uInt16 nSubMenuId = MN_ST_INSERT_START;
113 
114  VCLXMenu* pAwtMenu = comphelper::getFromUnoTunnel<VCLXMenu>( m_xPopupMenu );
115  PopupMenu* pVCLMenu = static_cast< PopupMenu* >( pAwtMenu->GetMenu() );
116 
117  const css::uno::Sequence< css::uno::Sequence< css::uno::Reference< css::smarttags::XSmartTagAction > > >& rActionComponentsSequence = m_pSmartTagItem->GetActionComponentsSequence();
118  const css::uno::Sequence< css::uno::Sequence< sal_Int32 > >& rActionIndicesSequence = m_pSmartTagItem->GetActionIndicesSequence();
119  const css::uno::Sequence< css::uno::Reference< css::container::XStringKeyMap > >& rStringKeyMaps = m_pSmartTagItem->GetStringKeyMaps();
120  const css::lang::Locale& rLocale = m_pSmartTagItem->GetLocale();
121  const OUString aApplicationName = m_pSmartTagItem->GetApplicationName();
122  const OUString aRangeText = m_pSmartTagItem->GetRangeText();
123  const css::uno::Reference< css::text::XTextRange >& xTextRange = m_pSmartTagItem->GetTextRange();
124  const css::uno::Reference< css::frame::XController >& xController = m_pSmartTagItem->GetController();
125 
126  for ( sal_Int32 i = 0; i < rActionComponentsSequence.getLength(); ++i )
127  {
128  css::uno::Reference< css::container::XStringKeyMap > xSmartTagProperties = rStringKeyMaps[i];
129 
130  // Get all actions references associated with the current smart tag type
131  const css::uno::Sequence< css::uno::Reference< css::smarttags::XSmartTagAction > >& rActionComponents = rActionComponentsSequence[i];
132  const css::uno::Sequence< sal_Int32 >& rActionIndices = rActionIndicesSequence[i];
133 
134  if ( !rActionComponents.hasElements() || !rActionIndices.hasElements() )
135  continue;
136 
137  // Ask first entry for the smart tag type caption
138  css::uno::Reference< css::smarttags::XSmartTagAction > xFirstAction = rActionComponents[0];
139 
140  if ( !xFirstAction.is() )
141  continue;
142 
143  const sal_Int32 nSmartTagIndex = rActionIndices[0];
144  const OUString aSmartTagType = xFirstAction->getSmartTagName( nSmartTagIndex );
145  const OUString aSmartTagCaption = xFirstAction->getSmartTagCaption( nSmartTagIndex, rLocale );
146 
147  // No sub-menus if there's only one smart tag type listed
148  PopupMenu* pSubMenu = pVCLMenu;
149  if ( 1 < rActionComponentsSequence.getLength() )
150  {
151  pVCLMenu->InsertItem( nMenuId, aSmartTagCaption );
153  pSubMenu = pMenu;
154  pVCLMenu->SetPopupMenu( nMenuId++, pSubMenu );
155  }
156  pSubMenu->SetSelectHdl( LINK( this, SmartTagMenuController, MenuSelect ) );
157 
158  // Sub-menu starts with smart tag caption and separator
159  const OUString aSmartTagCaption2 = aSmartTagCaption + ": " + aRangeText;
160  pSubMenu->InsertItem( nMenuId++, aSmartTagCaption2, MenuItemBits::NOSELECT );
161  pSubMenu->InsertSeparator();
162 
163  // Add subitem for every action reference for the current smart tag type
164  for ( const auto& xAction : rActionComponents )
165  {
166  for ( sal_Int32 j = 0; j < xAction->getActionCount( aSmartTagType, xController, xSmartTagProperties ); ++j )
167  {
168  const sal_uInt32 nActionID = xAction->getActionID( aSmartTagType, j, xController );
169  OUString aActionCaption = xAction->getActionCaptionFromID( nActionID,
170  aApplicationName,
171  rLocale,
172  xSmartTagProperties,
173  aRangeText,
174  OUString(),
175  xController,
176  xTextRange );
177 
178  pSubMenu->InsertItem( nSubMenuId++, aActionCaption );
179  InvokeAction aEntry( xAction, xSmartTagProperties, nActionID );
180  m_aInvokeActions.push_back( aEntry );
181  }
182  }
183  }
184 
185  if ( 0 < pVCLMenu->GetItemCount() )
186  {
187  static const OUStringLiteral aCommand = u".uno:AutoCorrectDlg?OpenSmartTag:bool=true";
188  pVCLMenu->InsertSeparator();
189  auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommand, m_aModuleName);
190  pVCLMenu->InsertItem( nMenuId, vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties) );
191  pVCLMenu->SetItemCommand( nMenuId, aCommand );
192  }
193 }
194 
195 IMPL_LINK( SmartTagMenuController, MenuSelect, Menu*, pMenu, bool )
196 {
197  if ( !m_pSmartTagItem )
198  return false;
199 
200  sal_uInt16 nMyId = pMenu->GetCurItemId();
201  if ( nMyId < MN_ST_INSERT_START )
202  return false;
203 
204  nMyId -= MN_ST_INSERT_START;
205 
206  // Compute SmartTag lib index and action index
207  css::uno::Reference< css::smarttags::XSmartTagAction > xSmartTagAction = m_aInvokeActions[nMyId].m_xAction;
208 
209  // Execute action
210  if ( xSmartTagAction.is() )
211  {
212  xSmartTagAction->invokeAction( m_aInvokeActions[nMyId].m_nActionID,
213  m_pSmartTagItem->GetApplicationName(),
214  m_pSmartTagItem->GetController(),
215  m_pSmartTagItem->GetTextRange(),
216  m_aInvokeActions[nMyId].m_xSmartTagProperties,
217  m_pSmartTagItem->GetRangeText(),
218  OUString(),
219  m_pSmartTagItem->GetLocale() );
220  }
221  return false;
222 }
223 
224 OUString SmartTagMenuController::getImplementationName()
225 {
226  return "com.sun.star.comp.svx.SmartTagMenuController";
227 }
228 
229 css::uno::Sequence< OUString > SmartTagMenuController::getSupportedServiceNames()
230 {
231  return { "com.sun.star.frame.PopupMenuController" };
232 }
233 
234 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
236  css::uno::XComponentContext* xContext,
237  css::uno::Sequence< css::uno::Any > const & )
238 {
239  return cppu::acquire( new SmartTagMenuController( xContext ) );
240 }
241 
242 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
IMPL_LINK(SmartTagMenuController, MenuSelect, Menu *, pMenu, bool)
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
Reference< XController > xController
PropertiesInfo aProperties
void InsertSeparator(const OString &rIdent=OString(), sal_uInt16 nPos=MENU_APPEND)
void SetPopupMenu(sal_uInt16 nItemId, PopupMenu *pMenu)
OUString GetPopupLabelForCommand(const css::uno::Sequence< css::beans::PropertyValue > &rProperties)
void SetSelectHdl(const Link< Menu *, bool > &rLink)
sal_uInt16 GetCurItemId() const
int i
float u
Sequence< beans::PropertyValue > GetCommandProperties(const OUString &rsCommandName, const OUString &rsModuleName)
const sal_uInt16 MN_ST_INSERT_START
void InsertItem(sal_uInt16 nItemId, const OUString &rStr, MenuItemBits nItemBits=MenuItemBits::NONE, const OString &rIdent=OString(), sal_uInt16 nPos=MENU_APPEND)
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 &)
OUString aCommand
Menu * GetMenu() const