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