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 "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>
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
;
51 /// activates the first panel
52 ACTION_ACTIVATE_FIRST
,
53 // activates the panel after the currently active panel
55 // activates the panel before the currently active panel
57 // activates the last panel
60 // toggles the focus between the active panel and the panel selector
65 //= ToolPanelDeck_Impl
67 class ToolPanelDeck_Impl
: public IToolPanelDeckListener
70 ToolPanelDeck_Impl( ToolPanelDeck
& i_rDeck
)
72 ,m_aPanelAnchor( VclPtr
<vcl::Window
>::Create(&i_rDeck
, WB_DIALOGCONTROL
| WB_CHILDDLGCTRL
) )
74 ,m_pDummyPanel( new DummyPanel
)
78 m_aPanels
.AddListener( *this );
79 m_aPanelAnchor
->Show();
80 m_aPanelAnchor
->SetAccessibleRole( AccessibleRole::PANEL
);
83 virtual ~ToolPanelDeck_Impl()
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
98 m_aPanels
.RemoveListener( *this );
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();
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
;
130 PToolPanel
GetActiveOrDummyPanel_Impl();
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
;
143 PToolPanel
ToolPanelDeck_Impl::GetActiveOrDummyPanel_Impl()
145 ::boost::optional
< size_t > aActivePanel( m_aPanels
.GetActivePanel() );
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
;
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() );
242 case ACTION_ACTIVATE_FIRST
:
243 if ( nPanelCount
> 0 )
246 case ACTION_ACTIVATE_PREV
:
247 if ( !aCurrentPanel
&& ( nPanelCount
> 0 ) )
248 aActivatePanel
= nPanelCount
- 1;
249 else if ( !!aCurrentPanel
&& ( *aCurrentPanel
> 0 ) )
250 aActivatePanel
= *aCurrentPanel
- 1;
252 case ACTION_ACTIVATE_NEXT
:
253 if ( !aCurrentPanel
&& ( nPanelCount
> 0 ) )
255 else if ( !!aCurrentPanel
&& ( *aCurrentPanel
< nPanelCount
- 1 ) )
256 aActivatePanel
= *aCurrentPanel
+ 1;
258 case ACTION_ACTIVATE_LAST
:
259 if ( nPanelCount
> 0 )
260 aActivatePanel
= nPanelCount
- 1;
262 case ACTION_TOGGLE_FOCUS
:
264 PToolPanel
pActivePanel( GetActiveOrDummyPanel_Impl() );
265 if ( !m_aPanelAnchor
->HasChildPathFocus() )
266 pActivePanel
->GrabFocus();
268 GetLayouter()->SetFocusToPanelSelector();
273 if ( !!aActivatePanel
)
275 ActivatePanel( aActivatePanel
);
280 bool ToolPanelDeck_Impl::FocusActivePanel()
282 ::boost::optional
< size_t > aActivePanel( m_aPanels
.GetActivePanel() );
286 PToolPanel
pActivePanel( m_aPanels
.GetPanel( *aActivePanel
) );
287 pActivePanel
->GrabFocus();
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
)
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.
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()
360 void ToolPanelDeck::dispose()
362 m_pImpl
->NotifyDying();
363 GetLayouter()->Destroy();
366 for ( size_t i
=0; i
<GetPanelCount(); ++i
)
368 PToolPanel
pPanel( GetPanel( i
) );
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()
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
)
464 switch ( rKeyCode
.GetCode() )
467 m_pImpl
->DoAction( ACTION_ACTIVATE_FIRST
);
470 m_pImpl
->DoAction( ACTION_ACTIVATE_PREV
);
473 m_pImpl
->DoAction( ACTION_ACTIVATE_NEXT
);
476 m_pImpl
->DoAction( ACTION_ACTIVATE_LAST
);
483 else if ( rKeyCode
.GetModifier() == ( KEY_MOD1
| KEY_SHIFT
) )
485 if ( rKeyCode
.GetCode() == KEY_E
)
487 m_pImpl
->DoAction( ACTION_TOGGLE_FOCUS
);
496 return Control::Notify( i_rNotifyEvent
);
500 void ToolPanelDeck::GetFocus()
503 if ( m_pImpl
->IsDead() )
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
);
529 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */