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 .
21 #include <sfx2/taskpane.hxx>
22 #include <sfx2/imagemgr.hxx>
23 #include <sfx2/sfxsids.hrc>
24 #include <sfx2/bindings.hxx>
25 #include <sfx2/dispatch.hxx>
26 #include <sfx2/sfxresid.hxx>
27 #include "sfxlocal.hrc"
30 #include <com/sun/star/frame/ModuleManager.hpp>
31 #include <com/sun/star/container/XNameAccess.hpp>
32 #include <com/sun/star/ui/XToolPanel.hpp>
33 #include <com/sun/star/ui/XUIElementFactory.hpp>
34 #include <com/sun/star/awt/XWindowPeer.hpp>
35 #include <com/sun/star/awt/PosSize.hpp>
36 #include <com/sun/star/graphic/GraphicProvider.hpp>
37 #include <com/sun/star/graphic/XGraphicProvider.hpp>
38 #include <com/sun/star/accessibility/XAccessible.hpp>
39 #include <com/sun/star/awt/XControl.hpp>
40 #include <com/sun/star/ui/theUIElementFactoryManager.hpp>
42 #include <comphelper/namedvaluecollection.hxx>
43 #include <comphelper/types.hxx>
44 #include <comphelper/processfactory.hxx>
45 #include <tools/diagnose_ex.h>
46 #include <svtools/miscopt.hxx>
47 #include <svtools/toolpanel/toolpaneldeck.hxx>
48 #include <svtools/toolpanel/tablayouter.hxx>
49 #include <svtools/toolpanel/drawerlayouter.hxx>
50 #include <unotools/confignode.hxx>
51 #include <vcl/menu.hxx>
52 #include <vcl/svapp.hxx>
53 #include <toolkit/helper/vclunohelper.hxx>
54 #include <tools/urlobj.hxx>
55 #include <boost/noncopyable.hpp>
62 using ::com::sun::star::uno::Reference
;
63 using ::com::sun::star::uno::XComponentContext
;
64 using ::com::sun::star::uno::XInterface
;
65 using ::com::sun::star::uno::UNO_QUERY
;
66 using ::com::sun::star::uno::UNO_QUERY_THROW
;
67 using ::com::sun::star::uno::UNO_SET_THROW
;
68 using ::com::sun::star::uno::Exception
;
69 using ::com::sun::star::uno::RuntimeException
;
70 using ::com::sun::star::uno::Any
;
71 using ::com::sun::star::uno::makeAny
;
72 using ::com::sun::star::uno::Sequence
;
73 using ::com::sun::star::uno::Type
;
74 using ::com::sun::star::frame::ModuleManager
;
75 using ::com::sun::star::frame::XModuleManager2
;
76 using ::com::sun::star::container::XNameAccess
;
77 using ::com::sun::star::ui::XToolPanel
;
78 using ::com::sun::star::ui::XUIElementFactory
;
79 using ::com::sun::star::ui::XUIElementFactoryManager
;
80 using ::com::sun::star::ui::theUIElementFactoryManager
;
81 using ::com::sun::star::ui::XUIElement
;
82 using ::com::sun::star::awt::XWindow
;
83 using ::com::sun::star::frame::XFrame
;
84 using ::com::sun::star::lang::XComponent
;
85 using ::com::sun::star::graphic::XGraphicProvider
;
86 using ::com::sun::star::graphic::XGraphic
;
87 using ::com::sun::star::accessibility::XAccessible
;
88 using ::com::sun::star::awt::XControl
;
90 namespace PosSize
= ::com::sun::star::awt::PosSize
;
98 ::utl::OConfigurationTreeRoot
lcl_getModuleUIElementStatesConfig( const OUString
& i_rModuleIdentifier
,
99 const OUString
& i_rResourceURL
= OUString() )
101 const Reference
<XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
102 OUStringBuffer aPathComposer
;
105 const Reference
< XModuleManager2
> xModuleAccess( ModuleManager::create(xContext
) );
106 const ::comphelper::NamedValueCollection
aModuleProps( xModuleAccess
->getByName( i_rModuleIdentifier
) );
108 const OUString
sWindowStateRef( aModuleProps
.getOrDefault( "ooSetupFactoryWindowStateConfigRef", OUString() ) );
110 aPathComposer
.append( "org.openoffice.Office.UI." );
111 aPathComposer
.append( sWindowStateRef
);
112 aPathComposer
.append( "/UIElements/States" );
113 if ( !i_rResourceURL
.isEmpty() )
115 aPathComposer
.append('/').append( i_rResourceURL
);
118 catch( const Exception
& )
120 DBG_UNHANDLED_EXCEPTION();
122 return ::utl::OConfigurationTreeRoot( xContext
, aPathComposer
.makeStringAndClear(), false );
126 OUString
lcl_identifyModule( const Reference
< XFrame
>& i_rDocumentFrame
)
128 OUString sModuleName
;
131 const Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
132 const Reference
< XModuleManager2
> xModuleManager( ModuleManager::create(xContext
) );
133 sModuleName
= xModuleManager
->identify( i_rDocumentFrame
);
135 catch( const Exception
& )
137 DBG_UNHANDLED_EXCEPTION();
143 Reference
< XFrame
> lcl_getFrame( const SfxBindings
* i_pBindings
)
145 const SfxViewFrame
* pViewFrame
= i_pBindings
->GetDispatcher()->GetFrame();
146 const SfxFrame
& rFrame
= pViewFrame
->GetFrame();
147 const Reference
< XFrame
> xFrame( rFrame
.GetFrameInterface() );
152 OUString
lcl_getPanelHelpURL( const ::utl::OConfigurationNode
& i_rPanelConfigNode
)
154 const OUString
sHelpURL( ::comphelper::getString( i_rPanelConfigNode
.getNodeValue( "HelpURL" ) ) );
159 Image
lcl_getPanelImage( const Reference
< XFrame
>& i_rDocFrame
, const ::utl::OConfigurationNode
& i_rPanelConfigNode
)
161 const OUString
sImageURL( ::comphelper::getString( i_rPanelConfigNode
.getNodeValue( "ImageURL" ) ) );
162 if ( !sImageURL
.isEmpty() )
166 ::comphelper::NamedValueCollection aMediaProperties
;
167 aMediaProperties
.put( "URL", sImageURL
);
169 // special handling: if the ImageURL denotes a CommandName, then retrieve the image for that command
170 static const sal_Char pCommandImagePrefix
[] = "private:commandimage/";
171 const sal_Int32 nCommandImagePrefixLen
= strlen( pCommandImagePrefix
);
172 if ( sImageURL
.startsWith( pCommandImagePrefix
) )
174 OUStringBuffer aCommandName
;
175 aCommandName
.append( ".uno:" );
176 aCommandName
.append( sImageURL
.copy( nCommandImagePrefixLen
) );
177 const OUString
sCommandName( aCommandName
.makeStringAndClear() );
179 const Image
aPanelImage( GetImage( i_rDocFrame
, sCommandName
, false ) );
183 // otherwise, delegate to the GraphicProvider
184 const Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
185 const Reference
< XGraphicProvider
> xGraphicProvider( com::sun::star::graphic::GraphicProvider::create(xContext
) );
187 const Reference
< XGraphic
> xGraphic( xGraphicProvider
->queryGraphic( aMediaProperties
.getPropertyValues() ), UNO_SET_THROW
);
188 return Image( xGraphic
);
190 catch( const Exception
& )
192 DBG_UNHANDLED_EXCEPTION();
200 //= TaskPaneDockingWindow
203 TaskPaneDockingWindow::TaskPaneDockingWindow( SfxBindings
* i_pBindings
, TaskPaneWrapper
& i_rWrapper
, vcl::Window
* i_pParent
, WinBits i_nBits
)
204 :TitledDockingWindow( i_pBindings
, &i_rWrapper
, i_pParent
, i_nBits
)
205 ,m_aTaskPane( VclPtr
<ModuleTaskPane
>::Create(GetContentWindow(), lcl_getFrame( i_pBindings
)) )
206 ,m_aPaneController( *m_aTaskPane
.get(), *this )
209 SetText( SfxResId( SID_TASKPANE
).toString() );
212 TaskPaneDockingWindow::~TaskPaneDockingWindow()
217 void TaskPaneDockingWindow::dispose()
219 m_aTaskPane
.disposeAndClear();
220 TitledDockingWindow::dispose();
224 void TaskPaneDockingWindow::ActivateToolPanel( const OUString
& i_rPanelURL
)
226 m_aPaneController
.ActivateToolPanel( i_rPanelURL
);
230 void TaskPaneDockingWindow::GetFocus()
232 TitledDockingWindow::GetFocus();
233 m_aTaskPane
->GrabFocus();
237 void TaskPaneDockingWindow::onLayoutDone()
239 m_aTaskPane
->SetPosSizePixel( Point(), GetContentWindow().GetOutputSizePixel() );
246 SFX_IMPL_DOCKINGWINDOW( TaskPaneWrapper
, SID_TASKPANE
);
249 TaskPaneWrapper::TaskPaneWrapper( vcl::Window
* i_pParent
, sal_uInt16 i_nId
, SfxBindings
* i_pBindings
, SfxChildWinInfo
* i_pInfo
)
250 :SfxChildWindow( i_pParent
, i_nId
)
252 pWindow
= VclPtr
<TaskPaneDockingWindow
>::Create( i_pBindings
, *this, i_pParent
,
253 WB_STDDOCKWIN
| WB_CLIPCHILDREN
| WB_SIZEABLE
| WB_3DLOOK
| WB_ROLLABLE
);
254 eChildAlignment
= SfxChildAlignment::RIGHT
;
256 pWindow
->SetHelpId( HID_TASKPANE_WINDOW
);
257 pWindow
->SetOutputSizePixel( Size( 300, 450 ) );
259 dynamic_cast<SfxDockingWindow
&>(*pWindow
).Initialize(i_pInfo
);
260 SetHideNotDelete( true );
266 void TaskPaneWrapper::ActivateToolPanel( const OUString
& i_rPanelURL
)
268 TaskPaneDockingWindow
* pDockingWindow
= dynamic_cast< TaskPaneDockingWindow
* >( GetWindow() );
269 ENSURE_OR_RETURN_VOID( pDockingWindow
, "TaskPaneWrapper::ActivateToolPanel: invalid docking window implementation!" );
270 pDockingWindow
->ActivateToolPanel( i_rPanelURL
);
274 //= CustomPanelUIElement
276 class CustomPanelUIElement
279 CustomPanelUIElement()
286 CustomPanelUIElement( const Reference
< XUIElement
>& i_rUIElement
)
287 :m_xUIElement( i_rUIElement
)
288 ,m_xToolPanel( i_rUIElement
->getRealInterface(), UNO_QUERY_THROW
)
289 ,m_xPanelWindow( m_xToolPanel
->getWindow(), UNO_SET_THROW
)
293 bool is() const { return m_xPanelWindow
.is(); }
295 const Reference
< XUIElement
>& getUIElement() const { return m_xUIElement
; }
296 const Reference
< XToolPanel
>& getToolPanel() const { return m_xToolPanel
; }
297 const Reference
< XWindow
>& getPanelWindow() const { return m_xPanelWindow
; }
300 Reference
< XUIElement
> m_xUIElement
;
301 Reference
< XToolPanel
> m_xToolPanel
;
302 Reference
< XWindow
> m_xPanelWindow
;
308 class CustomToolPanel
: public ::svt::ToolPanelBase
311 CustomToolPanel( const ::utl::OConfigurationNode
& i_rPanelWindowState
, const Reference
< XFrame
>& i_rFrame
);
313 virtual OUString
GetDisplayName() const SAL_OVERRIDE
;
314 virtual Image
GetImage() const SAL_OVERRIDE
;
315 virtual OString
GetHelpID() const SAL_OVERRIDE
;
316 virtual void Activate( vcl::Window
& i_rParentWindow
) SAL_OVERRIDE
;
317 virtual void Deactivate() SAL_OVERRIDE
;
318 virtual void SetSizePixel( const Size
& i_rPanelWindowSize
) SAL_OVERRIDE
;
319 virtual void GrabFocus() SAL_OVERRIDE
;
320 virtual void Dispose() SAL_OVERRIDE
;
321 virtual Reference
< XAccessible
>
322 CreatePanelAccessible( const Reference
< XAccessible
>& i_rParentAccessible
) SAL_OVERRIDE
;
325 GetResourceURL() const { return m_sResourceURL
; }
328 virtual ~CustomToolPanel();
331 bool impl_ensureToolPanelWindow( vcl::Window
& i_rPanelParentWindow
);
332 void impl_updatePanelConfig( const bool i_bVisible
) const;
335 const OUString m_sUIName
;
336 const Image m_aPanelImage
;
337 const OUString m_aPanelHelpURL
;
338 const OUString m_sResourceURL
;
339 const OUString m_sPanelConfigPath
;
340 Reference
< XFrame
> m_xFrame
;
341 CustomPanelUIElement m_aCustomPanel
;
342 bool m_bAttemptedCreation
;
346 CustomToolPanel::CustomToolPanel( const ::utl::OConfigurationNode
& i_rPanelWindowState
, const Reference
< XFrame
>& i_rFrame
)
347 :m_sUIName( ::comphelper::getString( i_rPanelWindowState
.getNodeValue( "UIName" ) ) )
348 ,m_aPanelImage( lcl_getPanelImage( i_rFrame
, i_rPanelWindowState
) )
349 ,m_aPanelHelpURL( lcl_getPanelHelpURL( i_rPanelWindowState
) )
350 ,m_sResourceURL( i_rPanelWindowState
.getLocalName() )
351 ,m_sPanelConfigPath( i_rPanelWindowState
.getNodePath() )
352 ,m_xFrame( i_rFrame
)
354 ,m_bAttemptedCreation( false )
359 CustomToolPanel::~CustomToolPanel()
364 bool CustomToolPanel::impl_ensureToolPanelWindow( vcl::Window
& i_rPanelParentWindow
)
366 if ( m_bAttemptedCreation
)
367 return m_aCustomPanel
.is();
369 m_bAttemptedCreation
= true;
372 const Reference
< XUIElementFactoryManager
> xFactory
= theUIElementFactoryManager::get( ::comphelper::getProcessComponentContext() );
374 ::comphelper::NamedValueCollection aCreationArgs
;
375 aCreationArgs
.put( "Frame", makeAny( m_xFrame
) );
376 aCreationArgs
.put( "ParentWindow", makeAny( i_rPanelParentWindow
.GetComponentInterface() ) );
378 const Reference
< XUIElement
> xElement(
379 xFactory
->createUIElement( m_sResourceURL
, aCreationArgs
.getPropertyValues() ),
382 m_aCustomPanel
= CustomPanelUIElement( xElement
);
384 catch( const Exception
& )
386 DBG_UNHANDLED_EXCEPTION();
388 return m_aCustomPanel
.is();
392 void CustomToolPanel::impl_updatePanelConfig( const bool i_bVisible
) const
394 ::utl::OConfigurationTreeRoot
aConfig( ::comphelper::getProcessComponentContext(), m_sPanelConfigPath
, true );
396 aConfig
.setNodeValue( "Visible", makeAny( i_bVisible
) );
401 OUString
CustomToolPanel::GetDisplayName() const
407 Image
CustomToolPanel::GetImage() const
409 return m_aPanelImage
;
412 static OString
lcl_getHelpId( const OUString
& _rHelpURL
)
414 INetURLObject
aHID( _rHelpURL
);
415 if ( aHID
.GetProtocol() == INetProtocol::Hid
)
416 return OUStringToOString( aHID
.GetURLPath(), RTL_TEXTENCODING_UTF8
);
418 return OUStringToOString( _rHelpURL
, RTL_TEXTENCODING_UTF8
);
422 OString
CustomToolPanel::GetHelpID() const
424 return lcl_getHelpId( m_aPanelHelpURL
);
428 void CustomToolPanel::Activate( vcl::Window
& i_rParentWindow
)
430 ENSURE_OR_RETURN_VOID( impl_ensureToolPanelWindow( i_rParentWindow
), "no panel to activate!" );
432 // TODO: we might need a mechanism to decide whether the panel should be destroyed/re-created, or (as it is
433 // done now) hidden/shown
434 m_aCustomPanel
.getPanelWindow()->setVisible( sal_True
);
436 // update the panel's configuration
437 impl_updatePanelConfig( true );
441 void CustomToolPanel::Deactivate()
443 ENSURE_OR_RETURN_VOID( m_aCustomPanel
.is(), "no panel to deactivate!" );
445 m_aCustomPanel
.getPanelWindow()->setVisible( sal_False
);
447 // update the panel's configuration
448 impl_updatePanelConfig( false );
452 void CustomToolPanel::SetSizePixel( const Size
& i_rPanelWindowSize
)
454 ENSURE_OR_RETURN_VOID( m_aCustomPanel
.is(), "no panel/window to position!" );
458 m_aCustomPanel
.getPanelWindow()->setPosSize( 0, 0, i_rPanelWindowSize
.Width(), i_rPanelWindowSize
.Height(),
461 catch( const Exception
& )
463 DBG_UNHANDLED_EXCEPTION();
468 void CustomToolPanel::GrabFocus()
470 ENSURE_OR_RETURN_VOID( m_aCustomPanel
.is(), "no panel/window to focus!" );
472 m_aCustomPanel
.getPanelWindow()->setFocus();
476 void CustomToolPanel::Dispose()
478 if ( !m_bAttemptedCreation
)
479 // nothing to dispose
482 ENSURE_OR_RETURN_VOID( m_aCustomPanel
.is(), "no panel to destroy!" );
485 Reference
< XComponent
> xUIElementComponent( m_aCustomPanel
.getUIElement(), UNO_QUERY_THROW
);
486 xUIElementComponent
->dispose();
488 catch( const Exception
& )
490 DBG_UNHANDLED_EXCEPTION();
495 Reference
< XAccessible
> CustomToolPanel::CreatePanelAccessible( const Reference
< XAccessible
>& i_rParentAccessible
)
497 ENSURE_OR_RETURN( m_aCustomPanel
.is(), "no panel to ask!", NULL
);
499 Reference
< XAccessible
> xPanelAccessible
;
502 xPanelAccessible
.set( m_aCustomPanel
.getToolPanel()->createAccessible( i_rParentAccessible
), UNO_SET_THROW
);
504 catch( const Exception
& )
506 DBG_UNHANDLED_EXCEPTION();
508 return xPanelAccessible
;
512 //= ModuleTaskPane_Impl
514 class ModuleTaskPane_Impl
: public ::boost::noncopyable
517 ModuleTaskPane_Impl( ModuleTaskPane
& i_rAntiImpl
, const Reference
< XFrame
>& i_rDocumentFrame
)
518 :m_rAntiImpl( i_rAntiImpl
)
519 ,m_sModuleIdentifier( lcl_identifyModule( i_rDocumentFrame
) )
520 ,m_xFrame( i_rDocumentFrame
)
521 ,m_aPanelDeck( VclPtr
< ::svt::ToolPanelDeck
>::Create(i_rAntiImpl
) )
523 m_aPanelDeck
->Show();
525 impl_initFromConfiguration();
528 ~ModuleTaskPane_Impl()
535 static bool ModuleHasToolPanels( const OUString
& i_rModuleIdentifier
);
537 ::svt::ToolPanelDeck
& GetPanelDeck() { return *m_aPanelDeck
.get(); }
539 ::boost::optional
< size_t >
540 GetPanelPos( const OUString
& i_rResourceURL
);
542 void SetDrawersLayout();
543 void SetTabsLayout( const ::svt::TabAlignment i_eTabAlignment
, const ::svt::TabItemContent i_eTabContent
);
546 void impl_initFromConfiguration();
549 impl_isToolPanelResource( const OUString
& i_rResourceURL
);
551 DECL_LINK( OnActivatePanel
, void* );
554 ModuleTaskPane
& m_rAntiImpl
;
555 const OUString m_sModuleIdentifier
;
556 const Reference
< XFrame
> m_xFrame
;
557 VclPtr
< ::svt::ToolPanelDeck
> m_aPanelDeck
;
561 void ModuleTaskPane_Impl::OnResize()
563 m_aPanelDeck
->SetPosSizePixel( Point(), m_rAntiImpl
.GetOutputSizePixel() );
567 void ModuleTaskPane_Impl::OnGetFocus()
569 m_aPanelDeck
->GrabFocus();
573 IMPL_LINK( ModuleTaskPane_Impl
, OnActivatePanel
, void*, i_pArg
)
575 m_aPanelDeck
->ActivatePanel( reinterpret_cast< size_t >( i_pArg
) );
580 bool ModuleTaskPane_Impl::impl_isToolPanelResource( const OUString
& i_rResourceURL
)
582 return i_rResourceURL
.startsWith( "private:resource/toolpanel/" );
586 void ModuleTaskPane_Impl::impl_initFromConfiguration()
588 const ::utl::OConfigurationTreeRoot
aWindowStateConfig( lcl_getModuleUIElementStatesConfig( m_sModuleIdentifier
) );
589 if ( !aWindowStateConfig
.isValid() )
592 OUString sFirstVisiblePanelResource
;
593 OUString sFirstPanelResource
;
595 const Sequence
< OUString
> aUIElements( aWindowStateConfig
.getNodeNames() );
596 for ( const OUString
* resource
= aUIElements
.getConstArray();
597 resource
!= aUIElements
.getConstArray() + aUIElements
.getLength();
601 if ( !impl_isToolPanelResource( *resource
) )
604 sFirstPanelResource
= *resource
;
606 ::utl::OConfigurationNode
aResourceNode( aWindowStateConfig
.openNode( *resource
) );
607 ::svt::PToolPanel
pCustomPanel( new CustomToolPanel( aResourceNode
, m_xFrame
) );
609 size_t nPanelPos
= m_aPanelDeck
->GetPanelCount();
610 nPanelPos
= m_aPanelDeck
->InsertPanel( pCustomPanel
, nPanelPos
);
612 if ( ::comphelper::getBOOL( aResourceNode
.getNodeValue( "Visible" ) ) )
613 sFirstVisiblePanelResource
= *resource
;
616 if ( sFirstVisiblePanelResource
.isEmpty() )
617 sFirstVisiblePanelResource
= sFirstPanelResource
;
619 if ( !sFirstVisiblePanelResource
.isEmpty() )
621 ::boost::optional
< size_t > aPanelPos( GetPanelPos( sFirstVisiblePanelResource
) );
622 OSL_ENSURE( !!aPanelPos
, "ModuleTaskPane_Impl::impl_isToolPanelResource: just inserted it, and it's not there?!" );
624 m_rAntiImpl
.PostUserEvent( LINK( this, ModuleTaskPane_Impl
, OnActivatePanel
), reinterpret_cast< void* >( *aPanelPos
) );
629 bool ModuleTaskPane_Impl::ModuleHasToolPanels( const OUString
& i_rModuleIdentifier
)
631 const ::utl::OConfigurationTreeRoot
aWindowStateConfig( lcl_getModuleUIElementStatesConfig( i_rModuleIdentifier
) );
632 if ( !aWindowStateConfig
.isValid() )
635 const Sequence
< OUString
> aUIElements( aWindowStateConfig
.getNodeNames() );
636 for ( const OUString
* resource
= aUIElements
.getConstArray();
637 resource
!= aUIElements
.getConstArray() + aUIElements
.getLength();
641 if ( impl_isToolPanelResource( *resource
) )
648 ::boost::optional
< size_t > ModuleTaskPane_Impl::GetPanelPos( const OUString
& i_rResourceURL
)
650 ::boost::optional
< size_t > aPanelPos
;
651 for ( size_t i
= 0; i
< m_aPanelDeck
->GetPanelCount(); ++i
)
653 const ::svt::PToolPanel
pPanel( m_aPanelDeck
->GetPanel( i
) );
654 const CustomToolPanel
* pCustomPanel
= dynamic_cast< const CustomToolPanel
* >( pPanel
.get() );
657 SAL_WARN( "sfx.dialog", "ModuleTaskPane_Impl::GetPanelPos: illegal panel implementation!" );
661 if ( pCustomPanel
->GetResourceURL() == i_rResourceURL
)
670 void ModuleTaskPane_Impl::SetDrawersLayout()
672 const ::svt::PDeckLayouter
pLayouter( m_aPanelDeck
->GetLayouter() );
673 const ::svt::DrawerDeckLayouter
* pDrawerLayouter
= dynamic_cast< const ::svt::DrawerDeckLayouter
* >( pLayouter
.get() );
674 if ( pDrawerLayouter
!= NULL
)
675 // already have the proper layout
677 m_aPanelDeck
->SetLayouter( new ::svt::DrawerDeckLayouter( *m_aPanelDeck
.get(), *m_aPanelDeck
.get() ) );
681 void ModuleTaskPane_Impl::SetTabsLayout( const ::svt::TabAlignment i_eTabAlignment
, const ::svt::TabItemContent i_eTabContent
)
683 ::svt::PDeckLayouter
pLayouter( m_aPanelDeck
->GetLayouter() );
684 ::svt::TabDeckLayouter
* pTabLayouter
= dynamic_cast< ::svt::TabDeckLayouter
* >( pLayouter
.get() );
685 if ( ( pTabLayouter
!= NULL
)
686 && ( pTabLayouter
->GetTabAlignment() == i_eTabAlignment
)
687 && ( pTabLayouter
->GetTabItemContent() == i_eTabContent
)
689 // already have the requested layout
692 if ( pTabLayouter
&& ( pTabLayouter
->GetTabAlignment() == i_eTabAlignment
) )
694 // changing only the item content does not require a new layouter instance
695 pTabLayouter
->SetTabItemContent( i_eTabContent
);
699 m_aPanelDeck
->SetLayouter( new ::svt::TabDeckLayouter( *m_aPanelDeck
.get(), *m_aPanelDeck
.get(), i_eTabAlignment
, i_eTabContent
) );
706 ModuleTaskPane::ModuleTaskPane( vcl::Window
& i_rParentWindow
, const Reference
< XFrame
>& i_rDocumentFrame
)
707 :Window( &i_rParentWindow
, WB_DIALOGCONTROL
)
708 ,m_xImpl( new ModuleTaskPane_Impl( *this, i_rDocumentFrame
) )
712 ModuleTaskPane::~ModuleTaskPane()
717 bool ModuleTaskPane::ModuleHasToolPanels( const Reference
< XFrame
>& i_rDocumentFrame
)
719 return ModuleTaskPane_Impl::ModuleHasToolPanels( lcl_identifyModule( i_rDocumentFrame
) );
723 void ModuleTaskPane::Resize()
730 void ModuleTaskPane::GetFocus()
733 m_xImpl
->OnGetFocus();
737 ::svt::ToolPanelDeck
& ModuleTaskPane::GetPanelDeck()
739 return m_xImpl
->GetPanelDeck();
743 const ::svt::ToolPanelDeck
& ModuleTaskPane::GetPanelDeck() const
745 return m_xImpl
->GetPanelDeck();
749 ::boost::optional
< size_t > ModuleTaskPane::GetPanelPos( const OUString
& i_rResourceURL
)
751 return m_xImpl
->GetPanelPos( i_rResourceURL
);
755 void ModuleTaskPane::SetDrawersLayout()
757 m_xImpl
->SetDrawersLayout();
761 void ModuleTaskPane::SetTabsLayout( const ::svt::TabAlignment i_eTabAlignment
, const ::svt::TabItemContent i_eTabContent
)
763 m_xImpl
->SetTabsLayout( i_eTabAlignment
, i_eTabContent
);
767 // = PanelSelectorLayout
769 enum PanelSelectorLayout
783 PanelSelectorLayout
lcl_getTabLayoutFromAlignment( const SfxChildAlignment i_eAlignment
)
785 switch ( i_eAlignment
)
787 case SfxChildAlignment::LEFT
:
788 return LAYOUT_TABS_LEFT
;
789 case SfxChildAlignment::TOP
:
790 return LAYOUT_TABS_TOP
;
791 case SfxChildAlignment::BOTTOM
:
792 return LAYOUT_TABS_BOTTOM
;
794 return LAYOUT_TABS_RIGHT
;
802 /** is a helper class for TaskPaneController_Impl, holding the details about a single panel which is not
803 contained in the IToolPanel implementation itself.
805 struct PanelDescriptor
807 ::svt::PToolPanel pPanel
;
810 PanelDescriptor( const ::svt::PToolPanel
& i_rPanel
)
818 //= TaskPaneController_Impl
820 class TaskPaneController_Impl
:public ::boost::noncopyable
821 ,public ::svt::IToolPanelDeckListener
824 TaskPaneController_Impl(
825 ModuleTaskPane
& i_rTaskPane
,
826 TitledDockingWindow
& i_rDockingWindow
828 virtual ~TaskPaneController_Impl();
830 void SetDefaultTitle( const OUString
& i_rTitle
);
831 void ActivateToolPanel( const OUString
& i_rPanelURL
);
834 // IToolPanelDeckListener overridables
835 virtual void PanelInserted( const ::svt::PToolPanel
& i_pPanel
, const size_t i_nPosition
) SAL_OVERRIDE
;
836 virtual void PanelRemoved( const size_t i_nPosition
) SAL_OVERRIDE
;
837 virtual void ActivePanelChanged( const ::boost::optional
< size_t >& i_rOldActive
, const ::boost::optional
< size_t >& i_rNewActive
) SAL_OVERRIDE
;
838 virtual void LayouterChanged( const ::svt::PDeckLayouter
& i_rNewLayouter
) SAL_OVERRIDE
;
839 virtual void Dying() SAL_OVERRIDE
;
842 DECL_LINK_TYPED( OnToolboxClicked
, ToolBox
*, void );
843 DECL_LINK( OnMenuItemSelected
, Menu
* );
844 DECL_LINK( DockingChanged
, TitledDockingWindow
* );
845 ::std::unique_ptr
< PopupMenu
> impl_createPopupMenu() const;
847 /// sets the given layout for the panel selector
848 void impl_setLayout( const PanelSelectorLayout i_eLayout
, const bool i_bForce
= false );
850 /// returns the current layout of the panel selector
852 impl_getLayout() const { return m_eCurrentLayout
; }
854 void impl_updateDockingWindowTitle();
855 void impl_togglePanelVisibility( const size_t i_nLogicalPanelIndex
);
856 size_t impl_getLogicalPanelIndex( const size_t i_nVisibleIndex
);
861 MID_UNLOCK_TASK_PANEL
= 1,
862 MID_LOCK_TASK_PANEL
= 2,
864 MID_LAYOUT_DRAWERS
= 4,
869 typedef ::std::vector
< PanelDescriptor
> PanelDescriptors
;
871 ModuleTaskPane
& m_rTaskPane
;
872 TitledDockingWindow
& m_rDockingWindow
;
873 sal_uInt16 m_nViewMenuID
;
874 PanelSelectorLayout m_eCurrentLayout
;
875 PanelDescriptors m_aPanelRepository
;
876 bool m_bTogglingPanelVisibility
;
877 OUString m_sDefaultTitle
;
881 TaskPaneController_Impl::TaskPaneController_Impl( ModuleTaskPane
& i_rTaskPane
, TitledDockingWindow
& i_rDockingWindow
)
882 :m_rTaskPane( i_rTaskPane
)
883 ,m_rDockingWindow( i_rDockingWindow
)
885 ,m_eCurrentLayout( LAYOUT_DRAWERS
)
886 ,m_aPanelRepository()
887 ,m_bTogglingPanelVisibility( false )
890 m_rDockingWindow
.ResetToolBox();
891 m_nViewMenuID
= m_rDockingWindow
.AddDropDownToolBoxItem(
892 SfxResId( STR_SFX_TASK_PANE_VIEW
).toString(),
893 HID_TASKPANE_VIEW_MENU
,
894 LINK( this, TaskPaneController_Impl
, OnToolboxClicked
)
896 m_rDockingWindow
.SetEndDockingHdl( LINK( this, TaskPaneController_Impl
, DockingChanged
) );
897 impl_setLayout(LAYOUT_DRAWERS
, true);
899 m_rTaskPane
.GetPanelDeck().AddListener( *this );
901 // initialize the panel repository
902 for ( size_t i
= 0; i
< m_rTaskPane
.GetPanelDeck().GetPanelCount(); ++i
)
904 ::svt::PToolPanel
pPanel( m_rTaskPane
.GetPanelDeck().GetPanel( i
) );
905 m_aPanelRepository
.push_back( PanelDescriptor( pPanel
) );
908 SetDefaultTitle( SfxResId( STR_SFX_TASKS
).toString() );
912 TaskPaneController_Impl::~TaskPaneController_Impl()
914 m_rTaskPane
.GetPanelDeck().RemoveListener( *this );
917 // remove the panels which are not under the control of the panel deck currently
918 for ( PanelDescriptors::iterator panelPos
= m_aPanelRepository
.begin();
919 panelPos
!= m_aPanelRepository
.end();
923 if ( panelPos
->bHidden
)
924 impl_togglePanelVisibility( i
);
926 m_aPanelRepository
.clear();
930 void TaskPaneController_Impl::SetDefaultTitle( const OUString
& i_rTitle
)
932 m_sDefaultTitle
= i_rTitle
;
933 impl_updateDockingWindowTitle();
937 void TaskPaneController_Impl::ActivateToolPanel( const OUString
& i_rPanelURL
)
939 ::boost::optional
< size_t > aPanelPos( m_rTaskPane
.GetPanelPos( i_rPanelURL
) );
940 ENSURE_OR_RETURN_VOID( !!aPanelPos
, "TaskPaneController_Impl::ActivateToolPanel: no such panel!" );
942 if ( aPanelPos
== m_rTaskPane
.GetPanelDeck().GetActivePanel() )
944 ::svt::PToolPanel
pPanel( m_rTaskPane
.GetPanelDeck().GetPanel( *aPanelPos
) );
949 m_rTaskPane
.GetPanelDeck().ActivatePanel( aPanelPos
);
954 IMPL_LINK( TaskPaneController_Impl
, DockingChanged
, TitledDockingWindow
*, i_pDockingWindow
)
956 ENSURE_OR_RETURN( i_pDockingWindow
, "TaskPaneController_Impl::DockingChanged: where does this come from?", 0L );
958 if ( impl_getLayout() == LAYOUT_DRAWERS
)
961 impl_setLayout( lcl_getTabLayoutFromAlignment( i_pDockingWindow
->GetAlignment() ) );
966 IMPL_LINK_TYPED( TaskPaneController_Impl
, OnToolboxClicked
, ToolBox
*, i_pToolBox
, void )
968 if ( i_pToolBox
->GetCurItemId() == m_nViewMenuID
)
970 i_pToolBox
->EndSelection();
972 ::std::unique_ptr
< PopupMenu
> pMenu
= impl_createPopupMenu();
973 pMenu
->SetSelectHdl( LINK( this, TaskPaneController_Impl
, OnMenuItemSelected
) );
975 // pass toolbox button rect so the menu can stay open on button up
976 Rectangle
aMenuRect( i_pToolBox
->GetItemRect( m_nViewMenuID
) );
977 aMenuRect
.SetPos( i_pToolBox
->GetPosPixel() );
978 pMenu
->Execute( &m_rDockingWindow
, aMenuRect
, PopupMenuFlags::ExecuteDown
);
983 IMPL_LINK( TaskPaneController_Impl
, OnMenuItemSelected
, Menu
*, i_pMenu
)
985 ENSURE_OR_RETURN( i_pMenu
, "TaskPaneController_Impl::OnMenuItemSelected: illegal menu!", 0L );
987 i_pMenu
->Deactivate();
988 switch ( i_pMenu
->GetCurItemId() )
990 case MID_UNLOCK_TASK_PANEL
:
991 m_rDockingWindow
.SetFloatingMode( true );
994 case MID_LOCK_TASK_PANEL
:
995 m_rDockingWindow
.SetFloatingMode( false );
998 case MID_LAYOUT_DRAWERS
:
999 impl_setLayout( LAYOUT_DRAWERS
);
1002 case MID_LAYOUT_TABS
:
1003 impl_setLayout( lcl_getTabLayoutFromAlignment( m_rDockingWindow
.GetAlignment() ) );
1008 size_t nPanelIndex
= size_t( i_pMenu
->GetCurItemId() - MID_FIRST_PANEL
);
1009 impl_togglePanelVisibility( nPanelIndex
);
1018 size_t TaskPaneController_Impl::impl_getLogicalPanelIndex( const size_t i_nVisibleIndex
)
1020 size_t nLogicalIndex
= 0;
1021 size_t nVisibleIndex( i_nVisibleIndex
);
1022 for ( size_t i
=0; i
< m_aPanelRepository
.size(); ++i
)
1024 if ( !m_aPanelRepository
[i
].bHidden
)
1026 if ( !nVisibleIndex
)
1032 return nLogicalIndex
;
1036 void TaskPaneController_Impl::PanelInserted( const ::svt::PToolPanel
& i_pPanel
, const size_t i_nPosition
)
1038 if ( m_bTogglingPanelVisibility
)
1041 const size_t nLogicalIndex( impl_getLogicalPanelIndex( i_nPosition
) );
1042 m_aPanelRepository
.insert( m_aPanelRepository
.begin() + nLogicalIndex
, PanelDescriptor( i_pPanel
) );
1046 void TaskPaneController_Impl::PanelRemoved( const size_t i_nPosition
)
1048 if ( m_bTogglingPanelVisibility
)
1051 const size_t nLogicalIndex( impl_getLogicalPanelIndex( i_nPosition
) );
1052 m_aPanelRepository
.erase( m_aPanelRepository
.begin() + nLogicalIndex
);
1056 void TaskPaneController_Impl::ActivePanelChanged( const ::boost::optional
< size_t >& i_rOldActive
, const ::boost::optional
< size_t >& i_rNewActive
)
1058 if ( impl_getLayout() == LAYOUT_DRAWERS
)
1059 // no adjustment of the title when we use the classical "drawers" layout
1062 impl_updateDockingWindowTitle( );
1068 void TaskPaneController_Impl::LayouterChanged( const ::svt::PDeckLayouter
& i_rNewLayouter
)
1070 // not interested in
1071 (void)i_rNewLayouter
;
1075 void TaskPaneController_Impl::Dying()
1077 OSL_FAIL( "TaskPaneController_Impl::Dying: unexpected call!" );
1078 // We are expected to live longer than the ToolPanelDeck we work with. Since we remove ourself, in our dtor,
1079 // as listener from the panel deck, this method here should never be called.
1083 void TaskPaneController_Impl::impl_togglePanelVisibility( const size_t i_nLogicalPanelIndex
)
1085 ENSURE_OR_RETURN_VOID( i_nLogicalPanelIndex
< m_aPanelRepository
.size(), "illegal index" );
1087 // get the actual panel index, within the deck
1088 size_t nActualPanelIndex(0);
1089 for ( size_t i
=0; i
< i_nLogicalPanelIndex
; ++i
)
1091 if ( !m_aPanelRepository
[i
].bHidden
)
1092 ++nActualPanelIndex
;
1095 ::boost::optional
< size_t > aActivatePanel
;
1097 m_bTogglingPanelVisibility
= true;
1098 if ( m_aPanelRepository
[ i_nLogicalPanelIndex
].bHidden
)
1100 OSL_VERIFY( m_rTaskPane
.GetPanelDeck().InsertPanel( m_aPanelRepository
[ i_nLogicalPanelIndex
].pPanel
, nActualPanelIndex
) == nActualPanelIndex
);
1101 // if there has not been an active panel before, activate the newly inserted one
1102 ::boost::optional
< size_t > aActivePanel( m_rTaskPane
.GetPanelDeck().GetActivePanel() );
1103 if ( !aActivePanel
)
1104 aActivatePanel
= nActualPanelIndex
;
1108 OSL_VERIFY( m_rTaskPane
.GetPanelDeck().RemovePanel( nActualPanelIndex
).get() == m_aPanelRepository
[ i_nLogicalPanelIndex
].pPanel
.get() );
1110 m_bTogglingPanelVisibility
= false;
1111 m_aPanelRepository
[ i_nLogicalPanelIndex
].bHidden
= !m_aPanelRepository
[ i_nLogicalPanelIndex
].bHidden
;
1113 if ( !!aActivatePanel
)
1114 m_rTaskPane
.GetPanelDeck().ActivatePanel( *aActivatePanel
);
1118 void TaskPaneController_Impl::impl_setLayout( const PanelSelectorLayout i_eLayout
, const bool i_bForce
)
1120 if ( !i_bForce
&& ( m_eCurrentLayout
== i_eLayout
) )
1123 switch ( i_eLayout
)
1125 case LAYOUT_DRAWERS
:
1126 m_rTaskPane
.SetDrawersLayout();
1128 case LAYOUT_TABS_TOP
:
1129 m_rTaskPane
.SetTabsLayout( ::svt::TABS_TOP
, ::svt::TABITEM_IMAGE_ONLY
);
1131 case LAYOUT_TABS_BOTTOM
:
1132 m_rTaskPane
.SetTabsLayout( ::svt::TABS_BOTTOM
, ::svt::TABITEM_IMAGE_ONLY
);
1134 case LAYOUT_TABS_LEFT
:
1135 m_rTaskPane
.SetTabsLayout( ::svt::TABS_LEFT
, ::svt::TABITEM_IMAGE_ONLY
);
1137 case LAYOUT_TABS_RIGHT
:
1138 m_rTaskPane
.SetTabsLayout( ::svt::TABS_RIGHT
, ::svt::TABITEM_IMAGE_ONLY
);
1141 m_eCurrentLayout
= i_eLayout
;
1143 impl_updateDockingWindowTitle();
1147 void TaskPaneController_Impl::impl_updateDockingWindowTitle()
1149 ::boost::optional
< size_t > aActivePanel( m_rTaskPane
.GetPanelDeck().GetActivePanel() );
1150 if ( !aActivePanel
|| ( impl_getLayout() == LAYOUT_DRAWERS
) )
1151 m_rDockingWindow
.SetTitle( m_sDefaultTitle
);
1154 size_t nNewActive( *aActivePanel
);
1155 for ( size_t i
=0; i
< m_aPanelRepository
.size(); ++i
)
1157 if ( m_aPanelRepository
[i
].bHidden
)
1162 m_rDockingWindow
.SetTitle( m_aPanelRepository
[i
].pPanel
->GetDisplayName() );
1171 ::std::unique_ptr
< PopupMenu
> TaskPaneController_Impl::impl_createPopupMenu() const
1173 ::std::unique_ptr
<PopupMenu
> pMenu( new PopupMenu
);
1174 FloatingWindow
* pMenuWindow
= static_cast< FloatingWindow
* >( pMenu
->GetWindow() );
1175 if ( pMenuWindow
!= NULL
)
1177 pMenuWindow
->SetPopupModeFlags ( pMenuWindow
->GetPopupModeFlags() | FloatWinPopupFlags::NoMouseUpClose
);
1180 // Add one entry for every tool panel element to individually make
1181 // them visible or hide them.
1182 sal_uInt16 nIndex
= MID_FIRST_PANEL
;
1183 for ( size_t i
=0; i
<m_aPanelRepository
.size(); ++i
, ++nIndex
)
1185 const PanelDescriptor
& rPanelDesc( m_aPanelRepository
[i
] );
1186 pMenu
->InsertItem( nIndex
, rPanelDesc
.pPanel
->GetDisplayName(), MenuItemBits::CHECKABLE
);
1187 pMenu
->CheckItem( nIndex
, !rPanelDesc
.bHidden
);
1189 pMenu
->InsertSeparator();
1191 #if OSL_DEBUG_LEVEL > 0
1192 if (SvtMiscOptions().IsExperimentalMode())
1194 pMenu
->InsertItem( MID_LAYOUT_TABS
, OUString("Tab-Layout (exp.)"), MenuItemBits::CHECKABLE
);
1195 pMenu
->CheckItem( MID_LAYOUT_TABS
, impl_getLayout() != LAYOUT_DRAWERS
);
1196 pMenu
->InsertItem( MID_LAYOUT_DRAWERS
, OUString("Drawer-Layout"), MenuItemBits::CHECKABLE
);
1197 pMenu
->CheckItem( MID_LAYOUT_DRAWERS
, impl_getLayout() == LAYOUT_DRAWERS
);
1199 pMenu
->InsertSeparator();
1203 // Add entry for docking or un-docking the tool panel.
1204 if ( m_rDockingWindow
.IsFloatingMode() )
1206 MID_LOCK_TASK_PANEL
,
1207 SfxResId( STR_SFX_DOCK
).toString()
1211 MID_UNLOCK_TASK_PANEL
,
1212 SfxResId( STR_SFX_UNDOCK
).toString()
1215 pMenu
->RemoveDisabledEntries( false, false );
1220 //= TaskPaneController
1223 TaskPaneController::TaskPaneController( ModuleTaskPane
& i_rTaskPane
, TitledDockingWindow
& i_rDockingWindow
)
1224 :m_xImpl( new TaskPaneController_Impl( i_rTaskPane
, i_rDockingWindow
) )
1229 TaskPaneController::~TaskPaneController()
1234 void TaskPaneController::ActivateToolPanel( const OUString
& i_rPanelURL
)
1236 m_xImpl
->ActivateToolPanel( i_rPanelURL
);
1243 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */