Avoid potential negative array index access to cached text.
[LibreOffice.git] / framework / source / uielement / generictoolbarcontroller.cxx
blob827991f7226d93cd80b15d749e681d374b8f4631
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <framework/generictoolbarcontroller.hxx>
22 #include <com/sun/star/util/XURLTransformer.hpp>
23 #include <com/sun/star/frame/XDispatch.hpp>
24 #include <com/sun/star/lang/DisposedException.hpp>
25 #include <com/sun/star/frame/status/ItemStatus.hpp>
26 #include <com/sun/star/frame/status/Visibility.hpp>
27 #include <com/sun/star/frame/ControlCommand.hpp>
29 #include <comphelper/propertyvalue.hxx>
30 #include <svl/imageitm.hxx>
31 #include <vcl/commandinfoprovider.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/weld.hxx>
34 #include <tools/urlobj.hxx>
35 #include <toolkit/helper/vclunohelper.hxx>
36 #include <strings.hrc>
37 #include <classes/fwkresid.hxx>
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::beans;
41 using namespace ::com::sun::star::lang;
42 using namespace ::com::sun::star::frame;
43 using namespace ::com::sun::star::frame::status;
45 namespace framework
48 static bool isEnumCommand( std::u16string_view rCommand )
50 INetURLObject aURL( rCommand );
52 return ( aURL.GetProtocol() == INetProtocol::Uno ) &&
53 ( aURL.GetURLPath().indexOf( '.' ) != -1);
56 static OUString getEnumCommand( std::u16string_view rCommand )
58 INetURLObject aURL( rCommand );
60 OUString aEnumCommand;
61 OUString aURLPath = aURL.GetURLPath();
62 sal_Int32 nIndex = aURLPath.indexOf( '.' );
63 if (( nIndex > 0 ) && ( nIndex < aURLPath.getLength() ))
64 aEnumCommand = aURLPath.copy( nIndex+1 );
66 return aEnumCommand;
69 static OUString getMasterCommand( const OUString& rCommand )
71 OUString aMasterCommand( rCommand );
72 INetURLObject aURL( rCommand );
73 if ( aURL.GetProtocol() == INetProtocol::Uno )
75 sal_Int32 nIndex = aURL.GetURLPath().indexOf( '.' );
76 if ( nIndex )
78 aURL.SetURLPath( aURL.GetURLPath().subView( 0, nIndex ) );
79 aMasterCommand = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
82 return aMasterCommand;
85 GenericToolbarController::GenericToolbarController( const Reference< XComponentContext >& rxContext,
86 const Reference< XFrame >& rFrame,
87 ToolBox* pToolbar,
88 ToolBoxItemId nID,
89 const OUString& aCommand ) :
90 svt::ToolboxController( rxContext, rFrame, aCommand )
91 , m_xToolbar( pToolbar )
92 , m_nID( nID )
93 , m_bEnumCommand( isEnumCommand( aCommand ))
94 , m_bMirrored( false )
95 , m_bMadeInvisible( false )
96 , m_aEnumCommand( getEnumCommand( aCommand ))
98 if ( m_bEnumCommand )
99 addStatusListener( getMasterCommand( aCommand ) );
101 addStatusListener( aCommand );
103 // Initialization is done through ctor
104 m_bInitialized = true;
107 GenericToolbarController::GenericToolbarController( const Reference< XComponentContext >& rxContext,
108 const Reference< XFrame >& rFrame,
109 weld::Toolbar& rToolbar,
110 const OUString& aCommand ) :
111 GenericToolbarController( rxContext, rFrame, nullptr, ToolBoxItemId(0), aCommand )
113 m_pToolbar = &rToolbar;
116 GenericToolbarController::~GenericToolbarController()
120 void SAL_CALL GenericToolbarController::dispose()
122 SolarMutexGuard aSolarMutexGuard;
124 svt::ToolboxController::dispose();
126 m_pToolbar = nullptr;
127 m_xToolbar.clear();
128 m_nID = ToolBoxItemId(0);
131 void SAL_CALL GenericToolbarController::execute( sal_Int16 KeyModifier )
133 Reference< XDispatch > xDispatch;
134 OUString aCommandURL;
137 SolarMutexGuard aSolarMutexGuard;
139 if ( m_bDisposed )
140 throw DisposedException();
142 if ( m_bInitialized &&
143 m_xFrame.is() &&
144 !m_aCommandURL.isEmpty() )
146 aCommandURL = m_aCommandURL;
147 URLToDispatchMap::iterator pIter = m_aListenerMap.find( m_aCommandURL );
148 if ( pIter != m_aListenerMap.end() )
149 xDispatch = pIter->second;
153 if ( !xDispatch.is() )
154 return;
156 css::util::URL aTargetURL;
158 // Add key modifier to argument list
159 Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("KeyModifier", KeyModifier) };
161 // handle also command aliases
162 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(m_aCommandURL,
163 vcl::CommandInfoProvider::GetModuleIdentifier(m_xFrame));
164 OUString sRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties);
166 aTargetURL.Complete = sRealCommand.isEmpty() ? aCommandURL : sRealCommand;
167 if ( m_xUrlTransformer.is() )
168 m_xUrlTransformer->parseStrict( aTargetURL );
170 // Execute dispatch asynchronously
171 ExecuteInfo* pExecuteInfo = new ExecuteInfo;
172 pExecuteInfo->xDispatch = xDispatch;
173 pExecuteInfo->aTargetURL = aTargetURL;
174 pExecuteInfo->aArgs = aArgs;
175 Application::PostUserEvent( LINK(nullptr, GenericToolbarController , ExecuteHdl_Impl), pExecuteInfo );
178 void GenericToolbarController::statusChanged( const FeatureStateEvent& Event )
180 SolarMutexGuard aSolarMutexGuard;
182 if ( m_bDisposed )
183 return;
185 if ( m_pToolbar )
187 m_pToolbar->set_item_sensitive(m_aCommandURL, Event.IsEnabled);
189 bool bValue;
190 OUString aStrValue;
191 SfxImageItem aImageItem;
193 if ( Event.State >>= bValue )
195 // Boolean, treat it as checked/unchecked
196 m_pToolbar->set_item_active(m_aCommandURL, bValue);
198 else if ( Event.State >>= aStrValue )
200 m_pToolbar->set_item_label(m_aCommandURL, aStrValue);
202 else if ( aImageItem.PutValue( Event.State, 0 ) && aImageItem.IsMirrored() != m_bMirrored )
204 m_pToolbar->set_item_image_mirrored(m_aCommandURL, aImageItem.IsMirrored());
205 auto xGraphic(vcl::CommandInfoProvider::GetXGraphicForCommand(m_aCommandURL, m_xFrame, m_pToolbar->get_icon_size()));
206 m_pToolbar->set_item_image(m_aCommandURL, xGraphic);
207 m_bMirrored = !m_bMirrored;
209 else
210 m_pToolbar->set_item_active(m_aCommandURL, false);
212 return;
215 if ( !m_xToolbar )
216 return;
218 m_xToolbar->EnableItem( m_nID, Event.IsEnabled );
220 ToolBoxItemBits nItemBits = m_xToolbar->GetItemBits( m_nID );
221 nItemBits &= ~ToolBoxItemBits::CHECKABLE;
222 TriState eTri = TRISTATE_FALSE;
224 bool bValue;
225 OUString aStrValue;
226 ItemStatus aItemState;
227 Visibility aItemVisibility;
228 ControlCommand aControlCommand;
229 SfxImageItem aImageItem;
231 if (( Event.State >>= bValue ) && !m_bEnumCommand )
233 // Boolean, treat it as checked/unchecked
234 if ( m_bMadeInvisible )
235 m_xToolbar->ShowItem( m_nID );
236 m_xToolbar->CheckItem( m_nID, bValue );
237 if ( bValue )
238 eTri = TRISTATE_TRUE;
239 nItemBits |= ToolBoxItemBits::CHECKABLE;
241 else if ( Event.State >>= aStrValue )
243 if ( m_bEnumCommand )
245 bValue = aStrValue == m_aEnumCommand;
247 m_xToolbar->CheckItem( m_nID, bValue );
248 if ( bValue )
249 eTri = TRISTATE_TRUE;
250 nItemBits |= ToolBoxItemBits::CHECKABLE;
252 else
254 // Replacement for place holders
255 if ( aStrValue.startsWith("($1)") )
257 aStrValue = FwkResId(STR_UPDATEDOC) + " " + aStrValue.subView( 4 );
259 else if ( aStrValue.startsWith("($2)") )
261 aStrValue = FwkResId(STR_CLOSEDOC_ANDRETURN) + aStrValue.subView( 4 );
263 else if ( aStrValue.startsWith("($3)") )
265 aStrValue = FwkResId(STR_SAVECOPYDOC) + aStrValue.subView( 4 );
267 m_xToolbar->SetItemText( m_nID, aStrValue );
268 // tdf#124267 strip mnemonic from tooltip
269 m_xToolbar->SetQuickHelpText(m_nID, aStrValue.replaceFirst("~", ""));
272 if ( m_bMadeInvisible )
273 m_xToolbar->ShowItem( m_nID );
275 else if (( Event.State >>= aItemState ) && !m_bEnumCommand )
277 eTri = TRISTATE_INDET;
278 nItemBits |= ToolBoxItemBits::CHECKABLE;
279 if ( m_bMadeInvisible )
280 m_xToolbar->ShowItem( m_nID );
282 else if ( Event.State >>= aItemVisibility )
284 m_xToolbar->ShowItem( m_nID, aItemVisibility.bVisible );
285 m_bMadeInvisible = !aItemVisibility.bVisible;
287 else if ( Event.State >>= aControlCommand )
289 if (aControlCommand.Command == "SetQuickHelpText")
291 for ( NamedValue const & rArg : std::as_const(aControlCommand.Arguments) )
293 if (rArg.Name == "HelpText")
295 OUString aHelpText;
296 rArg.Value >>= aHelpText;
297 m_xToolbar->SetQuickHelpText(m_nID, aHelpText);
298 break;
302 if ( m_bMadeInvisible )
303 m_xToolbar->ShowItem( m_nID );
305 else if ( aImageItem.PutValue( Event.State, 0 ) && aImageItem.IsMirrored() != m_bMirrored )
307 m_xToolbar->SetItemImageMirrorMode( m_nID, aImageItem.IsMirrored() );
308 Image aImage( vcl::CommandInfoProvider::GetImageForCommand( m_aCommandURL, m_xFrame, m_xToolbar->GetImageSize() ));
309 m_xToolbar->SetItemImage( m_nID, aImage );
310 m_bMirrored = !m_bMirrored;
311 if ( m_bMadeInvisible )
312 m_xToolbar->ShowItem( m_nID );
314 else if ( m_bMadeInvisible )
315 m_xToolbar->ShowItem( m_nID );
317 m_xToolbar->SetItemState( m_nID, eTri );
318 m_xToolbar->SetItemBits( m_nID, nItemBits );
321 IMPL_STATIC_LINK( GenericToolbarController, ExecuteHdl_Impl, void*, p, void )
323 ExecuteInfo* pExecuteInfo = static_cast<ExecuteInfo*>(p);
324 SolarMutexReleaser aReleaser;
327 // Asynchronous execution as this can lead to our own destruction!
328 // Framework can recycle our current frame and the layout manager disposes all user interface
329 // elements if a component gets detached from its frame!
330 pExecuteInfo->xDispatch->dispatch( pExecuteInfo->aTargetURL, pExecuteInfo->aArgs );
332 catch ( const Exception& )
336 delete pExecuteInfo;
339 ImageOrientationController::ImageOrientationController(const Reference<XComponentContext>& rContext,
340 const Reference<XFrame>& rFrame,
341 const Reference<css::awt::XWindow>& rParentWindow,
342 const OUString& rModuleName)
343 : ToolboxController(rContext, rFrame, ".uno:ImageOrientation")
344 , m_nRotationAngle(0_deg10)
345 , m_bMirrored(false)
347 m_sModuleName = rModuleName;
348 m_xParentWindow = rParentWindow;
349 initialize({});
350 if (!m_pToolbar)
351 VCLUnoHelper::GetWindow(getParent())->AddEventListener(LINK(this, ImageOrientationController, WindowEventListener));
354 void ImageOrientationController::dispose()
356 ToolboxController::dispose();
357 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(getParent());
358 if (pWindow)
359 pWindow->RemoveEventListener(LINK(this, ImageOrientationController, WindowEventListener));
362 IMPL_LINK(ImageOrientationController, WindowEventListener, VclWindowEvent&, rWindowEvent, void)
364 if (m_bDisposed || rWindowEvent.GetId() != VclEventId::ToolboxItemAdded)
365 return;
367 ToolBox* pToolBox = static_cast<ToolBox*>(rWindowEvent.GetWindow());
368 ToolBoxItemId nItemId = pToolBox->GetItemId(reinterpret_cast<sal_IntPtr>(rWindowEvent.GetData()));
369 OUString aCommand = pToolBox->GetItemCommand(nItemId);
371 if (vcl::CommandInfoProvider::IsMirrored(aCommand, getModuleName()))
372 pToolBox->SetItemImageMirrorMode(nItemId, m_bMirrored);
373 if (vcl::CommandInfoProvider::IsRotated(aCommand, getModuleName()))
374 pToolBox->SetItemImageAngle(nItemId, m_nRotationAngle);
377 void ImageOrientationController::statusChanged(const css::frame::FeatureStateEvent& rEvent)
379 if (m_bDisposed)
380 throw DisposedException();
382 SfxImageItem aItem;
383 aItem.PutValue(rEvent.State, 0);
385 if (m_bMirrored == aItem.IsMirrored() && m_nRotationAngle == aItem.GetRotation())
386 return;
388 m_bMirrored = aItem.IsMirrored();
389 m_nRotationAngle = aItem.GetRotation();
391 if (m_pToolbar)
393 for (int i = 0, nCount = m_pToolbar->get_n_items(); i < nCount; ++i)
395 OUString aCommand = m_pToolbar->get_item_ident(i);
396 if (vcl::CommandInfoProvider::IsMirrored(aCommand, getModuleName()))
398 m_pToolbar->set_item_image_mirrored(aCommand, m_bMirrored);
399 auto xGraphic(vcl::CommandInfoProvider::GetXGraphicForCommand(
400 aCommand, m_xFrame, m_pToolbar->get_icon_size()));
401 m_pToolbar->set_item_image(aCommand, xGraphic);
405 else
407 ToolBox* pToolBox = static_cast<ToolBox*>(VCLUnoHelper::GetWindow(getParent()));
408 for (ToolBox::ImplToolItems::size_type i = 0; i < pToolBox->GetItemCount(); ++i)
410 ToolBoxItemId nItemId = pToolBox->GetItemId(i);
411 OUString aCommand = pToolBox->GetItemCommand(nItemId);
412 bool bModified = false;
413 if (vcl::CommandInfoProvider::IsMirrored(aCommand, getModuleName()))
415 pToolBox->SetItemImageMirrorMode(nItemId, m_bMirrored);
416 bModified = true;
418 if (vcl::CommandInfoProvider::IsRotated(aCommand, getModuleName()))
420 pToolBox->SetItemImageAngle(nItemId, m_nRotationAngle);
421 bModified = true;
423 if (bModified)
425 Image aImage(vcl::CommandInfoProvider::GetImageForCommand(aCommand, m_xFrame, pToolBox->GetImageSize()));
426 pToolBox->SetItemImage(nItemId, aImage);
432 } // namespace
434 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */