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