1*5900e8ecSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*5900e8ecSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*5900e8ecSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*5900e8ecSAndrew Rist  * distributed with this work for additional information
6*5900e8ecSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*5900e8ecSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*5900e8ecSAndrew Rist  * "License"); you may not use this file except in compliance
9*5900e8ecSAndrew Rist  * with the License.  You may obtain a copy of the License at
10*5900e8ecSAndrew Rist  *
11*5900e8ecSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*5900e8ecSAndrew Rist  *
13*5900e8ecSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*5900e8ecSAndrew Rist  * software distributed under the License is distributed on an
15*5900e8ecSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*5900e8ecSAndrew Rist  * KIND, either express or implied.  See the License for the
17*5900e8ecSAndrew Rist  * specific language governing permissions and limitations
18*5900e8ecSAndrew Rist  * under the License.
19*5900e8ecSAndrew Rist  *
20*5900e8ecSAndrew Rist  *************************************************************/
21*5900e8ecSAndrew Rist 
22*5900e8ecSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir #include "precompiled_svtools.hxx"
25cdf0e10cSrcweir 
26cdf0e10cSrcweir #include "svtools/toolpanel/drawerlayouter.hxx"
27cdf0e10cSrcweir #include "toolpaneldrawer.hxx"
28cdf0e10cSrcweir 
29cdf0e10cSrcweir #include <com/sun/star/accessibility/XAccessible.hpp>
30cdf0e10cSrcweir 
31cdf0e10cSrcweir #include <comphelper/accimplaccess.hxx>
32cdf0e10cSrcweir #include <tools/diagnose_ex.h>
33cdf0e10cSrcweir 
34cdf0e10cSrcweir //......................................................................................................................
35cdf0e10cSrcweir namespace svt
36cdf0e10cSrcweir {
37cdf0e10cSrcweir //......................................................................................................................
38cdf0e10cSrcweir 
39cdf0e10cSrcweir     /** === begin UNO using === **/
40cdf0e10cSrcweir     using ::com::sun::star::uno::Reference;
41cdf0e10cSrcweir     using ::com::sun::star::accessibility::XAccessible;
42cdf0e10cSrcweir     /** === end UNO using === **/
43cdf0e10cSrcweir 
44cdf0e10cSrcweir 	//==================================================================================================================
45cdf0e10cSrcweir 	//= DrawerDeckLayouter
46cdf0e10cSrcweir 	//==================================================================================================================
47cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
DrawerDeckLayouter(::Window & i_rParentWindow,IToolPanelDeck & i_rPanels)48cdf0e10cSrcweir     DrawerDeckLayouter::DrawerDeckLayouter( ::Window& i_rParentWindow, IToolPanelDeck& i_rPanels )
49cdf0e10cSrcweir         :m_rParentWindow( i_rParentWindow )
50cdf0e10cSrcweir         ,m_rPanelDeck( i_rPanels )
51cdf0e10cSrcweir         ,m_aDrawers()
52cdf0e10cSrcweir         ,m_aLastKnownActivePanel()
53cdf0e10cSrcweir     {
54cdf0e10cSrcweir         m_rPanelDeck.AddListener( *this );
55cdf0e10cSrcweir 
56cdf0e10cSrcweir         // simulate PanelInserted events for the panels which are already there
57cdf0e10cSrcweir         for ( size_t i=0; i<m_rPanelDeck.GetPanelCount(); ++i )
58cdf0e10cSrcweir             PanelInserted( m_rPanelDeck.GetPanel( i ), i );
59cdf0e10cSrcweir     }
60cdf0e10cSrcweir 
61cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
~DrawerDeckLayouter()62cdf0e10cSrcweir     DrawerDeckLayouter::~DrawerDeckLayouter()
63cdf0e10cSrcweir     {
64cdf0e10cSrcweir     }
65cdf0e10cSrcweir 
66cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
IMPLEMENT_IREFERENCE(DrawerDeckLayouter)67cdf0e10cSrcweir     IMPLEMENT_IREFERENCE( DrawerDeckLayouter )
68cdf0e10cSrcweir 
69cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
70cdf0e10cSrcweir     Rectangle DrawerDeckLayouter::Layout( const Rectangle& i_rDeckPlayground )
71cdf0e10cSrcweir     {
72cdf0e10cSrcweir         const size_t nPanelCount( m_rPanelDeck.GetPanelCount() );
73cdf0e10cSrcweir         if ( nPanelCount == 0 )
74cdf0e10cSrcweir             return i_rDeckPlayground;
75cdf0e10cSrcweir 
76cdf0e10cSrcweir         const int nWidth( i_rDeckPlayground.GetWidth() );
77cdf0e10cSrcweir         ::boost::optional< size_t > aActivePanel( m_rPanelDeck.GetActivePanel() );
78cdf0e10cSrcweir         if ( !aActivePanel )
79cdf0e10cSrcweir             aActivePanel = m_aLastKnownActivePanel;
80cdf0e10cSrcweir 
81cdf0e10cSrcweir         // arrange the title bars which are *above* the active panel (or *all* if there is no active panel), plus
82cdf0e10cSrcweir         // the title bar of the active panel itself
83cdf0e10cSrcweir         Point aUpperDrawerPos( i_rDeckPlayground.TopLeft() );
84cdf0e10cSrcweir         const size_t nUpperBound = !!aActivePanel ? *aActivePanel : nPanelCount - 1;
85cdf0e10cSrcweir         for ( size_t i=0; i<=nUpperBound; ++i )
86cdf0e10cSrcweir         {
87cdf0e10cSrcweir             long const nDrawerHeight = m_aDrawers[i]->GetPreferredHeightPixel();
88cdf0e10cSrcweir             m_aDrawers[i]->SetPosSizePixel(
89cdf0e10cSrcweir                 aUpperDrawerPos, Size( nWidth, nDrawerHeight ) );
90cdf0e10cSrcweir             aUpperDrawerPos.Move( 0, nDrawerHeight );
91cdf0e10cSrcweir         }
92cdf0e10cSrcweir 
93cdf0e10cSrcweir         // arrange title bars which are below the active panel (or *none* if there is no active panel)
94cdf0e10cSrcweir         Point aLowerDrawerPos( i_rDeckPlayground.BottomLeft() );
95cdf0e10cSrcweir         for ( size_t j = nPanelCount - 1; j > nUpperBound; --j )
96cdf0e10cSrcweir         {
97cdf0e10cSrcweir             long const nDrawerHeight = m_aDrawers[j]->GetPreferredHeightPixel();
98cdf0e10cSrcweir             m_aDrawers[j]->SetPosSizePixel(
99cdf0e10cSrcweir                 Point( aLowerDrawerPos.X(), aLowerDrawerPos.Y() - nDrawerHeight + 1 ),
100cdf0e10cSrcweir                 Size( nWidth, nDrawerHeight )
101cdf0e10cSrcweir             );
102cdf0e10cSrcweir             aLowerDrawerPos.Move( 0, -nDrawerHeight );
103cdf0e10cSrcweir         }
104cdf0e10cSrcweir 
105cdf0e10cSrcweir         // fincally calculate the rectangle for the active panel
106cdf0e10cSrcweir         return Rectangle(
107cdf0e10cSrcweir             aUpperDrawerPos,
108cdf0e10cSrcweir             Size( nWidth, aLowerDrawerPos.Y() - aUpperDrawerPos.Y() + 1 )
109cdf0e10cSrcweir         );
110cdf0e10cSrcweir     }
111cdf0e10cSrcweir 
112cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
Destroy()113cdf0e10cSrcweir     void DrawerDeckLayouter::Destroy()
114cdf0e10cSrcweir     {
115cdf0e10cSrcweir         while ( !m_aDrawers.empty() )
116cdf0e10cSrcweir             impl_removeDrawer( 0 );
117cdf0e10cSrcweir         m_rPanelDeck.RemoveListener( *this );
118cdf0e10cSrcweir     }
119cdf0e10cSrcweir 
120cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
SetFocusToPanelSelector()121cdf0e10cSrcweir     void DrawerDeckLayouter::SetFocusToPanelSelector()
122cdf0e10cSrcweir     {
123cdf0e10cSrcweir         const size_t nPanelCount( m_rPanelDeck.GetPanelCount() );
124cdf0e10cSrcweir         if ( !nPanelCount )
125cdf0e10cSrcweir             // nothing to focus
126cdf0e10cSrcweir             return;
127cdf0e10cSrcweir         ::boost::optional< size_t > aActivePanel( m_rPanelDeck.GetActivePanel() );
128cdf0e10cSrcweir         if ( !aActivePanel )
129cdf0e10cSrcweir             aActivePanel = 0;
130cdf0e10cSrcweir         ENSURE_OR_RETURN_VOID( *aActivePanel < m_aDrawers.size(), "DrawerDeckLayouter::SetFocusToPanelSelector: invalid active panel, or inconsistent drawers!" );
131cdf0e10cSrcweir         m_aDrawers[ *aActivePanel ]->GrabFocus();
132cdf0e10cSrcweir     }
133cdf0e10cSrcweir 
134cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
GetAccessibleChildCount() const135cdf0e10cSrcweir     size_t DrawerDeckLayouter::GetAccessibleChildCount() const
136cdf0e10cSrcweir     {
137cdf0e10cSrcweir         return m_aDrawers.size();
138cdf0e10cSrcweir     }
139cdf0e10cSrcweir 
140cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
GetAccessibleChild(const size_t i_nChildIndex,const Reference<XAccessible> & i_rParentAccessible)141cdf0e10cSrcweir     Reference< XAccessible > DrawerDeckLayouter::GetAccessibleChild( const size_t i_nChildIndex, const Reference< XAccessible >& i_rParentAccessible )
142cdf0e10cSrcweir     {
143cdf0e10cSrcweir         ENSURE_OR_RETURN( i_nChildIndex < m_aDrawers.size(), "illegal index", NULL );
144cdf0e10cSrcweir 
145cdf0e10cSrcweir         const PToolPanelDrawer pDrawer( m_aDrawers[ i_nChildIndex ] );
146cdf0e10cSrcweir 
147cdf0e10cSrcweir         Reference< XAccessible > xItemAccessible = pDrawer->GetAccessible( sal_False );
148cdf0e10cSrcweir         if ( !xItemAccessible.is() )
149cdf0e10cSrcweir         {
150cdf0e10cSrcweir             xItemAccessible = pDrawer->GetAccessible( sal_True );
151cdf0e10cSrcweir             ENSURE_OR_RETURN( xItemAccessible.is(), "illegal accessible provided by the drawer implementation!", NULL );
152cdf0e10cSrcweir             OSL_VERIFY( ::comphelper::OAccessibleImplementationAccess::setAccessibleParent( xItemAccessible->getAccessibleContext(),
153cdf0e10cSrcweir                 i_rParentAccessible ) );
154cdf0e10cSrcweir         }
155cdf0e10cSrcweir 
156cdf0e10cSrcweir         return xItemAccessible;
157cdf0e10cSrcweir     }
158cdf0e10cSrcweir 
159cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
PanelInserted(const PToolPanel & i_pPanel,const size_t i_nPosition)160cdf0e10cSrcweir     void DrawerDeckLayouter::PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition )
161cdf0e10cSrcweir     {
162cdf0e10cSrcweir         OSL_PRECOND( i_nPosition <= m_aDrawers.size(), "DrawerDeckLayouter::PanelInserted: inconsistency!" );
163cdf0e10cSrcweir 
164cdf0e10cSrcweir         PToolPanelDrawer pDrawer( new ToolPanelDrawer( m_rParentWindow, i_pPanel->GetDisplayName() ) );
165cdf0e10cSrcweir         pDrawer->SetHelpId( i_pPanel->GetHelpID() );
166cdf0e10cSrcweir         // proper Z-Order
167cdf0e10cSrcweir         if ( i_nPosition == 0 )
168cdf0e10cSrcweir         {
169cdf0e10cSrcweir             pDrawer->SetZOrder( NULL, WINDOW_ZORDER_FIRST );
170cdf0e10cSrcweir         }
171cdf0e10cSrcweir         else
172cdf0e10cSrcweir         {
173cdf0e10cSrcweir             const PToolPanelDrawer pFirstDrawer( m_aDrawers[ i_nPosition - 1 ] );
174cdf0e10cSrcweir             pDrawer->SetZOrder( pFirstDrawer.get(), WINDOW_ZORDER_BEHIND );
175cdf0e10cSrcweir         }
176cdf0e10cSrcweir 
177cdf0e10cSrcweir         pDrawer->Show();
178cdf0e10cSrcweir         pDrawer->AddEventListener( LINK( this, DrawerDeckLayouter, OnWindowEvent ) );
179cdf0e10cSrcweir         m_aDrawers.insert( m_aDrawers.begin() + i_nPosition, pDrawer );
180cdf0e10cSrcweir         impl_triggerRearrange();
181cdf0e10cSrcweir     }
182cdf0e10cSrcweir 
183cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
PanelRemoved(const size_t i_nPosition)184cdf0e10cSrcweir     void DrawerDeckLayouter::PanelRemoved( const size_t i_nPosition )
185cdf0e10cSrcweir     {
186cdf0e10cSrcweir         impl_removeDrawer( i_nPosition );
187cdf0e10cSrcweir         impl_triggerRearrange();
188cdf0e10cSrcweir     }
189cdf0e10cSrcweir 
190cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
impl_triggerRearrange() const191cdf0e10cSrcweir     void DrawerDeckLayouter::impl_triggerRearrange() const
192cdf0e10cSrcweir     {
193cdf0e10cSrcweir         // this is somewhat hacky, it assumes that the parent of our panels is a tool panel deck, which, in its
194cdf0e10cSrcweir         // Resize implementation, rearrances all elements.
195cdf0e10cSrcweir         m_rParentWindow.Resize();
196cdf0e10cSrcweir     }
197cdf0e10cSrcweir 
198cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
ActivePanelChanged(const::boost::optional<size_t> & i_rOldActive,const::boost::optional<size_t> & i_rNewActive)199cdf0e10cSrcweir     void DrawerDeckLayouter::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive )
200cdf0e10cSrcweir     {
201cdf0e10cSrcweir         if ( !!i_rOldActive )
202cdf0e10cSrcweir         {
203cdf0e10cSrcweir             OSL_ENSURE( *i_rOldActive < m_aDrawers.size(), "DrawerDeckLayouter::ActivePanelChanged: illegal old index!" );
204cdf0e10cSrcweir             m_aDrawers[ *i_rOldActive ]->SetExpanded( false );
205cdf0e10cSrcweir         }
206cdf0e10cSrcweir 
207cdf0e10cSrcweir         if ( !!i_rNewActive )
208cdf0e10cSrcweir         {
209cdf0e10cSrcweir             OSL_ENSURE( *i_rNewActive < m_aDrawers.size(), "DrawerDeckLayouter::ActivePanelChanged: illegal new index!" );
210cdf0e10cSrcweir             m_aDrawers[ *i_rNewActive ]->SetExpanded( true );
211cdf0e10cSrcweir         }
212cdf0e10cSrcweir 
213cdf0e10cSrcweir         impl_triggerRearrange();
214cdf0e10cSrcweir     }
215cdf0e10cSrcweir 
216cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
LayouterChanged(const PDeckLayouter & i_rNewLayouter)217cdf0e10cSrcweir     void DrawerDeckLayouter::LayouterChanged( const PDeckLayouter& i_rNewLayouter )
218cdf0e10cSrcweir     {
219cdf0e10cSrcweir         // not interested in
220cdf0e10cSrcweir         (void)i_rNewLayouter;
221cdf0e10cSrcweir     }
222cdf0e10cSrcweir 
223cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
impl_getPanelPositionFromWindow(const Window * i_pDrawerWindow) const224cdf0e10cSrcweir     size_t DrawerDeckLayouter::impl_getPanelPositionFromWindow( const Window* i_pDrawerWindow ) const
225cdf0e10cSrcweir     {
226cdf0e10cSrcweir         for (   ::std::vector< PToolPanelDrawer >::const_iterator drawerPos = m_aDrawers.begin();
227cdf0e10cSrcweir                 drawerPos != m_aDrawers.end();
228cdf0e10cSrcweir                 ++drawerPos
229cdf0e10cSrcweir             )
230cdf0e10cSrcweir         {
231cdf0e10cSrcweir             if ( drawerPos->get() == i_pDrawerWindow )
232cdf0e10cSrcweir                 return drawerPos - m_aDrawers.begin();
233cdf0e10cSrcweir         }
234cdf0e10cSrcweir         return m_aDrawers.size();
235cdf0e10cSrcweir     }
236cdf0e10cSrcweir 
237cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
impl_removeDrawer(const size_t i_nPosition)238cdf0e10cSrcweir     void DrawerDeckLayouter::impl_removeDrawer( const size_t i_nPosition )
239cdf0e10cSrcweir     {
240cdf0e10cSrcweir         OSL_PRECOND( i_nPosition < m_aDrawers.size(), "DrawerDeckLayouter::impl_removeDrawer: invalid panel position!" );
241cdf0e10cSrcweir         m_aDrawers[ i_nPosition ]->RemoveEventListener( LINK( this, DrawerDeckLayouter, OnWindowEvent ) );
242cdf0e10cSrcweir         OSL_ENSURE( m_aDrawers[ i_nPosition ].unique(), "DrawerDeckLayouter::impl_removeDrawer: somebody else is still holding a reference!" );
243cdf0e10cSrcweir         m_aDrawers.erase( m_aDrawers.begin() + i_nPosition );
244cdf0e10cSrcweir     }
245cdf0e10cSrcweir 
246cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
IMPL_LINK(DrawerDeckLayouter,OnWindowEvent,VclSimpleEvent *,i_pEvent)247cdf0e10cSrcweir     IMPL_LINK( DrawerDeckLayouter, OnWindowEvent, VclSimpleEvent*, i_pEvent )
248cdf0e10cSrcweir     {
249cdf0e10cSrcweir         const VclWindowEvent* pWindowEvent = PTR_CAST( VclWindowEvent, i_pEvent );
250cdf0e10cSrcweir         ENSURE_OR_RETURN( pWindowEvent, "no WindowEvent", 0L );
251cdf0e10cSrcweir 
252cdf0e10cSrcweir         bool bActivatePanel = false;
253cdf0e10cSrcweir         switch ( pWindowEvent->GetId() )
254cdf0e10cSrcweir         {
255cdf0e10cSrcweir             case VCLEVENT_WINDOW_MOUSEBUTTONUP:
256cdf0e10cSrcweir             {
257cdf0e10cSrcweir                 const MouseEvent* pMouseEvent = static_cast< const MouseEvent* >( pWindowEvent->GetData() );
258cdf0e10cSrcweir                 ENSURE_OR_RETURN( pMouseEvent, "no mouse event with MouseButtonUp", 0L );
259cdf0e10cSrcweir                 if ( pMouseEvent->GetButtons() == MOUSE_LEFT )
260cdf0e10cSrcweir                 {
261cdf0e10cSrcweir                     bActivatePanel = true;
262cdf0e10cSrcweir                 }
263cdf0e10cSrcweir             }
264cdf0e10cSrcweir             break;
265cdf0e10cSrcweir             case VCLEVENT_WINDOW_KEYINPUT:
266cdf0e10cSrcweir             {
267cdf0e10cSrcweir                 const KeyEvent* pKeyEvent = static_cast< const KeyEvent* >( pWindowEvent->GetData() );
268cdf0e10cSrcweir                 ENSURE_OR_RETURN( pKeyEvent, "no key event with KeyInput", 0L );
269cdf0e10cSrcweir                 const KeyCode& rKeyCode( pKeyEvent->GetKeyCode() );
270cdf0e10cSrcweir                 if ( ( rKeyCode.GetModifier() == 0 ) && ( rKeyCode.GetCode() == KEY_RETURN ) )
271cdf0e10cSrcweir                 {
272cdf0e10cSrcweir                     bActivatePanel = true;
273cdf0e10cSrcweir                 }
274cdf0e10cSrcweir             }
275cdf0e10cSrcweir             break;
276cdf0e10cSrcweir         }
277cdf0e10cSrcweir         if ( bActivatePanel )
278cdf0e10cSrcweir         {
279cdf0e10cSrcweir             const size_t nPanelPos = impl_getPanelPositionFromWindow( pWindowEvent->GetWindow() );
280cdf0e10cSrcweir             if ( nPanelPos != m_rPanelDeck.GetActivePanel() )
281cdf0e10cSrcweir             {
282cdf0e10cSrcweir                 m_rPanelDeck.ActivatePanel( nPanelPos );
283cdf0e10cSrcweir             }
284cdf0e10cSrcweir             else
285cdf0e10cSrcweir             {
286cdf0e10cSrcweir                 PToolPanel pPanel( m_rPanelDeck.GetPanel( nPanelPos ) );
287cdf0e10cSrcweir                 pPanel->GrabFocus();
288cdf0e10cSrcweir             }
289cdf0e10cSrcweir             return 1L;
290cdf0e10cSrcweir         }
291cdf0e10cSrcweir         return 0L;
292cdf0e10cSrcweir     }
293cdf0e10cSrcweir 
294cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
Dying()295cdf0e10cSrcweir     void DrawerDeckLayouter::Dying()
296cdf0e10cSrcweir     {
297cdf0e10cSrcweir         Destroy();
298cdf0e10cSrcweir     }
299cdf0e10cSrcweir 
300cdf0e10cSrcweir //......................................................................................................................
301cdf0e10cSrcweir } // namespace svt
302cdf0e10cSrcweir //......................................................................................................................
303