Bump version to 5.0-14
[LibreOffice.git] / svtools / source / toolpanel / toolpaneldeck.cxx
blob8544ab104b0c30c31a7346e17ca3fe43c272c44e
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 "dummypanel.hxx"
22 #include "toolpanelcollection.hxx"
23 #include "paneldecklisteners.hxx"
24 #include "toolpaneldeckpeer.hxx"
25 #include <svtools/toolpanel/toolpaneldeck.hxx>
26 #include <svtools/toolpanel/tablayouter.hxx>
27 #include <svtools/toolpanel/drawerlayouter.hxx>
29 #include <com/sun/star/accessibility/XAccessible.hpp>
30 #include <com/sun/star/accessibility/AccessibleRole.hpp>
32 #include <tools/diagnose_ex.h>
33 #include <vcl/vclptr.hxx>
35 #include <boost/optional.hpp>
38 namespace svt
42 using ::com::sun::star::uno::Reference;
43 using ::com::sun::star::accessibility::XAccessible;
44 using ::com::sun::star::awt::XWindowPeer;
45 using ::com::sun::star::uno::UNO_SET_THROW;
47 namespace AccessibleRole = ::com::sun::star::accessibility::AccessibleRole;
49 enum DeckAction
51 /// activates the first panel
52 ACTION_ACTIVATE_FIRST,
53 // activates the panel after the currently active panel
54 ACTION_ACTIVATE_NEXT,
55 // activates the panel before the currently active panel
56 ACTION_ACTIVATE_PREV,
57 // activates the last panel
58 ACTION_ACTIVATE_LAST,
60 // toggles the focus between the active panel and the panel selector
61 ACTION_TOGGLE_FOCUS,
65 //= ToolPanelDeck_Impl
67 class ToolPanelDeck_Impl : public IToolPanelDeckListener
69 public:
70 ToolPanelDeck_Impl( ToolPanelDeck& i_rDeck )
71 :m_rDeck( i_rDeck )
72 ,m_aPanelAnchor( VclPtr<vcl::Window>::Create(&i_rDeck, WB_DIALOGCONTROL | WB_CHILDDLGCTRL) )
73 ,m_aPanels()
74 ,m_pDummyPanel( new DummyPanel )
75 ,m_pLayouter()
76 ,m_bInDtor( false )
78 m_aPanels.AddListener( *this );
79 m_aPanelAnchor->Show();
80 m_aPanelAnchor->SetAccessibleRole( AccessibleRole::PANEL );
83 virtual ~ToolPanelDeck_Impl()
85 m_bInDtor = true;
88 PDeckLayouter GetLayouter() const { return m_pLayouter; }
89 void SetLayouter( const PDeckLayouter& i_pNewLayouter );
91 vcl::Window& GetPanelWindowAnchor() { return *m_aPanelAnchor.get(); }
93 bool IsDead() const { return m_bInDtor; }
95 /// notifies our listeners that we're going to die. Only to be called from with our anti-impl's destructor
96 void NotifyDying()
98 m_aPanels.RemoveListener( *this );
99 m_aListeners.Dying();
102 // IToolPanelDeck equivalents
103 size_t GetPanelCount() const;
104 PToolPanel GetPanel( const size_t i_nPos ) const;
105 ::boost::optional< size_t >
106 GetActivePanel() const;
107 void ActivatePanel( const ::boost::optional< size_t >& i_rPanel );
108 size_t InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition );
109 PToolPanel RemovePanel( const size_t i_nPosition );
110 void AddListener( IToolPanelDeckListener& i_rListener );
111 void RemoveListener( IToolPanelDeckListener& i_rListener );
113 /// re-layouts everything
114 void LayoutAll() { ImplDoLayout(); }
116 void DoAction( const DeckAction i_eAction );
118 bool FocusActivePanel();
120 protected:
121 // IToolPanelDeckListener
122 virtual void PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition ) SAL_OVERRIDE;
123 virtual void PanelRemoved( const size_t i_nPosition ) SAL_OVERRIDE;
124 virtual void ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ) SAL_OVERRIDE;
125 virtual void LayouterChanged( const PDeckLayouter& i_rNewLayouter ) SAL_OVERRIDE;
126 virtual void Dying() SAL_OVERRIDE;
128 private:
129 void ImplDoLayout();
130 PToolPanel GetActiveOrDummyPanel_Impl();
132 private:
133 ToolPanelDeck& m_rDeck;
134 VclPtr<vcl::Window> m_aPanelAnchor;
135 ToolPanelCollection m_aPanels;
136 PToolPanel m_pDummyPanel;
137 PanelDeckListeners m_aListeners;
138 PDeckLayouter m_pLayouter;
139 bool m_bInDtor;
143 PToolPanel ToolPanelDeck_Impl::GetActiveOrDummyPanel_Impl()
145 ::boost::optional< size_t > aActivePanel( m_aPanels.GetActivePanel() );
146 if ( !aActivePanel )
147 return m_pDummyPanel;
148 return m_aPanels.GetPanel( *aActivePanel );
152 void ToolPanelDeck_Impl::SetLayouter( const PDeckLayouter& i_pNewLayouter )
154 ENSURE_OR_RETURN_VOID( i_pNewLayouter.get(), "invalid layouter" );
156 if ( m_pLayouter.get() )
157 m_pLayouter->Destroy();
159 m_pLayouter = i_pNewLayouter;
161 ImplDoLayout();
163 m_aListeners.LayouterChanged( m_pLayouter );
167 size_t ToolPanelDeck_Impl::GetPanelCount() const
169 return m_aPanels.GetPanelCount();
173 PToolPanel ToolPanelDeck_Impl::GetPanel( const size_t i_nPos ) const
175 return m_aPanels.GetPanel( i_nPos );
179 ::boost::optional< size_t > ToolPanelDeck_Impl::GetActivePanel() const
181 return m_aPanels.GetActivePanel();
185 void ToolPanelDeck_Impl::ActivatePanel( const ::boost::optional< size_t >& i_rPanel )
187 m_aPanels.ActivatePanel( i_rPanel );
191 size_t ToolPanelDeck_Impl::InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition )
193 return m_aPanels.InsertPanel( i_pPanel, i_nPosition );
197 PToolPanel ToolPanelDeck_Impl::RemovePanel( const size_t i_nPosition )
199 return m_aPanels.RemovePanel( i_nPosition );
203 void ToolPanelDeck_Impl::ImplDoLayout()
205 const Rectangle aDeckPlayground( Point(), m_rDeck.GetOutputSizePixel() );
207 // ask the layouter what is left for our panel, and position the panel container window appropriately
208 Rectangle aPlaygroundArea( aDeckPlayground );
209 OSL_ENSURE( m_pLayouter.get(), "ToolPanelDeck_Impl::ImplDoLayout: no layouter!" );
210 if ( m_pLayouter.get() )
212 aPlaygroundArea = m_pLayouter->Layout( aDeckPlayground );
214 m_aPanelAnchor->SetPosSizePixel( aPlaygroundArea.TopLeft(), aPlaygroundArea.GetSize() );
216 // position the active panel
217 const PToolPanel pActive( GetActiveOrDummyPanel_Impl() );
218 pActive->SetSizePixel( m_aPanelAnchor->GetOutputSizePixel() );
222 void ToolPanelDeck_Impl::AddListener( IToolPanelDeckListener& i_rListener )
224 m_aListeners.AddListener( i_rListener );
228 void ToolPanelDeck_Impl::RemoveListener( IToolPanelDeckListener& i_rListener )
230 m_aListeners.RemoveListener( i_rListener );
234 void ToolPanelDeck_Impl::DoAction( const DeckAction i_eAction )
236 const size_t nPanelCount( m_aPanels.GetPanelCount() );
237 ::boost::optional< size_t > aActivatePanel;
238 ::boost::optional< size_t > aCurrentPanel( GetActivePanel() );
240 switch ( i_eAction )
242 case ACTION_ACTIVATE_FIRST:
243 if ( nPanelCount > 0 )
244 aActivatePanel = 0;
245 break;
246 case ACTION_ACTIVATE_PREV:
247 if ( !aCurrentPanel && ( nPanelCount > 0 ) )
248 aActivatePanel = nPanelCount - 1;
249 else if ( !!aCurrentPanel && ( *aCurrentPanel > 0 ) )
250 aActivatePanel = *aCurrentPanel - 1;
251 break;
252 case ACTION_ACTIVATE_NEXT:
253 if ( !aCurrentPanel && ( nPanelCount > 0 ) )
254 aActivatePanel = 0;
255 else if ( !!aCurrentPanel && ( *aCurrentPanel < nPanelCount - 1 ) )
256 aActivatePanel = *aCurrentPanel + 1;
257 break;
258 case ACTION_ACTIVATE_LAST:
259 if ( nPanelCount > 0 )
260 aActivatePanel = nPanelCount - 1;
261 break;
262 case ACTION_TOGGLE_FOCUS:
264 PToolPanel pActivePanel( GetActiveOrDummyPanel_Impl() );
265 if ( !m_aPanelAnchor->HasChildPathFocus() )
266 pActivePanel->GrabFocus();
267 else
268 GetLayouter()->SetFocusToPanelSelector();
270 break;
273 if ( !!aActivatePanel )
275 ActivatePanel( aActivatePanel );
280 bool ToolPanelDeck_Impl::FocusActivePanel()
282 ::boost::optional< size_t > aActivePanel( m_aPanels.GetActivePanel() );
283 if ( !aActivePanel )
284 return false;
286 PToolPanel pActivePanel( m_aPanels.GetPanel( *aActivePanel ) );
287 pActivePanel->GrabFocus();
288 return true;
292 void ToolPanelDeck_Impl::PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition )
294 // multiplex to our own listeners
295 m_aListeners.PanelInserted( i_pPanel, i_nPosition );
299 void ToolPanelDeck_Impl::PanelRemoved( const size_t i_nPosition )
301 // multiplex to our own listeners
302 m_aListeners.PanelRemoved( i_nPosition );
306 void ToolPanelDeck_Impl::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive )
308 // hide the old panel
309 if ( !!i_rOldActive )
311 const PToolPanel pOldActive( m_aPanels.GetPanel( *i_rOldActive ) );
312 pOldActive->Deactivate();
315 // position and show the new panel
316 const PToolPanel pNewActive( !i_rNewActive ? m_pDummyPanel : m_aPanels.GetPanel( *i_rNewActive ) );
317 pNewActive->Activate( *m_aPanelAnchor.get() );
318 pNewActive->GrabFocus();
320 // resize the panel (cannot guarantee it has ever been resized before
321 pNewActive->SetSizePixel( m_aPanelAnchor->GetOutputSizePixel() );
323 // multiplex to our own listeners
324 m_aListeners.ActivePanelChanged( i_rOldActive, i_rNewActive );
328 void ToolPanelDeck_Impl::LayouterChanged( const PDeckLayouter& i_rNewLayouter )
330 // not interested in
331 (void)i_rNewLayouter;
335 void ToolPanelDeck_Impl::Dying()
337 // not interested in. Since the ToolPanelCollection is our member, this just means we ourself
338 // are dying, and we already sent this notification in our dtor.
342 //= ToolPanelDeck
345 ToolPanelDeck::ToolPanelDeck( vcl::Window& i_rParent, const WinBits i_nStyle )
346 :Control( &i_rParent, i_nStyle )
347 ,m_pImpl( new ToolPanelDeck_Impl( *this ) )
349 // use a default layouter
350 // SetLayouter( PDeckLayouter( new TabDeckLayouter( *this, *this, TABS_RIGHT, TABITEM_IMAGE_AND_TEXT ) ) );
351 SetLayouter( PDeckLayouter( new DrawerDeckLayouter( *this, *this ) ) );
355 ToolPanelDeck::~ToolPanelDeck()
357 disposeOnce();
360 void ToolPanelDeck::dispose()
362 m_pImpl->NotifyDying();
363 GetLayouter()->Destroy();
365 Hide();
366 for ( size_t i=0; i<GetPanelCount(); ++i )
368 PToolPanel pPanel( GetPanel( i ) );
369 pPanel->Dispose();
371 Control::dispose();
375 size_t ToolPanelDeck::GetPanelCount() const
377 return m_pImpl->GetPanelCount();
381 PToolPanel ToolPanelDeck::GetPanel( const size_t i_nPos ) const
383 return m_pImpl->GetPanel( i_nPos );
387 ::boost::optional< size_t > ToolPanelDeck::GetActivePanel() const
389 return m_pImpl->GetActivePanel();
393 void ToolPanelDeck::ActivatePanel( const ::boost::optional< size_t >& i_rPanel )
395 m_pImpl->ActivatePanel( i_rPanel );
399 size_t ToolPanelDeck::InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition )
401 return m_pImpl->InsertPanel( i_pPanel, i_nPosition );
405 PToolPanel ToolPanelDeck::RemovePanel( const size_t i_nPosition )
407 return m_pImpl->RemovePanel( i_nPosition );
411 PDeckLayouter ToolPanelDeck::GetLayouter() const
413 return m_pImpl->GetLayouter();
417 void ToolPanelDeck::SetLayouter( const PDeckLayouter& i_pNewLayouter )
419 return m_pImpl->SetLayouter( i_pNewLayouter );
423 void ToolPanelDeck::AddListener( IToolPanelDeckListener& i_rListener )
425 m_pImpl->AddListener( i_rListener );
429 void ToolPanelDeck::RemoveListener( IToolPanelDeckListener& i_rListener )
431 m_pImpl->RemoveListener( i_rListener );
435 vcl::Window& ToolPanelDeck::GetPanelWindowAnchor()
437 return m_pImpl->GetPanelWindowAnchor();
441 const vcl::Window& ToolPanelDeck::GetPanelWindowAnchor() const
443 return m_pImpl->GetPanelWindowAnchor();
447 void ToolPanelDeck::Resize()
449 Control::Resize();
450 m_pImpl->LayoutAll();
454 bool ToolPanelDeck::Notify( NotifyEvent& i_rNotifyEvent )
456 bool bHandled = false;
457 if ( i_rNotifyEvent.GetType() == MouseNotifyEvent::KEYINPUT )
459 const KeyEvent* pEvent = i_rNotifyEvent.GetKeyEvent();
460 const vcl::KeyCode& rKeyCode = pEvent->GetKeyCode();
461 if ( rKeyCode.GetModifier() == KEY_MOD1 )
463 bHandled = true;
464 switch ( rKeyCode.GetCode() )
466 case KEY_HOME:
467 m_pImpl->DoAction( ACTION_ACTIVATE_FIRST );
468 break;
469 case KEY_PAGEUP:
470 m_pImpl->DoAction( ACTION_ACTIVATE_PREV );
471 break;
472 case KEY_PAGEDOWN:
473 m_pImpl->DoAction( ACTION_ACTIVATE_NEXT );
474 break;
475 case KEY_END:
476 m_pImpl->DoAction( ACTION_ACTIVATE_LAST );
477 break;
478 default:
479 bHandled = false;
480 break;
483 else if ( rKeyCode.GetModifier() == ( KEY_MOD1 | KEY_SHIFT ) )
485 if ( rKeyCode.GetCode() == KEY_E )
487 m_pImpl->DoAction( ACTION_TOGGLE_FOCUS );
488 bHandled = true;
493 if ( bHandled )
494 return true;
496 return Control::Notify( i_rNotifyEvent );
500 void ToolPanelDeck::GetFocus()
502 Control::GetFocus();
503 if ( m_pImpl->IsDead() )
504 return;
505 if ( !m_pImpl->FocusActivePanel() )
507 PDeckLayouter pLayouter( GetLayouter() );
508 ENSURE_OR_RETURN_VOID( pLayouter.get(), "ToolPanelDeck::GetFocus: no layouter?!" );
509 pLayouter->SetFocusToPanelSelector();
514 Reference< XWindowPeer > ToolPanelDeck::GetComponentInterface( bool i_bCreate )
516 Reference< XWindowPeer > xWindowPeer( Control::GetComponentInterface( false ) );
517 if ( !xWindowPeer.is() && i_bCreate )
519 xWindowPeer.set( new ToolPanelDeckPeer( *this ) );
520 SetComponentInterface( xWindowPeer );
522 return xWindowPeer;
526 } // namespace svt
529 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */