bump product version to 5.0.4.1
[LibreOffice.git] / sfx2 / source / dialog / taskpane.cxx
blob5c963d9470244dd6a126d72c3ba0dd05072a6732
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
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"
28 #include "helpid.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>
58 namespace sfx2
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;
93 //= helpers
95 namespace
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();
139 return sModuleName;
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() );
148 return xFrame;
152 OUString lcl_getPanelHelpURL( const ::utl::OConfigurationNode& i_rPanelConfigNode )
154 const OUString sHelpURL( ::comphelper::getString( i_rPanelConfigNode.getNodeValue( "HelpURL" ) ) );
155 return sHelpURL;
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 ) );
180 return aPanelImage;
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();
195 return Image();
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 )
208 m_aTaskPane->Show();
209 SetText( SfxResId( SID_TASKPANE ).toString() );
212 TaskPaneDockingWindow::~TaskPaneDockingWindow()
214 disposeOnce();
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() );
243 //= TaskPaneWrapper
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 );
262 pWindow->Show();
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
278 public:
279 CustomPanelUIElement()
280 :m_xUIElement()
281 ,m_xToolPanel()
282 ,m_xPanelWindow()
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; }
299 private:
300 Reference< XUIElement > m_xUIElement;
301 Reference< XToolPanel > m_xToolPanel;
302 Reference< XWindow > m_xPanelWindow;
306 //= CustomToolPanel
308 class CustomToolPanel : public ::svt::ToolPanelBase
310 public:
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;
324 const OUString&
325 GetResourceURL() const { return m_sResourceURL; }
327 protected:
328 virtual ~CustomToolPanel();
330 private:
331 bool impl_ensureToolPanelWindow( vcl::Window& i_rPanelParentWindow );
332 void impl_updatePanelConfig( const bool i_bVisible ) const;
334 private:
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 )
353 ,m_aCustomPanel()
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() ),
380 UNO_SET_THROW );
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 ) );
397 aConfig.commit();
401 OUString CustomToolPanel::GetDisplayName() const
403 return m_sUIName;
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 );
417 else
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(),
459 PosSize::POSSIZE );
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
480 return;
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
516 public:
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();
524 OnResize();
525 impl_initFromConfiguration();
528 ~ModuleTaskPane_Impl()
532 void OnResize();
533 void OnGetFocus();
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 );
545 private:
546 void impl_initFromConfiguration();
548 static bool
549 impl_isToolPanelResource( const OUString& i_rResourceURL );
551 DECL_LINK( OnActivatePanel, void* );
553 private:
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 ) );
576 return 1L;
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() )
590 return;
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();
598 ++resource
601 if ( !impl_isToolPanelResource( *resource ) )
602 continue;
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?!" );
623 if ( !!aPanelPos )
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() )
633 return false;
635 const Sequence< OUString > aUIElements( aWindowStateConfig.getNodeNames() );
636 for ( const OUString* resource = aUIElements.getConstArray();
637 resource != aUIElements.getConstArray() + aUIElements.getLength();
638 ++resource
641 if ( impl_isToolPanelResource( *resource ) )
642 return true;
644 return false;
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() );
655 if ( !pCustomPanel )
657 SAL_WARN( "sfx.dialog", "ModuleTaskPane_Impl::GetPanelPos: illegal panel implementation!" );
658 continue;
661 if ( pCustomPanel->GetResourceURL() == i_rResourceURL )
663 aPanelPos = i;
664 break;
667 return aPanelPos;
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
676 return;
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
690 return;
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 );
696 return;
699 m_aPanelDeck->SetLayouter( new ::svt::TabDeckLayouter( *m_aPanelDeck.get(), *m_aPanelDeck.get(), i_eTabAlignment, i_eTabContent ) );
703 //= ModuleTaskPane
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()
714 disposeOnce();
717 bool ModuleTaskPane::ModuleHasToolPanels( const Reference< XFrame >& i_rDocumentFrame )
719 return ModuleTaskPane_Impl::ModuleHasToolPanels( lcl_identifyModule( i_rDocumentFrame ) );
723 void ModuleTaskPane::Resize()
725 Window::Resize();
726 m_xImpl->OnResize();
730 void ModuleTaskPane::GetFocus()
732 Window::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
771 LAYOUT_DRAWERS,
772 LAYOUT_TABS_RIGHT,
773 LAYOUT_TABS_LEFT,
774 LAYOUT_TABS_TOP,
775 LAYOUT_TABS_BOTTOM
779 //= helper
781 namespace
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;
793 default:
794 return LAYOUT_TABS_RIGHT;
800 // = PanelDescriptor
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;
808 bool bHidden;
810 PanelDescriptor( const ::svt::PToolPanel& i_rPanel )
811 :pPanel( i_rPanel )
812 ,bHidden( false )
818 //= TaskPaneController_Impl
820 class TaskPaneController_Impl :public ::boost::noncopyable
821 ,public ::svt::IToolPanelDeckListener
823 public:
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 );
833 protected:
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;
841 private:
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
851 PanelSelectorLayout
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 );
858 private:
859 enum MenuId
861 MID_UNLOCK_TASK_PANEL = 1,
862 MID_LOCK_TASK_PANEL = 2,
863 MID_LAYOUT_TABS = 3,
864 MID_LAYOUT_DRAWERS = 4,
865 MID_FIRST_PANEL = 5
868 private:
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 )
884 ,m_nViewMenuID( 0 )
885 ,m_eCurrentLayout( LAYOUT_DRAWERS )
886 ,m_aPanelRepository()
887 ,m_bTogglingPanelVisibility( false )
888 ,m_sDefaultTitle()
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 );
915 int i = 0;
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();
920 ++panelPos, ++i
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 ) );
945 pPanel->GrabFocus();
947 else
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 )
959 return 0L;
961 impl_setLayout( lcl_getTabLayoutFromAlignment( i_pDockingWindow->GetAlignment() ) );
962 return 1L;
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 );
992 break;
994 case MID_LOCK_TASK_PANEL:
995 m_rDockingWindow.SetFloatingMode( false );
996 break;
998 case MID_LAYOUT_DRAWERS:
999 impl_setLayout( LAYOUT_DRAWERS );
1000 break;
1002 case MID_LAYOUT_TABS:
1003 impl_setLayout( lcl_getTabLayoutFromAlignment( m_rDockingWindow.GetAlignment() ) );
1004 break;
1006 default:
1008 size_t nPanelIndex = size_t( i_pMenu->GetCurItemId() - MID_FIRST_PANEL );
1009 impl_togglePanelVisibility( nPanelIndex );
1011 break;
1014 return 1L;
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 )
1027 break;
1028 --nVisibleIndex;
1030 ++nLogicalIndex;
1032 return nLogicalIndex;
1036 void TaskPaneController_Impl::PanelInserted( const ::svt::PToolPanel& i_pPanel, const size_t i_nPosition )
1038 if ( m_bTogglingPanelVisibility )
1039 return;
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 )
1049 return;
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
1060 return;
1062 impl_updateDockingWindowTitle( );
1063 (void)i_rOldActive;
1064 (void)i_rNewActive;
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;
1106 else
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 ) )
1121 return;
1123 switch ( i_eLayout )
1125 case LAYOUT_DRAWERS:
1126 m_rTaskPane.SetDrawersLayout();
1127 break;
1128 case LAYOUT_TABS_TOP:
1129 m_rTaskPane.SetTabsLayout( ::svt::TABS_TOP, ::svt::TABITEM_IMAGE_ONLY );
1130 break;
1131 case LAYOUT_TABS_BOTTOM:
1132 m_rTaskPane.SetTabsLayout( ::svt::TABS_BOTTOM, ::svt::TABITEM_IMAGE_ONLY );
1133 break;
1134 case LAYOUT_TABS_LEFT:
1135 m_rTaskPane.SetTabsLayout( ::svt::TABS_LEFT, ::svt::TABITEM_IMAGE_ONLY );
1136 break;
1137 case LAYOUT_TABS_RIGHT:
1138 m_rTaskPane.SetTabsLayout( ::svt::TABS_RIGHT, ::svt::TABITEM_IMAGE_ONLY );
1139 break;
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 );
1152 else
1154 size_t nNewActive( *aActivePanel );
1155 for ( size_t i=0; i < m_aPanelRepository.size(); ++i )
1157 if ( m_aPanelRepository[i].bHidden )
1158 continue;
1160 if ( !nNewActive )
1162 m_rDockingWindow.SetTitle( m_aPanelRepository[i].pPanel->GetDisplayName() );
1163 break;
1165 --nNewActive;
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();
1201 #endif
1203 // Add entry for docking or un-docking the tool panel.
1204 if ( m_rDockingWindow.IsFloatingMode() )
1205 pMenu->InsertItem(
1206 MID_LOCK_TASK_PANEL,
1207 SfxResId( STR_SFX_DOCK ).toString()
1209 else
1210 pMenu->InsertItem(
1211 MID_UNLOCK_TASK_PANEL,
1212 SfxResId( STR_SFX_UNDOCK ).toString()
1215 pMenu->RemoveDisabledEntries( false, false );
1217 return pMenu;
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 );
1240 } // namespace sfx2
1243 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */