1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <comphelper/propertysequence.hxx>
21 #include <cppuhelper/implbase.hxx>
22 #include <cppuhelper/supportsservice.hxx>
23 #include <cppuhelper/weakref.hxx>
24 #include <svtools/popupwindowcontroller.hxx>
25 #include <svtools/toolbarmenu.hxx>
26 #include <toolkit/helper/vclunohelper.hxx>
27 #include <tools/gen.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/toolbox.hxx>
30 #include <vcl/commandinfoprovider.hxx>
31 #include <vcl/weldutils.hxx>
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>
41 typedef cppu::ImplInheritanceHelper
< svt::PopupWindowController
,
42 css::frame::XSubToolbarController
,
43 css::awt::XDockableWindowListener
> ToolBarBase
;
47 class SubToolBarController
: public ToolBarBase
49 OUString m_aSubTbName
;
50 OUString m_aLastCommand
;
51 css::uno::Reference
< css::ui::XUIElement
> m_xUIElement
;
52 void disposeUIElement();
54 explicit SubToolBarController( const rtl::Reference
< css::uno::XComponentContext
>& rxContext
,
55 const css::uno::Sequence
< css::uno::Any
>& rxArgs
);
56 virtual ~SubToolBarController() override
;
58 void PopoverDestroyed();
61 virtual void SAL_CALL
initialize( const css::uno::Sequence
< css::uno::Any
>& rxArgs
) override
;
64 virtual void SAL_CALL
statusChanged( const css::frame::FeatureStateEvent
& Event
) override
;
67 virtual void SAL_CALL
execute( sal_Int16 nKeyModifier
) override
;
69 // PopupWindowController
70 virtual VclPtr
<vcl::Window
> createVclPopupWindow(vcl::Window
* pParent
) override
;
71 virtual std::unique_ptr
<WeldToolbarPopup
> weldPopupWindow() override
;
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
;
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
;
89 virtual void SAL_CALL
disposing( const css::lang::EventObject
& e
) override
;
92 virtual void SAL_CALL
dispose() override
;
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
;
102 SubToolBarController::SubToolBarController(
103 const rtl::Reference
< css::uno::XComponentContext
>& rxContext
,
104 const css::uno::Sequence
< css::uno::Any
>& rxArgs
107 rtl::Reference
< css::frame::XFrame
>(),
111 for ( css::uno::Any
const & arg
: rxArgs
)
113 css::beans::PropertyValue aPropValue
;
115 if ( aPropValue
.Name
== "Value" )
119 aPropValue
.Value
>>= aValue
;
120 m_aSubTbName
= aValue
.getToken(0, ';', nIdx
);
121 m_aCommandURL
= m_aSubTbName
;
122 m_aLastCommand
= aValue
.getToken(0, ';', nIdx
);
126 if ( !m_aLastCommand
.isEmpty() )
127 addStatusListener( m_aLastCommand
);
130 SubToolBarController::~SubToolBarController()
133 m_xUIElement
= nullptr;
136 void SubToolBarController::disposeUIElement()
138 if ( m_xUIElement
.is() )
140 css::uno::Reference
< css::lang::XComponent
> xComponent( m_xUIElement
, css::uno::UNO_QUERY
);
141 xComponent
->dispose();
145 void SubToolBarController::statusChanged( const css::frame::FeatureStateEvent
& Event
)
147 SolarMutexGuard aSolarMutexGuard
;
152 ToolBox
* pToolBox
= nullptr;
154 if ( !getToolboxId( nId
, &pToolBox
) )
157 ToolBoxItemBits nItemBits
= pToolBox
->GetItemBits( nId
);
158 nItemBits
&= ~ToolBoxItemBits::CHECKABLE
;
159 TriState eTri
= TRISTATE_FALSE
;
161 if ( Event
.FeatureURL
.Complete
== m_aCommandURL
)
163 pToolBox
->EnableItem( nId
, Event
.IsEnabled
);
166 css::frame::status::Visibility aItemVisibility
;
167 if ( Event
.State
>>= aStrValue
)
169 // Enum command, such as the current custom shape,
170 // toggle checked state.
171 if ( m_aLastCommand
== Concat2View( m_aCommandURL
+ "." + aStrValue
) )
173 eTri
= TRISTATE_TRUE
;
174 nItemBits
|= ToolBoxItemBits::CHECKABLE
;
177 else if ( Event
.State
>>= aItemVisibility
)
179 pToolBox
->ShowItem( nId
, aItemVisibility
.bVisible
);
185 if ( Event
.State
>>= bValue
)
187 // Boolean, treat it as checked/unchecked
189 eTri
= TRISTATE_TRUE
;
190 nItemBits
|= ToolBoxItemBits::CHECKABLE
;
194 pToolBox
->SetItemState( nId
, eTri
);
195 pToolBox
->SetItemBits( nId
, nItemBits
);
198 void SubToolBarController::execute( sal_Int16 nKeyModifier
)
200 if ( !m_aLastCommand
.isEmpty() )
202 auto aArgs( comphelper::InitPropertySequence( {
203 { "KeyModifier", css::uno::Any( nKeyModifier
) }
205 dispatchCommand( m_aLastCommand
, aArgs
);
210 class SubToolbarControl final
: public WeldToolbarPopup
213 explicit SubToolbarControl(SubToolBarController
& rController
, weld::Widget
* pParent
);
214 virtual ~SubToolbarControl() override
;
216 virtual void GrabFocus() override
;
218 weld::Container
* GetContainer() { return m_xTargetContainer
.get(); }
221 SubToolBarController
& m_rController
;
222 std::unique_ptr
<weld::Container
> m_xTargetContainer
;
226 SubToolbarControl::SubToolbarControl(SubToolBarController
& rController
,
227 weld::Widget
* pParent
)
228 : WeldToolbarPopup(rController
.getFrameInterface(), pParent
, u
"svt/ui/subtoolbar.ui"_ustr
, u
"subtoolbar"_ustr
)
229 , m_rController(rController
)
230 , m_xTargetContainer(m_xBuilder
->weld_container(u
"container"_ustr
))
234 void SubToolbarControl::GrabFocus()
239 SubToolbarControl::~SubToolbarControl()
241 m_rController
.PopoverDestroyed();
244 std::unique_ptr
<WeldToolbarPopup
> SubToolBarController::weldPopupWindow()
246 SolarMutexGuard aGuard
;
248 auto pPopup
= std::make_unique
<SubToolbarControl
>(*this, m_pToolbar
);
250 css::uno::Reference
< css::frame::XFrame
> xFrame ( getFrameInterface() );
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() )
257 xUIElementFactory
= css::ui::theUIElementFactoryManager::get( m_xContext
);
258 xWeakUIElementFactory
= xUIElementFactory
;
261 css::uno::Reference
< css::awt::XWindow
> xParent
= new weld::TransportAsXWindow(pPopup
->GetContainer());
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 ) }
272 m_xUIElement
= xUIElementFactory
->createUIElement( "private:resource/toolbar/" + m_aSubTbName
, aPropSeq
);
274 catch ( css::container::NoSuchElementException
& )
276 catch ( css::lang::IllegalArgumentException
& )
282 VclPtr
<vcl::Window
> SubToolBarController::createVclPopupWindow(vcl::Window
* /*pParent*/)
284 SolarMutexGuard aGuard
;
286 ToolBox
* pToolBox
= nullptr;
288 if ( getToolboxId( nId
, &pToolBox
) )
290 css::uno::Reference
< css::frame::XFrame
> xFrame ( getFrameInterface() );
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() )
298 xUIElementFactory
= css::ui::theUIElementFactoryManager::get( m_xContext
);
299 xWeakUIElementFactory
= xUIElementFactory
;
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 ) }
311 xUIElement
= xUIElementFactory
->createUIElement( "private:resource/toolbar/" + m_aSubTbName
, aPropSeq
);
313 catch ( css::container::NoSuchElementException
& )
315 catch ( css::lang::IllegalArgumentException
& )
318 if ( xUIElement
.is() )
320 css::uno::Reference
< css::awt::XWindow
> xSubToolBar( xUIElement
->getRealInterface(), css::uno::UNO_QUERY
);
321 if ( xSubToolBar
.is() )
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 );
327 // keep reference to UIElement to avoid its destruction
329 m_xUIElement
= std::move(xUIElement
);
331 VclPtr
<vcl::Window
> pTbxWindow
= VCLUnoHelper::GetWindow( xSubToolBar
);
332 if ( pTbxWindow
&& pTbxWindow
->GetType() == WindowType::TOOLBOX
)
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
);
347 sal_Bool
SubToolBarController::opensSubToolbar()
349 return !m_aLastCommand
.isEmpty();
352 OUString
SubToolBarController::getSubToolbarName()
357 void SubToolBarController::functionSelected( const OUString
& rCommand
)
359 if ( !m_aLastCommand
.isEmpty() && m_aLastCommand
!= rCommand
)
361 removeStatusListener( m_aLastCommand
);
362 m_aLastCommand
= rCommand
;
363 addStatusListener( m_aLastCommand
);
368 void SubToolBarController::updateImage()
370 SolarMutexGuard aGuard
;
371 if ( !m_aLastCommand
.isEmpty() )
373 ToolBox
* pToolBox
= nullptr;
375 if ( getToolboxId( nId
, &pToolBox
) )
377 vcl::ImageType eImageType
= pToolBox
->GetImageSize();
378 Image aImage
= vcl::CommandInfoProvider::GetImageForCommand(m_aLastCommand
, getFrameInterface(), eImageType
);
380 pToolBox
->SetItemImage( nId
, aImage
);
385 void SubToolBarController::startDocking( const css::awt::DockingEvent
& )
389 css::awt::DockingData
SubToolBarController::docking( const css::awt::DockingEvent
& )
391 return css::awt::DockingData();
394 void SubToolBarController::endDocking( const css::awt::EndDockingEvent
& )
398 sal_Bool
SubToolBarController::prepareToggleFloatingMode( const css::lang::EventObject
& )
403 void SubToolBarController::toggleFloatingMode( const css::lang::EventObject
& )
407 void SubToolBarController::closed( const css::lang::EventObject
& )
411 void SubToolBarController::endPopupMode( const css::awt::EndPopupModeEvent
& e
)
413 SolarMutexGuard aGuard
;
415 OUString aSubToolBarResName
;
416 if ( m_xUIElement
.is() )
418 css::uno::Reference
< css::beans::XPropertySet
> xPropSet( m_xUIElement
, css::uno::UNO_QUERY
);
423 xPropSet
->getPropertyValue(u
"ResourceURL"_ustr
) >>= aSubToolBarResName
;
425 catch ( css::beans::UnknownPropertyException
& )
427 catch ( css::lang::WrappedTargetException
& )
432 m_xUIElement
= nullptr;
434 // if the toolbar was teared-off recreate it and place it at the given position
438 css::uno::Reference
< css::ui::XUIElement
> xUIElement
;
439 css::uno::Reference
< css::frame::XLayoutManager
> xLayoutManager
= getLayoutManager();
441 if ( !xLayoutManager
.is() )
444 xLayoutManager
->createElement( aSubToolBarResName
);
445 xUIElement
= xLayoutManager
->getElement( aSubToolBarResName
);
446 if ( !xUIElement
.is() )
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()) )
456 VclPtr
<vcl::Window
> pTbxWindow
= VCLUnoHelper::GetWindow( xSubToolBar
);
457 if ( pTbxWindow
&& pTbxWindow
->GetType() == WindowType::TOOLBOX
)
459 OUString
aPersistentString( u
"Persistent"_ustr
);
460 css::uno::Any a
= xProp
->getPropertyValue( aPersistentString
);
461 xProp
->setPropertyValue( aPersistentString
, css::uno::Any( false ) );
463 xLayoutManager
->hideElement( aSubToolBarResName
);
464 xLayoutManager
->floatWindow( aSubToolBarResName
);
466 xLayoutManager
->setElementPos( aSubToolBarResName
, e
.FloatingPosition
);
467 xLayoutManager
->showElement( aSubToolBarResName
);
469 xProp
->setPropertyValue(u
"Persistent"_ustr
, a
);
472 catch ( css::uno::RuntimeException
& )
476 catch ( css::uno::Exception
& )
480 void SubToolBarController::disposing( const css::lang::EventObject
& e
)
482 svt::ToolboxController::disposing( e
);
485 void SubToolBarController::initialize( const css::uno::Sequence
< css::uno::Any
>& rxArgs
)
487 svt::PopupWindowController::initialize( rxArgs
);
489 ToolBox
* pToolBox
= nullptr;
491 if ( getToolboxId( nId
, &pToolBox
) )
493 if ( m_aLastCommand
.isEmpty() )
494 pToolBox
->SetItemBits( nId
, pToolBox
->GetItemBits( nId
) | ToolBoxItemBits::DROPDOWNONLY
);
496 pToolBox
->SetItemBits( nId
, pToolBox
->GetItemBits( nId
) | ToolBoxItemBits::DROPDOWN
);
501 mxPopoverContainer
.reset(new ToolbarPopupContainer(m_pToolbar
));
502 m_pToolbar
->set_item_popover(m_aCommandURL
, mxPopoverContainer
->getTopLevel());
508 void SubToolBarController::PopoverDestroyed()
511 m_xUIElement
= nullptr;
514 void SubToolBarController::dispose()
519 svt::PopupWindowController::dispose();
521 m_xUIElement
= nullptr;
524 OUString
SubToolBarController::getImplementationName()
526 return u
"com.sun.star.comp.framework.SubToolBarController"_ustr
;
529 sal_Bool
SubToolBarController::supportsService( const OUString
& rServiceName
)
531 return cppu::supportsService( this, rServiceName
);
534 css::uno::Sequence
< OUString
> SubToolBarController::getSupportedServiceNames()
536 return {u
"com.sun.star.frame.ToolbarController"_ustr
};
539 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
540 com_sun_star_comp_framework_SubToolBarController_get_implementation(
541 css::uno::XComponentContext
* rxContext
,
542 css::uno::Sequence
<css::uno::Any
> const & rxArgs
)
544 return cppu::acquire( new SubToolBarController( rxContext
, rxArgs
) );
547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */