/src/libreoffice/svtools/source/uno/toolboxcontroller.cxx
Line | Count | Source |
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 <svtools/toolboxcontroller.hxx> |
21 | | #include <com/sun/star/beans/PropertyAttribute.hpp> |
22 | | #include <com/sun/star/beans/PropertyValue.hpp> |
23 | | #include <com/sun/star/beans/XPropertySet.hpp> |
24 | | #include <com/sun/star/frame/XDispatchProvider.hpp> |
25 | | #include <com/sun/star/lang/DisposedException.hpp> |
26 | | #include <com/sun/star/lang/XMultiServiceFactory.hpp> |
27 | | #include <com/sun/star/frame/XLayoutManager.hpp> |
28 | | #include <com/sun/star/util/URLTransformer.hpp> |
29 | | #include <utility> |
30 | | #include <vcl/commandinfoprovider.hxx> |
31 | | #include <vcl/svapp.hxx> |
32 | | #include <toolkit/helper/vclunohelper.hxx> |
33 | | #include <vcl/toolbox.hxx> |
34 | | #include <vcl/weld/Toolbar.hxx> |
35 | | #include <vcl/weld/weldutils.hxx> |
36 | | #include <comphelper/processfactory.hxx> |
37 | | #include <comphelper/propertyvalue.hxx> |
38 | | |
39 | | const int TOOLBARCONTROLLER_PROPHANDLE_SUPPORTSVISIBLE = 1; |
40 | | constexpr OUString TOOLBARCONTROLLER_PROPNAME_SUPPORTSVISIBLE = u"SupportsVisible"_ustr; |
41 | | |
42 | | |
43 | | using namespace ::cppu; |
44 | | using namespace css::awt; |
45 | | using namespace css::uno; |
46 | | using namespace css::util; |
47 | | using namespace css::beans; |
48 | | using namespace css::lang; |
49 | | using namespace css::frame; |
50 | | |
51 | | namespace svt |
52 | | { |
53 | | |
54 | | ToolboxController::ToolboxController( |
55 | | const Reference< XComponentContext >& rxContext, |
56 | | const Reference< XFrame >& xFrame, |
57 | | OUString aCommandURL ) : |
58 | 0 | OPropertyContainer( GetBroadcastHelper() ) |
59 | 0 | , m_bSupportVisible( false ) |
60 | 0 | , m_bInitialized( false ) |
61 | 0 | , m_bDisposed( false ) |
62 | 0 | , m_bSidebar( false ) |
63 | 0 | , m_nToolBoxId( SAL_MAX_UINT16 ) |
64 | 0 | , m_xFrame( xFrame ) |
65 | 0 | , m_xContext( rxContext ) |
66 | 0 | , m_aCommandURL(std::move( aCommandURL )) |
67 | 0 | , m_aListenerContainer( m_aMutex ) |
68 | 0 | , m_pToolbar(nullptr) |
69 | 0 | , m_pBuilder(nullptr) |
70 | 0 | { |
71 | 0 | OSL_ASSERT( m_xContext.is() ); |
72 | 0 | registerProperty( TOOLBARCONTROLLER_PROPNAME_SUPPORTSVISIBLE, |
73 | 0 | TOOLBARCONTROLLER_PROPHANDLE_SUPPORTSVISIBLE, |
74 | 0 | css::beans::PropertyAttribute::TRANSIENT | css::beans::PropertyAttribute::READONLY, |
75 | 0 | &m_bSupportVisible, cppu::UnoType<decltype(m_bSupportVisible)>::get()); |
76 | |
|
77 | 0 | try |
78 | 0 | { |
79 | 0 | m_xUrlTransformer = URLTransformer::create( rxContext ); |
80 | 0 | } |
81 | 0 | catch(const Exception&) |
82 | 0 | { |
83 | 0 | } |
84 | 0 | } |
85 | | |
86 | | ToolboxController::ToolboxController() : |
87 | 0 | OPropertyContainer(GetBroadcastHelper()) |
88 | 0 | , m_bSupportVisible(false) |
89 | 0 | , m_bInitialized( false ) |
90 | 0 | , m_bDisposed( false ) |
91 | 0 | , m_bSidebar( false ) |
92 | 0 | , m_nToolBoxId( SAL_MAX_UINT16 ) |
93 | 0 | , m_aListenerContainer( m_aMutex ) |
94 | 0 | , m_pToolbar(nullptr) |
95 | 0 | , m_pBuilder(nullptr) |
96 | 0 | { |
97 | 0 | registerProperty( TOOLBARCONTROLLER_PROPNAME_SUPPORTSVISIBLE, |
98 | 0 | TOOLBARCONTROLLER_PROPHANDLE_SUPPORTSVISIBLE, |
99 | 0 | css::beans::PropertyAttribute::TRANSIENT | css::beans::PropertyAttribute::READONLY, |
100 | 0 | &m_bSupportVisible, cppu::UnoType<decltype(m_bSupportVisible)>::get()); |
101 | 0 | } |
102 | | |
103 | | ToolboxController::~ToolboxController() |
104 | 0 | { |
105 | 0 | } |
106 | | |
107 | | Reference< XFrame > ToolboxController::getFrameInterface() const |
108 | 0 | { |
109 | 0 | SolarMutexGuard aSolarMutexGuard; |
110 | 0 | return m_xFrame; |
111 | 0 | } |
112 | | |
113 | | const Reference< XComponentContext > & ToolboxController::getContext() const |
114 | 0 | { |
115 | 0 | SolarMutexGuard aSolarMutexGuard; |
116 | 0 | return m_xContext; |
117 | 0 | } |
118 | | |
119 | | Reference< XLayoutManager > ToolboxController::getLayoutManager() const |
120 | 0 | { |
121 | 0 | Reference< XLayoutManager > xLayoutManager; |
122 | 0 | Reference< XPropertySet > xPropSet; |
123 | 0 | { |
124 | 0 | SolarMutexGuard aSolarMutexGuard; |
125 | 0 | xPropSet.set( m_xFrame, UNO_QUERY ); |
126 | 0 | } |
127 | |
|
128 | 0 | if ( xPropSet.is() ) |
129 | 0 | { |
130 | 0 | try |
131 | 0 | { |
132 | 0 | xLayoutManager.set(xPropSet->getPropertyValue(u"LayoutManager"_ustr),UNO_QUERY); |
133 | 0 | } |
134 | 0 | catch ( Exception& ) |
135 | 0 | { |
136 | 0 | } |
137 | 0 | } |
138 | |
|
139 | 0 | return xLayoutManager; |
140 | 0 | } |
141 | | |
142 | | // XInterface |
143 | | Any SAL_CALL ToolboxController::queryInterface( const Type& rType ) |
144 | 0 | { |
145 | 0 | css::uno::Any a(ToolboxController_Base::queryInterface(rType)); |
146 | 0 | return a.hasValue() ? a : OPropertyContainer::queryInterface(rType); |
147 | 0 | } |
148 | | |
149 | | void SAL_CALL ToolboxController::acquire() noexcept |
150 | 0 | { |
151 | 0 | ToolboxController_Base::acquire(); |
152 | 0 | } |
153 | | |
154 | | void SAL_CALL ToolboxController::release() noexcept |
155 | 0 | { |
156 | 0 | ToolboxController_Base::release(); |
157 | 0 | } |
158 | | |
159 | | css::uno::Sequence<css::uno::Type> ToolboxController::getTypes() |
160 | 0 | { |
161 | 0 | return comphelper::concatSequences(ToolboxController_Base::getTypes(), |
162 | 0 | getBaseTypes()); |
163 | 0 | } |
164 | | |
165 | | void SAL_CALL ToolboxController::initialize( const Sequence< Any >& rArguments ) |
166 | 0 | { |
167 | 0 | SolarMutexGuard aSolarMutexGuard; |
168 | |
|
169 | 0 | if ( m_bDisposed ) |
170 | 0 | throw DisposedException(); |
171 | | |
172 | 0 | if ( m_bInitialized ) |
173 | 0 | return; |
174 | | |
175 | 0 | m_bInitialized = true; |
176 | 0 | m_bSupportVisible = false; |
177 | 0 | PropertyValue aPropValue; |
178 | 0 | for ( const auto& rArgument : rArguments ) |
179 | 0 | { |
180 | 0 | if ( rArgument >>= aPropValue ) |
181 | 0 | { |
182 | 0 | if ( aPropValue.Name == "Frame" ) |
183 | 0 | m_xFrame.set(aPropValue.Value,UNO_QUERY); |
184 | 0 | else if ( aPropValue.Name == "CommandURL" ) |
185 | 0 | aPropValue.Value >>= m_aCommandURL; |
186 | 0 | else if ( aPropValue.Name == "ServiceManager" ) |
187 | 0 | { |
188 | 0 | Reference<XMultiServiceFactory> xMSF(aPropValue.Value, UNO_QUERY); |
189 | 0 | if (xMSF.is()) |
190 | 0 | m_xContext = comphelper::getComponentContext(xMSF); |
191 | 0 | } |
192 | 0 | else if ( aPropValue.Name == "ParentWindow" ) |
193 | 0 | m_xParentWindow.set(aPropValue.Value,UNO_QUERY); |
194 | 0 | else if ( aPropValue.Name == "ModuleIdentifier" ) |
195 | 0 | aPropValue.Value >>= m_sModuleName; |
196 | 0 | else if ( aPropValue.Name == "Identifier" ) |
197 | 0 | { |
198 | 0 | sal_uInt16 nTmp; |
199 | 0 | if (aPropValue.Value >>= nTmp) |
200 | 0 | m_nToolBoxId = ToolBoxItemId(nTmp); |
201 | 0 | } |
202 | 0 | else if ( aPropValue.Name == "IsSidebar" ) |
203 | 0 | aPropValue.Value >>= m_bSidebar; |
204 | 0 | } |
205 | 0 | } |
206 | |
|
207 | 0 | try |
208 | 0 | { |
209 | 0 | if ( !m_xUrlTransformer.is() && m_xContext.is() ) |
210 | 0 | m_xUrlTransformer = URLTransformer::create( m_xContext ); |
211 | 0 | } |
212 | 0 | catch(const Exception&) |
213 | 0 | { |
214 | 0 | } |
215 | |
|
216 | 0 | if ( !m_aCommandURL.isEmpty() ) |
217 | 0 | m_aListenerMap.emplace( m_aCommandURL, Reference< XDispatch >() ); |
218 | |
|
219 | 0 | if (weld::TransportAsXWindow* pTunnel = dynamic_cast<weld::TransportAsXWindow*>(getParent().get())) |
220 | 0 | { |
221 | 0 | m_pToolbar = dynamic_cast<weld::Toolbar*>(pTunnel->getWidget()); |
222 | 0 | assert(m_pToolbar && "must be a toolbar"); |
223 | 0 | m_pBuilder = pTunnel->getBuilder(); |
224 | 0 | } |
225 | 0 | } |
226 | | |
227 | | void SAL_CALL ToolboxController::update() |
228 | 0 | { |
229 | 0 | { |
230 | 0 | SolarMutexGuard aSolarMutexGuard; |
231 | 0 | if ( m_bDisposed ) |
232 | 0 | throw DisposedException(); |
233 | 0 | } |
234 | | |
235 | | // Bind all registered listeners to their dispatch objects |
236 | 0 | bindListener(); |
237 | 0 | } |
238 | | |
239 | | // XComponent |
240 | | void SAL_CALL ToolboxController::dispose() |
241 | 0 | { |
242 | 0 | Reference< XComponent > xThis(this); |
243 | |
|
244 | 0 | { |
245 | 0 | SolarMutexGuard aSolarMutexGuard; |
246 | 0 | if ( m_bDisposed ) |
247 | 0 | return; |
248 | 0 | } |
249 | | |
250 | 0 | css::lang::EventObject aEvent( xThis ); |
251 | 0 | m_aListenerContainer.disposeAndClear( aEvent ); |
252 | |
|
253 | 0 | SolarMutexGuard aSolarMutexGuard; |
254 | 0 | Reference< XStatusListener > xStatusListener(this); |
255 | 0 | for (auto const& listener : m_aListenerMap) |
256 | 0 | { |
257 | 0 | try |
258 | 0 | { |
259 | 0 | Reference< XDispatch > xDispatch( listener.second ); |
260 | |
|
261 | 0 | css::util::URL aTargetURL; |
262 | 0 | aTargetURL.Complete = listener.first; |
263 | 0 | if ( m_xUrlTransformer.is() ) |
264 | 0 | m_xUrlTransformer->parseStrict( aTargetURL ); |
265 | |
|
266 | 0 | if ( xDispatch.is() && xStatusListener.is() ) |
267 | 0 | xDispatch->removeStatusListener( xStatusListener, aTargetURL ); |
268 | 0 | } |
269 | 0 | catch ( Exception& ) |
270 | 0 | { |
271 | 0 | } |
272 | |
|
273 | 0 | } |
274 | |
|
275 | 0 | m_bDisposed = true; |
276 | 0 | } |
277 | | |
278 | | void SAL_CALL ToolboxController::addEventListener( const Reference< XEventListener >& xListener ) |
279 | 0 | { |
280 | 0 | m_aListenerContainer.addInterface( cppu::UnoType<XEventListener>::get(), xListener ); |
281 | 0 | } |
282 | | |
283 | | void SAL_CALL ToolboxController::removeEventListener( const Reference< XEventListener >& rListener ) |
284 | 0 | { |
285 | 0 | m_aListenerContainer.removeInterface( cppu::UnoType<XEventListener>::get(), rListener ); |
286 | 0 | } |
287 | | |
288 | | // XEventListener |
289 | | void SAL_CALL ToolboxController::disposing( const EventObject& Source ) |
290 | 0 | { |
291 | 0 | Reference< XInterface > xSource( Source.Source ); |
292 | |
|
293 | 0 | SolarMutexGuard aSolarMutexGuard; |
294 | |
|
295 | 0 | if ( m_bDisposed ) |
296 | 0 | return; |
297 | | |
298 | 0 | for (auto & listener : m_aListenerMap) |
299 | 0 | { |
300 | | // Compare references and release dispatch references if they are equal. |
301 | 0 | Reference< XInterface > xIfac(listener.second, UNO_QUERY); |
302 | 0 | if ( xSource == xIfac ) |
303 | 0 | listener.second.clear(); |
304 | 0 | } |
305 | |
|
306 | 0 | Reference< XInterface > xIfac( m_xFrame, UNO_QUERY ); |
307 | 0 | if ( xIfac == xSource ) |
308 | 0 | m_xFrame.clear(); |
309 | 0 | } |
310 | | |
311 | | // XStatusListener |
312 | | void SAL_CALL ToolboxController::statusChanged( const FeatureStateEvent& ) |
313 | 0 | { |
314 | | // must be implemented by sub class |
315 | 0 | } |
316 | | |
317 | | // XToolbarController |
318 | | void SAL_CALL ToolboxController::execute( sal_Int16 KeyModifier ) |
319 | 0 | { |
320 | 0 | Reference< XDispatch > xDispatch; |
321 | 0 | OUString aCommandURL; |
322 | |
|
323 | 0 | { |
324 | 0 | SolarMutexGuard aSolarMutexGuard; |
325 | |
|
326 | 0 | if ( m_bDisposed ) |
327 | 0 | throw DisposedException(); |
328 | | |
329 | 0 | if ( m_bInitialized && |
330 | 0 | m_xFrame.is() && |
331 | 0 | !m_aCommandURL.isEmpty() ) |
332 | 0 | { |
333 | 0 | aCommandURL = m_aCommandURL; |
334 | 0 | URLToDispatchMap::iterator pIter = m_aListenerMap.find( m_aCommandURL ); |
335 | 0 | if ( pIter != m_aListenerMap.end() ) |
336 | 0 | xDispatch = pIter->second; |
337 | 0 | } |
338 | 0 | } |
339 | | |
340 | 0 | if ( !xDispatch.is() ) |
341 | 0 | return; |
342 | | |
343 | 0 | try |
344 | 0 | { |
345 | 0 | css::util::URL aTargetURL; |
346 | | |
347 | | // Provide key modifier information to dispatch function |
348 | 0 | Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue(u"KeyModifier"_ustr, KeyModifier) }; |
349 | |
|
350 | 0 | aTargetURL.Complete = aCommandURL; |
351 | 0 | if ( m_xUrlTransformer.is() ) |
352 | 0 | m_xUrlTransformer->parseStrict( aTargetURL ); |
353 | 0 | xDispatch->dispatch( aTargetURL, aArgs ); |
354 | 0 | } |
355 | 0 | catch ( DisposedException& ) |
356 | 0 | { |
357 | 0 | } |
358 | 0 | } |
359 | | |
360 | | void SAL_CALL ToolboxController::click() |
361 | 0 | { |
362 | 0 | } |
363 | | |
364 | | void SAL_CALL ToolboxController::doubleClick() |
365 | 0 | { |
366 | 0 | } |
367 | | |
368 | | Reference< XWindow > SAL_CALL ToolboxController::createPopupWindow() |
369 | 0 | { |
370 | 0 | return Reference< XWindow >(); |
371 | 0 | } |
372 | | |
373 | | Reference< XWindow > SAL_CALL ToolboxController::createItemWindow( const Reference< XWindow >& ) |
374 | 0 | { |
375 | 0 | return Reference< XWindow >(); |
376 | 0 | } |
377 | | |
378 | | void ToolboxController::addStatusListener( const OUString& rCommandURL ) |
379 | 0 | { |
380 | 0 | Reference< XDispatch > xDispatch; |
381 | 0 | Reference< XStatusListener > xStatusListener; |
382 | 0 | css::util::URL aTargetURL; |
383 | |
|
384 | 0 | { |
385 | 0 | SolarMutexGuard aSolarMutexGuard; |
386 | 0 | URLToDispatchMap::iterator pIter = m_aListenerMap.find( rCommandURL ); |
387 | | |
388 | | // Already in the list of status listener. Do nothing. |
389 | 0 | if ( pIter != m_aListenerMap.end() ) |
390 | 0 | return; |
391 | | |
392 | | // Check if we are already initialized. Implementation starts adding itself as status listener when |
393 | | // initialize is called. |
394 | 0 | if ( !m_bInitialized ) |
395 | 0 | { |
396 | | // Put into the unordered_map of status listener. Will be activated when initialized is called |
397 | 0 | m_aListenerMap.emplace( rCommandURL, Reference< XDispatch >() ); |
398 | 0 | return; |
399 | 0 | } |
400 | 0 | else |
401 | 0 | { |
402 | | // Add status listener directly as initialize has already been called. |
403 | 0 | Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY ); |
404 | 0 | if ( m_xContext.is() && xDispatchProvider.is() ) |
405 | 0 | { |
406 | 0 | aTargetURL.Complete = rCommandURL; |
407 | 0 | if ( m_xUrlTransformer.is() ) |
408 | 0 | m_xUrlTransformer->parseStrict( aTargetURL ); |
409 | 0 | xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 ); |
410 | |
|
411 | 0 | xStatusListener = this; |
412 | 0 | URLToDispatchMap::iterator aIter = m_aListenerMap.find( rCommandURL ); |
413 | 0 | if ( aIter != m_aListenerMap.end() ) |
414 | 0 | { |
415 | 0 | Reference< XDispatch > xOldDispatch( aIter->second ); |
416 | 0 | aIter->second = xDispatch; |
417 | |
|
418 | 0 | try |
419 | 0 | { |
420 | 0 | if ( xOldDispatch.is() ) |
421 | 0 | xOldDispatch->removeStatusListener( xStatusListener, aTargetURL ); |
422 | 0 | } |
423 | 0 | catch ( Exception& ) |
424 | 0 | { |
425 | 0 | } |
426 | 0 | } |
427 | 0 | else |
428 | 0 | m_aListenerMap.emplace( rCommandURL, xDispatch ); |
429 | 0 | } |
430 | 0 | } |
431 | 0 | } |
432 | | |
433 | | // Call without locked mutex as we are called back from dispatch implementation |
434 | 0 | try |
435 | 0 | { |
436 | 0 | if ( xDispatch.is() ) |
437 | 0 | xDispatch->addStatusListener( xStatusListener, aTargetURL ); |
438 | 0 | } |
439 | 0 | catch ( Exception& ) |
440 | 0 | { |
441 | 0 | } |
442 | 0 | } |
443 | | |
444 | | void ToolboxController::removeStatusListener( const OUString& rCommandURL ) |
445 | 0 | { |
446 | 0 | SolarMutexGuard aSolarMutexGuard; |
447 | |
|
448 | 0 | URLToDispatchMap::iterator pIter = m_aListenerMap.find( rCommandURL ); |
449 | 0 | if ( pIter == m_aListenerMap.end() ) |
450 | 0 | return; |
451 | | |
452 | 0 | Reference< XDispatch > xDispatch( pIter->second ); |
453 | 0 | Reference< XStatusListener > xStatusListener(this); |
454 | 0 | m_aListenerMap.erase( pIter ); |
455 | |
|
456 | 0 | try |
457 | 0 | { |
458 | 0 | css::util::URL aTargetURL; |
459 | 0 | aTargetURL.Complete = rCommandURL; |
460 | 0 | if ( m_xUrlTransformer.is() ) |
461 | 0 | m_xUrlTransformer->parseStrict( aTargetURL ); |
462 | |
|
463 | 0 | if ( xDispatch.is() && xStatusListener.is() ) |
464 | 0 | xDispatch->removeStatusListener( xStatusListener, aTargetURL ); |
465 | 0 | } |
466 | 0 | catch ( Exception& ) |
467 | 0 | { |
468 | 0 | } |
469 | 0 | } |
470 | | |
471 | | void ToolboxController::bindListener() |
472 | 0 | { |
473 | 0 | std::vector< Listener > aDispatchVector; |
474 | 0 | Reference< XStatusListener > xStatusListener; |
475 | |
|
476 | 0 | { |
477 | 0 | SolarMutexGuard aSolarMutexGuard; |
478 | |
|
479 | 0 | if ( !m_bInitialized ) |
480 | 0 | return; |
481 | | |
482 | | // Collect all registered command URL's and store them temporary |
483 | 0 | Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY ); |
484 | 0 | if ( m_xContext.is() && xDispatchProvider.is() ) |
485 | 0 | { |
486 | 0 | xStatusListener = this; |
487 | 0 | for (auto & listener : m_aListenerMap) |
488 | 0 | { |
489 | 0 | css::util::URL aTargetURL; |
490 | 0 | aTargetURL.Complete = listener.first; |
491 | 0 | if ( m_xUrlTransformer.is() ) |
492 | 0 | m_xUrlTransformer->parseStrict( aTargetURL ); |
493 | |
|
494 | 0 | Reference< XDispatch > xDispatch(listener.second); |
495 | 0 | if ( xDispatch.is() ) |
496 | 0 | { |
497 | | // We already have a dispatch object => we have to requery. |
498 | | // Release old dispatch object and remove it as listener |
499 | 0 | try |
500 | 0 | { |
501 | 0 | xDispatch->removeStatusListener( xStatusListener, aTargetURL ); |
502 | 0 | } |
503 | 0 | catch ( Exception& ) |
504 | 0 | { |
505 | 0 | } |
506 | 0 | } |
507 | |
|
508 | 0 | listener.second.clear(); |
509 | 0 | xDispatch.clear(); |
510 | | |
511 | | // Query for dispatch object. Old dispatch will be released with this, too. |
512 | 0 | try |
513 | 0 | { |
514 | 0 | xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 ); |
515 | 0 | } |
516 | 0 | catch ( Exception& ) |
517 | 0 | { |
518 | 0 | } |
519 | | |
520 | | // it may be a command alias |
521 | 0 | if (!xDispatch.is()) |
522 | 0 | { |
523 | 0 | try |
524 | 0 | { |
525 | 0 | auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(listener.first, |
526 | 0 | vcl::CommandInfoProvider::GetModuleIdentifier(m_xFrame)); |
527 | 0 | OUString sRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties); |
528 | |
|
529 | 0 | if (!sRealCommand.isEmpty()) |
530 | 0 | { |
531 | 0 | aTargetURL.Complete = sRealCommand; |
532 | 0 | if ( m_xUrlTransformer.is() ) |
533 | 0 | m_xUrlTransformer->parseStrict( aTargetURL ); |
534 | |
|
535 | 0 | xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 ); |
536 | 0 | } |
537 | 0 | } |
538 | 0 | catch ( Exception& ) |
539 | 0 | { |
540 | 0 | } |
541 | 0 | } |
542 | |
|
543 | 0 | listener.second = xDispatch; |
544 | |
|
545 | 0 | aDispatchVector.emplace_back(aTargetURL, xDispatch); |
546 | 0 | } |
547 | 0 | } |
548 | 0 | } |
549 | | |
550 | | // Call without locked mutex as we are called back from dispatch implementation |
551 | 0 | if ( !xStatusListener.is() ) |
552 | 0 | return; |
553 | | |
554 | 0 | try |
555 | 0 | { |
556 | 0 | for (Listener & rListener : aDispatchVector) |
557 | 0 | { |
558 | 0 | if ( rListener.xDispatch.is() ) |
559 | 0 | rListener.xDispatch->addStatusListener( xStatusListener, rListener.aURL ); |
560 | 0 | else if ( rListener.aURL.Complete == m_aCommandURL ) |
561 | 0 | { |
562 | 0 | try |
563 | 0 | { |
564 | | // Send status changed for the main URL, if we cannot get a valid dispatch object. |
565 | | // UI disables the button. Catch exception as we release our mutex, it is possible |
566 | | // that someone else already disposed this instance! |
567 | 0 | FeatureStateEvent aFeatureStateEvent; |
568 | 0 | aFeatureStateEvent.IsEnabled = false; |
569 | 0 | aFeatureStateEvent.FeatureURL = rListener.aURL; |
570 | 0 | aFeatureStateEvent.State = Any(); |
571 | 0 | xStatusListener->statusChanged( aFeatureStateEvent ); |
572 | 0 | } |
573 | 0 | catch ( Exception& ) |
574 | 0 | { |
575 | 0 | } |
576 | 0 | } |
577 | 0 | } |
578 | 0 | } |
579 | 0 | catch ( Exception& ) |
580 | 0 | { |
581 | 0 | } |
582 | 0 | } |
583 | | |
584 | | void ToolboxController::unbindListener() |
585 | 0 | { |
586 | 0 | SolarMutexGuard aSolarMutexGuard; |
587 | |
|
588 | 0 | if ( !m_bInitialized ) |
589 | 0 | return; |
590 | | |
591 | | // Collect all registered command URL's and store them temporary |
592 | 0 | Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY ); |
593 | 0 | if ( !(m_xContext.is() && xDispatchProvider.is()) ) |
594 | 0 | return; |
595 | | |
596 | 0 | Reference< XStatusListener > xStatusListener(this); |
597 | 0 | for (auto & listener : m_aListenerMap) |
598 | 0 | { |
599 | 0 | css::util::URL aTargetURL; |
600 | 0 | aTargetURL.Complete = listener.first; |
601 | 0 | if ( m_xUrlTransformer.is() ) |
602 | 0 | m_xUrlTransformer->parseStrict( aTargetURL ); |
603 | |
|
604 | 0 | Reference< XDispatch > xDispatch(listener.second); |
605 | 0 | if ( xDispatch.is() ) |
606 | 0 | { |
607 | | // We already have a dispatch object => we have to requery. |
608 | | // Release old dispatch object and remove it as listener |
609 | 0 | try |
610 | 0 | { |
611 | 0 | xDispatch->removeStatusListener( xStatusListener, aTargetURL ); |
612 | 0 | } |
613 | 0 | catch ( Exception& ) |
614 | 0 | { |
615 | 0 | } |
616 | 0 | } |
617 | 0 | listener.second.clear(); |
618 | 0 | } |
619 | 0 | } |
620 | | |
621 | | void ToolboxController::updateStatus() |
622 | 0 | { |
623 | 0 | bindListener(); |
624 | 0 | } |
625 | | |
626 | | void ToolboxController::updateStatus( const OUString& rCommandURL ) |
627 | 0 | { |
628 | 0 | Reference< XDispatch > xDispatch; |
629 | 0 | Reference< XStatusListener > xStatusListener; |
630 | 0 | css::util::URL aTargetURL; |
631 | |
|
632 | 0 | { |
633 | 0 | SolarMutexGuard aSolarMutexGuard; |
634 | |
|
635 | 0 | if ( !m_bInitialized ) |
636 | 0 | return; |
637 | | |
638 | | // Try to find a dispatch object for the requested command URL |
639 | 0 | Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY ); |
640 | 0 | xStatusListener = this; |
641 | 0 | if ( m_xContext.is() && xDispatchProvider.is() ) |
642 | 0 | { |
643 | 0 | aTargetURL.Complete = rCommandURL; |
644 | 0 | if ( m_xUrlTransformer.is() ) |
645 | 0 | m_xUrlTransformer->parseStrict( aTargetURL ); |
646 | 0 | xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 ); |
647 | 0 | } |
648 | 0 | } |
649 | | |
650 | 0 | if ( !(xDispatch.is() && xStatusListener.is()) ) |
651 | 0 | return; |
652 | | |
653 | | // Catch exception as we release our mutex, it is possible that someone else |
654 | | // has already disposed this instance! |
655 | | // Add/remove status listener to get an update status information from the |
656 | | // requested command. |
657 | 0 | try |
658 | 0 | { |
659 | 0 | xDispatch->addStatusListener( xStatusListener, aTargetURL ); |
660 | 0 | xDispatch->removeStatusListener( xStatusListener, aTargetURL ); |
661 | 0 | } |
662 | 0 | catch ( Exception& ) |
663 | 0 | { |
664 | 0 | } |
665 | 0 | } |
666 | | |
667 | | |
668 | | void ToolboxController::dispatchCommand( const OUString& sCommandURL, const Sequence< PropertyValue >& rArgs, const OUString &sTarget ) |
669 | 0 | { |
670 | 0 | try |
671 | 0 | { |
672 | 0 | Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY_THROW ); |
673 | 0 | URL aURL; |
674 | 0 | aURL.Complete = sCommandURL; |
675 | 0 | getURLTransformer()->parseStrict( aURL ); |
676 | |
|
677 | 0 | Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch( aURL, sTarget, 0 ), UNO_SET_THROW ); |
678 | |
|
679 | 0 | std::unique_ptr<DispatchInfo> pDispatchInfo(new DispatchInfo( xDispatch, std::move(aURL), rArgs )); |
680 | 0 | if ( Application::PostUserEvent( LINK(nullptr, ToolboxController, ExecuteHdl_Impl), |
681 | 0 | pDispatchInfo.get() ) ) |
682 | 0 | pDispatchInfo.release(); |
683 | |
|
684 | 0 | } |
685 | 0 | catch( Exception& ) |
686 | 0 | { |
687 | 0 | } |
688 | 0 | } |
689 | | |
690 | | |
691 | | css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ToolboxController::getPropertySetInfo() |
692 | 0 | { |
693 | 0 | Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); |
694 | 0 | return xInfo; |
695 | 0 | } |
696 | | |
697 | | ::cppu::IPropertyArrayHelper& ToolboxController::getInfoHelper() |
698 | 0 | { |
699 | 0 | return *getArrayHelper(); |
700 | 0 | } |
701 | | |
702 | | |
703 | | ::cppu::IPropertyArrayHelper* ToolboxController::createArrayHelper( ) const |
704 | 0 | { |
705 | 0 | css::uno::Sequence< Property > aProps; |
706 | 0 | describeProperties(aProps); |
707 | 0 | return new ::cppu::OPropertyArrayHelper(aProps); |
708 | 0 | } |
709 | | |
710 | | sal_Bool SAL_CALL ToolboxController::convertFastPropertyValue(css::uno::Any& aConvertedValue, |
711 | | css::uno::Any& aOldValue, |
712 | | sal_Int32 nHandle, |
713 | | const css::uno::Any& rValue) |
714 | 0 | { |
715 | 0 | switch (nHandle) |
716 | 0 | { |
717 | 0 | case TOOLBARCONTROLLER_PROPHANDLE_SUPPORTSVISIBLE: |
718 | 0 | { |
719 | 0 | bool aNewValue(false); |
720 | 0 | rValue >>= aNewValue; |
721 | 0 | if (aNewValue != m_bSupportVisible) |
722 | 0 | { |
723 | 0 | aConvertedValue <<= aNewValue; |
724 | 0 | aOldValue <<= m_bSupportVisible; |
725 | 0 | return true; |
726 | 0 | } |
727 | 0 | return false; |
728 | 0 | } |
729 | 0 | } |
730 | 0 | return OPropertyContainer::convertFastPropertyValue(aConvertedValue, aOldValue, nHandle, rValue); |
731 | 0 | } |
732 | | |
733 | | void SAL_CALL ToolboxController::setFastPropertyValue_NoBroadcast( |
734 | | sal_Int32 nHandle, |
735 | | const css::uno::Any& rValue ) |
736 | 0 | { |
737 | 0 | OPropertyContainer::setFastPropertyValue_NoBroadcast(nHandle, rValue); |
738 | 0 | if (TOOLBARCONTROLLER_PROPHANDLE_SUPPORTSVISIBLE == nHandle) |
739 | 0 | { |
740 | 0 | bool bValue(false); |
741 | 0 | if (( rValue >>= bValue ) && m_bInitialized) |
742 | 0 | m_bSupportVisible = bValue; |
743 | 0 | } |
744 | 0 | } |
745 | | |
746 | | |
747 | | IMPL_STATIC_LINK( ToolboxController, ExecuteHdl_Impl, void*, p, void ) |
748 | 0 | { |
749 | 0 | DispatchInfo* pDispatchInfo = static_cast<DispatchInfo*>(p); |
750 | 0 | pDispatchInfo->mxDispatch->dispatch( pDispatchInfo->maURL, pDispatchInfo->maArgs ); |
751 | 0 | delete pDispatchInfo; |
752 | 0 | } |
753 | | |
754 | | void ToolboxController::enable( bool bEnable ) |
755 | 0 | { |
756 | 0 | ToolBox* pToolBox = nullptr; |
757 | 0 | ToolBoxItemId nItemId; |
758 | 0 | if( getToolboxId( nItemId, &pToolBox ) ) |
759 | 0 | { |
760 | 0 | pToolBox->EnableItem( nItemId, bEnable ); |
761 | 0 | } |
762 | 0 | } |
763 | | |
764 | | bool ToolboxController::getToolboxId( ToolBoxItemId& rItemId, ToolBox** ppToolBox ) |
765 | 0 | { |
766 | 0 | if( (m_nToolBoxId != ToolBoxItemId(SAL_MAX_UINT16)) && (ppToolBox == nullptr) ) |
767 | 0 | return false; |
768 | | |
769 | 0 | ToolBox* pToolBox = static_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) ); |
770 | |
|
771 | 0 | if( (m_nToolBoxId == ToolBoxItemId(SAL_MAX_UINT16)) && pToolBox ) |
772 | 0 | { |
773 | 0 | const ToolBox::ImplToolItems::size_type nCount = pToolBox->GetItemCount(); |
774 | 0 | for ( ToolBox::ImplToolItems::size_type nPos = 0; nPos < nCount; ++nPos ) |
775 | 0 | { |
776 | 0 | const ToolBoxItemId nItemId = pToolBox->GetItemId( nPos ); |
777 | 0 | if ( pToolBox->GetItemCommand( nItemId ) == m_aCommandURL ) |
778 | 0 | { |
779 | 0 | m_nToolBoxId = nItemId; |
780 | 0 | break; |
781 | 0 | } |
782 | 0 | } |
783 | 0 | } |
784 | |
|
785 | 0 | if( ppToolBox ) |
786 | 0 | *ppToolBox = pToolBox; |
787 | |
|
788 | 0 | rItemId = m_nToolBoxId; |
789 | |
|
790 | 0 | return (rItemId != ToolBoxItemId(SAL_MAX_UINT16)) && (( ppToolBox == nullptr) || (*ppToolBox != nullptr) ); |
791 | 0 | } |
792 | | //end |
793 | | |
794 | | } // svt |
795 | | |
796 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |