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