LibreOffice Module framework (master) 1
subtoolbarcontroller.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
27#include <tools/gen.hxx>
28#include <vcl/svapp.hxx>
29#include <vcl/toolbox.hxx>
31#include <vcl/weldutils.hxx>
32
33#include <com/sun/star/awt/XDockableWindow.hpp>
34#include <com/sun/star/frame/XLayoutManager.hpp>
35#include <com/sun/star/frame/XSubToolbarController.hpp>
36#include <com/sun/star/frame/status/Visibility.hpp>
37#include <com/sun/star/lang/XServiceInfo.hpp>
38#include <com/sun/star/ui/theUIElementFactoryManager.hpp>
39#include <com/sun/star/container/NoSuchElementException.hpp>
40
41typedef cppu::ImplInheritanceHelper< svt::PopupWindowController,
42 css::frame::XSubToolbarController,
43 css::awt::XDockableWindowListener> ToolBarBase;
44
45namespace {
46
47class SubToolBarController : public ToolBarBase
48{
49 OUString m_aSubTbName;
50 OUString m_aLastCommand;
51 css::uno::Reference< css::ui::XUIElement > m_xUIElement;
52 void disposeUIElement();
53public:
54 explicit SubToolBarController( const rtl::Reference< com::sun::star::uno::XComponentContext >& rxContext,
55 const css::uno::Sequence< css::uno::Any >& rxArgs );
56 virtual ~SubToolBarController() override;
57
58 void PopoverDestroyed();
59
60 // XInitialization
61 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& rxArgs ) override;
62
63 // XStatusListener
64 virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override;
65
66 // XToolbarController
67 virtual void SAL_CALL execute( sal_Int16 nKeyModifier ) override;
68
69 // PopupWindowController
70 virtual VclPtr<vcl::Window> createVclPopupWindow(vcl::Window* pParent) override;
71 virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
72
73 // XSubToolbarController
74 virtual sal_Bool SAL_CALL opensSubToolbar() override;
75 virtual OUString SAL_CALL getSubToolbarName() override;
76 virtual void SAL_CALL functionSelected( const OUString& rCommand ) override;
77 virtual void SAL_CALL updateImage() override;
78
79 // XDockableWindowListener
80 virtual void SAL_CALL startDocking( const css::awt::DockingEvent& e ) override;
81 virtual css::awt::DockingData SAL_CALL docking( const css::awt::DockingEvent& e ) override;
82 virtual void SAL_CALL endDocking( const css::awt::EndDockingEvent& e ) override;
83 virtual sal_Bool SAL_CALL prepareToggleFloatingMode( const css::lang::EventObject& e ) override;
84 virtual void SAL_CALL toggleFloatingMode( const css::lang::EventObject& e ) override;
85 virtual void SAL_CALL closed( const css::lang::EventObject& e ) override;
86 virtual void SAL_CALL endPopupMode( const css::awt::EndPopupModeEvent& e ) override;
87
88 // XEventListener
89 virtual void SAL_CALL disposing( const css::lang::EventObject& e ) override;
90
91 // XComponent
92 virtual void SAL_CALL dispose() override;
93
94 // XServiceInfo
95 virtual OUString SAL_CALL getImplementationName() override;
96 virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
97 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
98};
99
100}
101
102SubToolBarController::SubToolBarController(
104 const css::uno::Sequence< css::uno::Any >& rxArgs
105) : ToolBarBase(
106 rxContext,
107 rtl::Reference< css::frame::XFrame >(),
108 ""
109 )
110{
111 for ( css::uno::Any const & arg : rxArgs )
112 {
113 css::beans::PropertyValue aPropValue;
114 arg >>= aPropValue;
115 if ( aPropValue.Name == "Value" )
116 {
117 sal_Int32 nIdx{ 0 };
118 OUString aValue;
119 aPropValue.Value >>= aValue;
120 m_aSubTbName = aValue.getToken(0, ';', nIdx);
121 m_aCommandURL = m_aSubTbName;
122 m_aLastCommand = aValue.getToken(0, ';', nIdx);
123 break;
124 }
125 }
126 if ( !m_aLastCommand.isEmpty() )
127 addStatusListener( m_aLastCommand );
128}
129
130SubToolBarController::~SubToolBarController()
131{
132 disposeUIElement();
133 m_xUIElement = nullptr;
134}
135
136void SubToolBarController::disposeUIElement()
137{
138 if ( m_xUIElement.is() )
139 {
140 css::uno::Reference< css::lang::XComponent > xComponent( m_xUIElement, css::uno::UNO_QUERY );
141 xComponent->dispose();
142 }
143}
144
145void SubToolBarController::statusChanged( const css::frame::FeatureStateEvent& Event )
146{
147 SolarMutexGuard aSolarMutexGuard;
148
149 if ( m_bDisposed )
150 return;
151
152 ToolBox* pToolBox = nullptr;
154 if ( !getToolboxId( nId, &pToolBox ) )
155 return;
156
157 ToolBoxItemBits nItemBits = pToolBox->GetItemBits( nId );
158 nItemBits &= ~ToolBoxItemBits::CHECKABLE;
160
161 if ( Event.FeatureURL.Complete == m_aCommandURL )
162 {
163 pToolBox->EnableItem( nId, Event.IsEnabled );
164
165 OUString aStrValue;
166 css::frame::status::Visibility aItemVisibility;
167 if ( Event.State >>= aStrValue )
168 {
169 // Enum command, such as the current custom shape,
170 // toggle checked state.
171 if ( m_aLastCommand == Concat2View( m_aCommandURL + "." + aStrValue ) )
172 {
173 eTri = TRISTATE_TRUE;
174 nItemBits |= ToolBoxItemBits::CHECKABLE;
175 }
176 }
177 else if ( Event.State >>= aItemVisibility )
178 {
179 pToolBox->ShowItem( nId, aItemVisibility.bVisible );
180 }
181 }
182 else
183 {
184 bool bValue;
185 if ( Event.State >>= bValue )
186 {
187 // Boolean, treat it as checked/unchecked
188 if ( bValue )
189 eTri = TRISTATE_TRUE;
190 nItemBits |= ToolBoxItemBits::CHECKABLE;
191 }
192 }
193
194 pToolBox->SetItemState( nId, eTri );
195 pToolBox->SetItemBits( nId, nItemBits );
196}
197
198void SubToolBarController::execute( sal_Int16 nKeyModifier )
199{
200 if ( !m_aLastCommand.isEmpty() )
201 {
203 { "KeyModifier", css::uno::Any( nKeyModifier ) }
204 } ) );
205 dispatchCommand( m_aLastCommand, aArgs );
206 }
207}
208
209namespace {
210class SubToolbarControl final : public WeldToolbarPopup
211{
212public:
213 explicit SubToolbarControl(SubToolBarController& rController, weld::Widget* pParent);
214 virtual ~SubToolbarControl() override;
215
216 virtual void GrabFocus() override;
217
218 weld::Container* GetContainer() { return m_xTargetContainer.get(); }
219
220private:
221 SubToolBarController& m_rController;
222 std::unique_ptr<weld::Container> m_xTargetContainer;
223};
224}
225
226SubToolbarControl::SubToolbarControl(SubToolBarController& rController,
227 weld::Widget* pParent)
228 : WeldToolbarPopup(rController.getFrameInterface(), pParent, "svt/ui/subtoolbar.ui", "subtoolbar")
229 , m_rController(rController)
230 , m_xTargetContainer(m_xBuilder->weld_container("container"))
231{
232}
233
234void SubToolbarControl::GrabFocus()
235{
236 // TODO
237}
238
239SubToolbarControl::~SubToolbarControl()
240{
241 m_rController.PopoverDestroyed();
242}
243
244std::unique_ptr<WeldToolbarPopup> SubToolBarController::weldPopupWindow()
245{
246 SolarMutexGuard aGuard;
247
248 auto pPopup = std::make_unique<SubToolbarControl>(*this, m_pToolbar);
249
250 css::uno::Reference< css::frame::XFrame > xFrame ( getFrameInterface() );
251
252 // create element with factory
253 static css::uno::WeakReference< css::ui::XUIElementFactoryManager > xWeakUIElementFactory;
254 css::uno::Reference< css::ui::XUIElementFactoryManager > xUIElementFactory = xWeakUIElementFactory;
255 if ( !xUIElementFactory.is() )
256 {
257 xUIElementFactory = css::ui::theUIElementFactoryManager::get( m_xContext );
258 xWeakUIElementFactory = xUIElementFactory;
259 }
260
261 css::uno::Reference< css::awt::XWindow > xParent = new weld::TransportAsXWindow(pPopup->GetContainer());
262
263 auto aPropSeq( comphelper::InitPropertySequence( {
264 { "Frame", css::uno::Any( xFrame ) },
265 { "ParentWindow", css::uno::Any( xParent ) },
266 { "Persistent", css::uno::Any( false ) },
267 { "PopupMode", css::uno::Any( true ) }
268 } ) );
269
270 try
271 {
272 m_xUIElement = xUIElementFactory->createUIElement( "private:resource/toolbar/" + m_aSubTbName, aPropSeq );
273 }
274 catch ( css::container::NoSuchElementException& )
275 {}
276 catch ( css::lang::IllegalArgumentException& )
277 {}
278
279 return pPopup;
280}
281
282VclPtr<vcl::Window> SubToolBarController::createVclPopupWindow(vcl::Window* /*pParent*/)
283{
284 SolarMutexGuard aGuard;
285
286 ToolBox* pToolBox = nullptr;
288 if ( getToolboxId( nId, &pToolBox ) )
289 {
290 css::uno::Reference< css::frame::XFrame > xFrame ( getFrameInterface() );
291
292 // create element with factory
293 static css::uno::WeakReference< css::ui::XUIElementFactoryManager > xWeakUIElementFactory;
294 css::uno::Reference< css::ui::XUIElement > xUIElement;
295 css::uno::Reference< css::ui::XUIElementFactoryManager > xUIElementFactory = xWeakUIElementFactory;
296 if ( !xUIElementFactory.is() )
297 {
298 xUIElementFactory = css::ui::theUIElementFactoryManager::get( m_xContext );
299 xWeakUIElementFactory = xUIElementFactory;
300 }
301
302 auto aPropSeq( comphelper::InitPropertySequence( {
303 { "Frame", css::uno::Any( xFrame ) },
304 { "ParentWindow", css::uno::Any( m_xParentWindow ) },
305 { "Persistent", css::uno::Any( false ) },
306 { "PopupMode", css::uno::Any( true ) }
307 } ) );
308
309 try
310 {
311 xUIElement = xUIElementFactory->createUIElement( "private:resource/toolbar/" + m_aSubTbName, aPropSeq );
312 }
313 catch ( css::container::NoSuchElementException& )
314 {}
315 catch ( css::lang::IllegalArgumentException& )
316 {}
317
318 if ( xUIElement.is() )
319 {
320 css::uno::Reference< css::awt::XWindow > xSubToolBar( xUIElement->getRealInterface(), css::uno::UNO_QUERY );
321 if ( xSubToolBar.is() )
322 {
323 css::uno::Reference< css::awt::XDockableWindow > xDockWindow( xSubToolBar, css::uno::UNO_QUERY );
324 xDockWindow->addDockableWindowListener( css::uno::Reference< css::awt::XDockableWindowListener >(this) );
325 xDockWindow->enableDocking( true );
326
327 // keep reference to UIElement to avoid its destruction
328 disposeUIElement();
329 m_xUIElement = xUIElement;
330
331 VclPtr<vcl::Window> pTbxWindow = VCLUnoHelper::GetWindow( xSubToolBar );
332 if ( pTbxWindow && pTbxWindow->GetType() == WindowType::TOOLBOX )
333 {
334 ToolBox* pToolBar = static_cast< ToolBox* >( pTbxWindow.get() );
335 // calc and set size for popup mode
336 Size aSize = pToolBar->CalcPopupWindowSizePixel();
337 pToolBar->SetSizePixel( aSize );
338 // open subtoolbox in popup mode
339 vcl::Window::GetDockingManager()->StartPopupMode( pToolBox, pToolBar );
340 }
341 }
342 }
343 }
344 return nullptr;
345}
346
347sal_Bool SubToolBarController::opensSubToolbar()
348{
349 return !m_aLastCommand.isEmpty();
350}
351
352OUString SubToolBarController::getSubToolbarName()
353{
354 return m_aSubTbName;
355}
356
357void SubToolBarController::functionSelected( const OUString& rCommand )
358{
359 if ( !m_aLastCommand.isEmpty() && m_aLastCommand != rCommand )
360 {
361 removeStatusListener( m_aLastCommand );
362 m_aLastCommand = rCommand;
363 addStatusListener( m_aLastCommand );
364 updateImage();
365 }
366}
367
368void SubToolBarController::updateImage()
369{
370 SolarMutexGuard aGuard;
371 if ( !m_aLastCommand.isEmpty() )
372 {
373 ToolBox* pToolBox = nullptr;
375 if ( getToolboxId( nId, &pToolBox ) )
376 {
377 vcl::ImageType eImageType = pToolBox->GetImageSize();
378 Image aImage = vcl::CommandInfoProvider::GetImageForCommand(m_aLastCommand, getFrameInterface(), eImageType);
379 if ( !!aImage )
380 pToolBox->SetItemImage( nId, aImage );
381 }
382 }
383}
384
385void SubToolBarController::startDocking( const css::awt::DockingEvent& )
386{
387}
388
389css::awt::DockingData SubToolBarController::docking( const css::awt::DockingEvent& )
390{
391 return css::awt::DockingData();
392}
393
394void SubToolBarController::endDocking( const css::awt::EndDockingEvent& )
395{
396}
397
398sal_Bool SubToolBarController::prepareToggleFloatingMode( const css::lang::EventObject& )
399{
400 return false;
401}
402
403void SubToolBarController::toggleFloatingMode( const css::lang::EventObject& )
404{
405}
406
407void SubToolBarController::closed( const css::lang::EventObject& )
408{
409}
410
411void SubToolBarController::endPopupMode( const css::awt::EndPopupModeEvent& e )
412{
413 SolarMutexGuard aGuard;
414
415 OUString aSubToolBarResName;
416 if ( m_xUIElement.is() )
417 {
418 css::uno::Reference< css::beans::XPropertySet > xPropSet( m_xUIElement, css::uno::UNO_QUERY );
419 if ( xPropSet.is() )
420 {
421 try
422 {
423 xPropSet->getPropertyValue("ResourceURL") >>= aSubToolBarResName;
424 }
425 catch ( css::beans::UnknownPropertyException& )
426 {}
427 catch ( css::lang::WrappedTargetException& )
428 {}
429 }
430 disposeUIElement();
431 }
432 m_xUIElement = nullptr;
433
434 // if the toolbar was teared-off recreate it and place it at the given position
435 if( !e.bTearoff )
436 return;
437
438 css::uno::Reference< css::ui::XUIElement > xUIElement;
439 css::uno::Reference< css::frame::XLayoutManager > xLayoutManager = getLayoutManager();
440
441 if ( !xLayoutManager.is() )
442 return;
443
444 xLayoutManager->createElement( aSubToolBarResName );
445 xUIElement = xLayoutManager->getElement( aSubToolBarResName );
446 if ( !xUIElement.is() )
447 return;
448
449 css::uno::Reference< css::awt::XWindow > xSubToolBar( xUIElement->getRealInterface(), css::uno::UNO_QUERY );
450 css::uno::Reference< css::beans::XPropertySet > xProp( xUIElement, css::uno::UNO_QUERY );
451 if ( !(xSubToolBar.is() && xProp.is()) )
452 return;
453
454 try
455 {
456 VclPtr<vcl::Window> pTbxWindow = VCLUnoHelper::GetWindow( xSubToolBar );
457 if ( pTbxWindow && pTbxWindow->GetType() == WindowType::TOOLBOX )
458 {
459 OUString aPersistentString( "Persistent" );
460 css::uno::Any a = xProp->getPropertyValue( aPersistentString );
461 xProp->setPropertyValue( aPersistentString, css::uno::Any( false ) );
462
463 xLayoutManager->hideElement( aSubToolBarResName );
464 xLayoutManager->floatWindow( aSubToolBarResName );
465
466 xLayoutManager->setElementPos( aSubToolBarResName, e.FloatingPosition );
467 xLayoutManager->showElement( aSubToolBarResName );
468
469 xProp->setPropertyValue("Persistent", a );
470 }
471 }
472 catch ( css::uno::RuntimeException& )
473 {
474 throw;
475 }
476 catch ( css::uno::Exception& )
477 {}
478}
479
480void SubToolBarController::disposing( const css::lang::EventObject& e )
481{
483}
484
485void SubToolBarController::initialize( const css::uno::Sequence< css::uno::Any >& rxArgs )
486{
487 svt::PopupWindowController::initialize( rxArgs );
488
489 ToolBox* pToolBox = nullptr;
491 if ( getToolboxId( nId, &pToolBox ) )
492 {
493 if ( m_aLastCommand.isEmpty() )
494 pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
495 else
496 pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWN );
497 }
498
499 if (m_pToolbar)
500 {
501 mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
502 m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel());
503 }
504
505 updateImage();
506}
507
508void SubToolBarController::PopoverDestroyed()
509{
510 disposeUIElement();
511 m_xUIElement = nullptr;
512}
513
514void SubToolBarController::dispose()
515{
516 if ( m_bDisposed )
517 return;
518
520 disposeUIElement();
521 m_xUIElement = nullptr;
522}
523
524OUString SubToolBarController::getImplementationName()
525{
526 return "com.sun.star.comp.framework.SubToolBarController";
527}
528
529sal_Bool SubToolBarController::supportsService( const OUString& rServiceName )
530{
531 return cppu::supportsService( this, rServiceName );
532}
533
534css::uno::Sequence< OUString > SubToolBarController::getSupportedServiceNames()
535{
536 return {"com.sun.star.frame.ToolbarController"};
537}
538
539extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
541 css::uno::XComponentContext* rxContext,
542 css::uno::Sequence<css::uno::Any> const & rxArgs )
543{
544 return cppu::acquire( new SubToolBarController( rxContext, rxArgs ) );
545}
546
547/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void StartPopupMode(const vcl::Window *pWin, const tools::Rectangle &rRect, FloatWinPopupFlags nPopupModeFlags)
vcl::ImageType GetImageSize() const
void EnableItem(ToolBoxItemId nItemId, bool bEnable=true)
void ShowItem(ToolBoxItemId nItemId, bool bVisible=true)
Size CalcPopupWindowSizePixel()
void SetItemState(ToolBoxItemId nItemId, TriState eState)
void SetItemImage(ToolBoxItemId nItemId, const Image &rImage)
ToolBoxItemBits GetItemBits(ToolBoxItemId nItemId) const
void SetItemBits(ToolBoxItemId nItemId, ToolBoxItemBits nBits)
static vcl::Window * GetWindow(const css::uno::Reference< css::awt::XWindow > &rxWindow)
reference_type * get() const
virtual void GrabFocus()=0
ClassificationCategoriesController & m_rController
virtual void SAL_CALL dispose() override
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
virtual void SetSizePixel(const Size &rNewSize)
static DockingManager * GetDockingManager()
TriState
TRISTATE_FALSE
TRISTATE_TRUE
css::uno::Reference< css::uno::XComponentContext > m_xContext
bool m_bDisposed
uno_Any a
bool dispatchCommand(const OUString &rCommand, const uno::Reference< css::frame::XFrame > &rFrame, const css::uno::Sequence< css::beans::PropertyValue > &rArguments, const uno::Reference< css::frame::XDispatchResultListener > &rListener)
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
Reference
void dispose()
Image GetImageForCommand(const OUString &rsCommandName, const Reference< frame::XFrame > &rxFrame, vcl::ImageType eImageType)
sal_Int16 nId
Reference< XFrame > xFrame
cppu::ImplInheritanceHelper< svt::PopupWindowController, css::frame::XSubToolbarController, css::awt::XDockableWindowListener > ToolBarBase
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_framework_SubToolBarController_get_implementation(css::uno::XComponentContext *rxContext, css::uno::Sequence< css::uno::Any > const &rxArgs)
unsigned char sal_Bool
ToolBoxItemBits