1 /************************************************************************* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * Copyright 2000, 2010 Oracle and/or its affiliates. 5 * 6 * OpenOffice.org - a multi-platform office productivity suite 7 * 8 * This file is part of OpenOffice.org. 9 * 10 * OpenOffice.org is free software: you can redistribute it and/or modify 11 * it under the terms of the GNU Lesser General Public License version 3 12 * only, as published by the Free Software Foundation. 13 * 14 * OpenOffice.org is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU Lesser General Public License version 3 for more details 18 * (a copy is included in the LICENSE file that accompanied this code). 19 * 20 * You should have received a copy of the GNU Lesser General Public License 21 * version 3 along with OpenOffice.org. If not, see 22 * <http://www.openoffice.org/license.html> 23 * for a copy of the LGPLv3 License. 24 * 25 ************************************************************************/ 26 27 #include "precompiled_svtools.hxx" 28 29 #include "dummypanel.hxx" 30 #include "toolpanelcollection.hxx" 31 #include "paneldecklisteners.hxx" 32 #include "toolpaneldeckpeer.hxx" 33 #include "svtools/toolpanel/toolpaneldeck.hxx" 34 #include "svtools/toolpanel/tablayouter.hxx" 35 #include "svtools/toolpanel/drawerlayouter.hxx" 36 37 /** === begin UNO includes === **/ 38 #include <com/sun/star/accessibility/XAccessible.hpp> 39 #include <com/sun/star/accessibility/AccessibleRole.hpp> 40 /** === end UNO includes === **/ 41 42 #include <tools/diagnose_ex.h> 43 44 #include <boost/optional.hpp> 45 46 //........................................................................ 47 namespace svt 48 { 49 //........................................................................ 50 51 /** === begin UNO using === **/ 52 using ::com::sun::star::uno::Reference; 53 using ::com::sun::star::accessibility::XAccessible; 54 using ::com::sun::star::awt::XWindowPeer; 55 using ::com::sun::star::uno::UNO_SET_THROW; 56 /** === end UNO using === **/ 57 namespace AccessibleRole = ::com::sun::star::accessibility::AccessibleRole; 58 59 enum DeckAction 60 { 61 /// activates the first panel 62 ACTION_ACTIVATE_FIRST, 63 // activates the panel after the currently active panel 64 ACTION_ACTIVATE_NEXT, 65 // activates the panel before the currently active panel 66 ACTION_ACTIVATE_PREV, 67 // activates the last panel 68 ACTION_ACTIVATE_LAST, 69 70 // toggles the focus between the active panel and the panel selector 71 ACTION_TOGGLE_FOCUS, 72 }; 73 74 //==================================================================== 75 //= ToolPanelDeck_Impl 76 //==================================================================== 77 class ToolPanelDeck_Impl : public IToolPanelDeckListener 78 { 79 public: 80 ToolPanelDeck_Impl( ToolPanelDeck& i_rDeck ) 81 :m_rDeck( i_rDeck ) 82 ,m_aPanelAnchor( &i_rDeck, WB_DIALOGCONTROL | WB_CHILDDLGCTRL ) 83 ,m_aPanels() 84 ,m_pDummyPanel( new DummyPanel ) 85 ,m_pLayouter() 86 ,m_bInDtor( false ) 87 ,m_pAccessibleParent( NULL ) 88 { 89 m_aPanels.AddListener( *this ); 90 m_aPanelAnchor.Show(); 91 m_aPanelAnchor.SetAccessibleRole( AccessibleRole::PANEL ); 92 } 93 94 ~ToolPanelDeck_Impl() 95 { 96 m_bInDtor = true; 97 } 98 99 PDeckLayouter GetLayouter() const { return m_pLayouter; } 100 void SetLayouter( const PDeckLayouter& i_pNewLayouter ); 101 102 Window& GetPanelWindowAnchor() { return m_aPanelAnchor; } 103 const Window& GetPanelWindowAnchor() const { return m_aPanelAnchor; } 104 105 bool IsDead() const { return m_bInDtor; } 106 107 /// notifies our listeners that we're going to die. Only to be called from with our anti-impl's destructor 108 void NotifyDying() 109 { 110 m_aPanels.RemoveListener( *this ); 111 m_aListeners.Dying(); 112 } 113 114 // IToolPanelDeck equivalents 115 size_t GetPanelCount() const; 116 PToolPanel GetPanel( const size_t i_nPos ) const; 117 ::boost::optional< size_t > 118 GetActivePanel() const; 119 void ActivatePanel( const ::boost::optional< size_t >& i_rPanel ); 120 size_t InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition ); 121 PToolPanel RemovePanel( const size_t i_nPosition ); 122 void AddListener( IToolPanelDeckListener& i_rListener ); 123 void RemoveListener( IToolPanelDeckListener& i_rListener ); 124 125 /// re-layouts everything 126 void LayoutAll() { ImplDoLayout(); } 127 128 void DoAction( const DeckAction i_eAction ); 129 130 bool FocusActivePanel(); 131 132 void SetAccessibleParentWindow( Window* i_pAccessibleParent ); 133 Window* GetAccessibleParentWindow() const { return m_pAccessibleParent; } 134 135 protected: 136 // IToolPanelDeckListener 137 virtual void PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition ); 138 virtual void PanelRemoved( const size_t i_nPosition ); 139 virtual void ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ); 140 virtual void LayouterChanged( const PDeckLayouter& i_rNewLayouter ); 141 virtual void Dying(); 142 143 private: 144 void ImplDoLayout(); 145 PToolPanel GetActiveOrDummyPanel_Impl(); 146 147 private: 148 ToolPanelDeck& m_rDeck; 149 Window m_aPanelAnchor; 150 ToolPanelCollection m_aPanels; 151 PToolPanel m_pDummyPanel; 152 PanelDeckListeners m_aListeners; 153 PDeckLayouter m_pLayouter; 154 bool m_bInDtor; 155 Window* m_pAccessibleParent; 156 }; 157 158 //-------------------------------------------------------------------- 159 PToolPanel ToolPanelDeck_Impl::GetActiveOrDummyPanel_Impl() 160 { 161 ::boost::optional< size_t > aActivePanel( m_aPanels.GetActivePanel() ); 162 if ( !aActivePanel ) 163 return m_pDummyPanel; 164 return m_aPanels.GetPanel( *aActivePanel ); 165 } 166 167 //-------------------------------------------------------------------- 168 void ToolPanelDeck_Impl::SetLayouter( const PDeckLayouter& i_pNewLayouter ) 169 { 170 ENSURE_OR_RETURN_VOID( i_pNewLayouter.get(), "invalid layouter" ); 171 172 if ( m_pLayouter.get() ) 173 m_pLayouter->Destroy(); 174 175 m_pLayouter = i_pNewLayouter; 176 177 ImplDoLayout(); 178 179 m_aListeners.LayouterChanged( m_pLayouter ); 180 } 181 182 //-------------------------------------------------------------------- 183 size_t ToolPanelDeck_Impl::GetPanelCount() const 184 { 185 return m_aPanels.GetPanelCount(); 186 } 187 188 //-------------------------------------------------------------------- 189 PToolPanel ToolPanelDeck_Impl::GetPanel( const size_t i_nPos ) const 190 { 191 return m_aPanels.GetPanel( i_nPos ); 192 } 193 194 //-------------------------------------------------------------------- 195 ::boost::optional< size_t > ToolPanelDeck_Impl::GetActivePanel() const 196 { 197 return m_aPanels.GetActivePanel(); 198 } 199 200 //-------------------------------------------------------------------- 201 void ToolPanelDeck_Impl::ActivatePanel( const ::boost::optional< size_t >& i_rPanel ) 202 { 203 m_aPanels.ActivatePanel( i_rPanel ); 204 } 205 206 //-------------------------------------------------------------------- 207 size_t ToolPanelDeck_Impl::InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition ) 208 { 209 return m_aPanels.InsertPanel( i_pPanel, i_nPosition ); 210 } 211 212 //-------------------------------------------------------------------- 213 PToolPanel ToolPanelDeck_Impl::RemovePanel( const size_t i_nPosition ) 214 { 215 return m_aPanels.RemovePanel( i_nPosition ); 216 } 217 218 //-------------------------------------------------------------------- 219 void ToolPanelDeck_Impl::ImplDoLayout() 220 { 221 const Rectangle aDeckPlayground( Point(), m_rDeck.GetOutputSizePixel() ); 222 223 // ask the layouter what is left for our panel, and position the panel container window appropriately 224 Rectangle aPlaygroundArea( aDeckPlayground ); 225 OSL_ENSURE( m_pLayouter.get(), "ToolPanelDeck_Impl::ImplDoLayout: no layouter!" ); 226 if ( m_pLayouter.get() ) 227 { 228 aPlaygroundArea = m_pLayouter->Layout( aDeckPlayground ); 229 } 230 m_aPanelAnchor.SetPosSizePixel( aPlaygroundArea.TopLeft(), aPlaygroundArea.GetSize() ); 231 232 // position the active panel 233 const PToolPanel pActive( GetActiveOrDummyPanel_Impl() ); 234 pActive->SetSizePixel( m_aPanelAnchor.GetOutputSizePixel() ); 235 } 236 237 //-------------------------------------------------------------------- 238 void ToolPanelDeck_Impl::AddListener( IToolPanelDeckListener& i_rListener ) 239 { 240 m_aListeners.AddListener( i_rListener ); 241 } 242 243 //-------------------------------------------------------------------- 244 void ToolPanelDeck_Impl::RemoveListener( IToolPanelDeckListener& i_rListener ) 245 { 246 m_aListeners.RemoveListener( i_rListener ); 247 } 248 249 //-------------------------------------------------------------------- 250 void ToolPanelDeck_Impl::DoAction( const DeckAction i_eAction ) 251 { 252 const size_t nPanelCount( m_aPanels.GetPanelCount() ); 253 ::boost::optional< size_t > aActivatePanel; 254 ::boost::optional< size_t > aCurrentPanel( GetActivePanel() ); 255 256 switch ( i_eAction ) 257 { 258 case ACTION_ACTIVATE_FIRST: 259 if ( nPanelCount > 0 ) 260 aActivatePanel = 0; 261 break; 262 case ACTION_ACTIVATE_PREV: 263 if ( !aCurrentPanel && ( nPanelCount > 0 ) ) 264 aActivatePanel = nPanelCount - 1; 265 else 266 if ( !!aCurrentPanel && ( *aCurrentPanel > 0 ) ) 267 aActivatePanel = *aCurrentPanel - 1; 268 break; 269 case ACTION_ACTIVATE_NEXT: 270 if ( !aCurrentPanel && ( nPanelCount > 0 ) ) 271 aActivatePanel = 0; 272 else 273 if ( !!aCurrentPanel && ( *aCurrentPanel < nPanelCount - 1 ) ) 274 aActivatePanel = *aCurrentPanel + 1; 275 break; 276 case ACTION_ACTIVATE_LAST: 277 if ( nPanelCount > 0 ) 278 aActivatePanel = nPanelCount - 1; 279 break; 280 case ACTION_TOGGLE_FOCUS: 281 { 282 PToolPanel pActivePanel( GetActiveOrDummyPanel_Impl() ); 283 if ( !m_aPanelAnchor.HasChildPathFocus() ) 284 pActivePanel->GrabFocus(); 285 else 286 GetLayouter()->SetFocusToPanelSelector(); 287 } 288 break; 289 } 290 291 if ( !!aActivatePanel ) 292 { 293 ActivatePanel( aActivatePanel ); 294 } 295 } 296 297 //-------------------------------------------------------------------- 298 bool ToolPanelDeck_Impl::FocusActivePanel() 299 { 300 ::boost::optional< size_t > aActivePanel( m_aPanels.GetActivePanel() ); 301 if ( !aActivePanel ) 302 return false; 303 304 PToolPanel pActivePanel( m_aPanels.GetPanel( *aActivePanel ) ); 305 pActivePanel->GrabFocus(); 306 return true; 307 } 308 309 //-------------------------------------------------------------------- 310 void ToolPanelDeck_Impl::PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition ) 311 { 312 // multiplex to our own listeners 313 m_aListeners.PanelInserted( i_pPanel, i_nPosition ); 314 } 315 316 //-------------------------------------------------------------------- 317 void ToolPanelDeck_Impl::PanelRemoved( const size_t i_nPosition ) 318 { 319 // multiplex to our own listeners 320 m_aListeners.PanelRemoved( i_nPosition ); 321 } 322 323 //-------------------------------------------------------------------- 324 void ToolPanelDeck_Impl::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ) 325 { 326 // hide the old panel 327 if ( !!i_rOldActive ) 328 { 329 const PToolPanel pOldActive( m_aPanels.GetPanel( *i_rOldActive ) ); 330 pOldActive->Deactivate(); 331 } 332 333 // position and show the new panel 334 const PToolPanel pNewActive( !i_rNewActive ? m_pDummyPanel : m_aPanels.GetPanel( *i_rNewActive ) ); 335 pNewActive->Activate( m_aPanelAnchor ); 336 pNewActive->GrabFocus(); 337 338 // resize the panel (cannot guarantee it has ever been resized before 339 pNewActive->SetSizePixel( m_aPanelAnchor.GetOutputSizePixel() ); 340 341 // multiplex to our own listeners 342 m_aListeners.ActivePanelChanged( i_rOldActive, i_rNewActive ); 343 } 344 345 //-------------------------------------------------------------------- 346 void ToolPanelDeck_Impl::LayouterChanged( const PDeckLayouter& i_rNewLayouter ) 347 { 348 // not interested in 349 (void)i_rNewLayouter; 350 } 351 352 //-------------------------------------------------------------------- 353 void ToolPanelDeck_Impl::Dying() 354 { 355 // not interested in. Since the ToolPanelCollection is our member, this just means we ourself 356 // are dying, and we already sent this notification in our dtor. 357 } 358 359 //-------------------------------------------------------------------- 360 void ToolPanelDeck_Impl::SetAccessibleParentWindow( Window* i_pAccessibleParent ) 361 { 362 m_pAccessibleParent = i_pAccessibleParent; 363 } 364 365 //==================================================================== 366 //= ToolPanelDeck 367 //==================================================================== 368 //-------------------------------------------------------------------- 369 ToolPanelDeck::ToolPanelDeck( Window& i_rParent, const WinBits i_nStyle ) 370 :Control( &i_rParent, i_nStyle ) 371 ,m_pImpl( new ToolPanelDeck_Impl( *this ) ) 372 { 373 // use a default layouter 374 // SetLayouter( PDeckLayouter( new TabDeckLayouter( *this, *this, TABS_RIGHT, TABITEM_IMAGE_AND_TEXT ) ) ); 375 SetLayouter( PDeckLayouter( new DrawerDeckLayouter( *this, *this ) ) ); 376 } 377 378 //-------------------------------------------------------------------- 379 ToolPanelDeck::~ToolPanelDeck() 380 { 381 m_pImpl->NotifyDying(); 382 GetLayouter()->Destroy(); 383 384 Hide(); 385 for ( size_t i=0; i<GetPanelCount(); ++i ) 386 { 387 PToolPanel pPanel( GetPanel( i ) ); 388 pPanel->Dispose(); 389 } 390 } 391 392 //-------------------------------------------------------------------- 393 size_t ToolPanelDeck::GetPanelCount() const 394 { 395 return m_pImpl->GetPanelCount(); 396 } 397 398 //-------------------------------------------------------------------- 399 PToolPanel ToolPanelDeck::GetPanel( const size_t i_nPos ) const 400 { 401 return m_pImpl->GetPanel( i_nPos ); 402 } 403 404 //-------------------------------------------------------------------- 405 ::boost::optional< size_t > ToolPanelDeck::GetActivePanel() const 406 { 407 return m_pImpl->GetActivePanel(); 408 } 409 410 //-------------------------------------------------------------------- 411 void ToolPanelDeck::ActivatePanel( const ::boost::optional< size_t >& i_rPanel ) 412 { 413 m_pImpl->ActivatePanel( i_rPanel ); 414 } 415 416 //-------------------------------------------------------------------- 417 size_t ToolPanelDeck::InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition ) 418 { 419 return m_pImpl->InsertPanel( i_pPanel, i_nPosition ); 420 } 421 422 //-------------------------------------------------------------------- 423 PToolPanel ToolPanelDeck::RemovePanel( const size_t i_nPosition ) 424 { 425 return m_pImpl->RemovePanel( i_nPosition ); 426 } 427 428 //-------------------------------------------------------------------- 429 PDeckLayouter ToolPanelDeck::GetLayouter() const 430 { 431 return m_pImpl->GetLayouter(); 432 } 433 434 //-------------------------------------------------------------------- 435 void ToolPanelDeck::SetLayouter( const PDeckLayouter& i_pNewLayouter ) 436 { 437 return m_pImpl->SetLayouter( i_pNewLayouter ); 438 } 439 440 //-------------------------------------------------------------------- 441 void ToolPanelDeck::AddListener( IToolPanelDeckListener& i_rListener ) 442 { 443 m_pImpl->AddListener( i_rListener ); 444 } 445 446 //-------------------------------------------------------------------- 447 void ToolPanelDeck::RemoveListener( IToolPanelDeckListener& i_rListener ) 448 { 449 m_pImpl->RemoveListener( i_rListener ); 450 } 451 452 //-------------------------------------------------------------------- 453 Window& ToolPanelDeck::GetPanelWindowAnchor() 454 { 455 return m_pImpl->GetPanelWindowAnchor(); 456 } 457 458 //-------------------------------------------------------------------- 459 const Window& ToolPanelDeck::GetPanelWindowAnchor() const 460 { 461 return m_pImpl->GetPanelWindowAnchor(); 462 } 463 464 //-------------------------------------------------------------------- 465 void ToolPanelDeck::Resize() 466 { 467 Control::Resize(); 468 m_pImpl->LayoutAll(); 469 } 470 471 //-------------------------------------------------------------------- 472 long ToolPanelDeck::Notify( NotifyEvent& i_rNotifyEvent ) 473 { 474 bool bHandled = false; 475 if ( i_rNotifyEvent.GetType() == EVENT_KEYINPUT ) 476 { 477 const KeyEvent* pEvent = i_rNotifyEvent.GetKeyEvent(); 478 const KeyCode& rKeyCode = pEvent->GetKeyCode(); 479 if ( rKeyCode.GetModifier() == KEY_MOD1 ) 480 { 481 bHandled = true; 482 switch ( rKeyCode.GetCode() ) 483 { 484 case KEY_HOME: 485 m_pImpl->DoAction( ACTION_ACTIVATE_FIRST ); 486 break; 487 case KEY_PAGEUP: 488 m_pImpl->DoAction( ACTION_ACTIVATE_PREV ); 489 break; 490 case KEY_PAGEDOWN: 491 m_pImpl->DoAction( ACTION_ACTIVATE_NEXT ); 492 break; 493 case KEY_END: 494 m_pImpl->DoAction( ACTION_ACTIVATE_LAST ); 495 break; 496 default: 497 bHandled = false; 498 break; 499 } 500 } 501 else if ( rKeyCode.GetModifier() == ( KEY_MOD1 | KEY_SHIFT ) ) 502 { 503 if ( rKeyCode.GetCode() == KEY_E ) 504 { 505 m_pImpl->DoAction( ACTION_TOGGLE_FOCUS ); 506 bHandled = true; 507 } 508 } 509 } 510 511 if ( bHandled ) 512 return 1; 513 514 return Control::Notify( i_rNotifyEvent ); 515 } 516 517 //-------------------------------------------------------------------- 518 void ToolPanelDeck::GetFocus() 519 { 520 Control::GetFocus(); 521 if ( m_pImpl->IsDead() ) 522 return; 523 if ( !m_pImpl->FocusActivePanel() ) 524 { 525 PDeckLayouter pLayouter( GetLayouter() ); 526 ENSURE_OR_RETURN_VOID( pLayouter.get(), "ToolPanelDeck::GetFocus: no layouter?!" ); 527 pLayouter->SetFocusToPanelSelector(); 528 } 529 } 530 531 //-------------------------------------------------------------------- 532 void ToolPanelDeck::SetAccessibleParentWindow( Window* i_pAccessibleParent ) 533 { 534 m_pImpl->SetAccessibleParentWindow( i_pAccessibleParent ); 535 } 536 537 //-------------------------------------------------------------------- 538 Window* ToolPanelDeck::GetAccessibleParentWindow() const 539 { 540 Window* pAccessibleParent( m_pImpl->GetAccessibleParentWindow() ); 541 if ( !pAccessibleParent ) 542 pAccessibleParent = Window::GetAccessibleParentWindow(); 543 return pAccessibleParent; 544 } 545 546 //-------------------------------------------------------------------- 547 Reference< XWindowPeer > ToolPanelDeck::GetComponentInterface( sal_Bool i_bCreate ) 548 { 549 Reference< XWindowPeer > xWindowPeer( Control::GetComponentInterface( sal_False ) ); 550 if ( !xWindowPeer.is() && i_bCreate ) 551 { 552 xWindowPeer.set( new ToolPanelDeckPeer( *this ) ); 553 SetComponentInterface( xWindowPeer ); 554 } 555 return xWindowPeer; 556 } 557 558 //........................................................................ 559 } // namespace svt 560 //........................................................................ 561