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 #include "precompiled_sfx2.hxx" 23 24 #include "FocusManager.hxx" 25 #include "Panel.hxx" 26 #include "DeckTitleBar.hxx" 27 #include "PanelTitleBar.hxx" 28 #include "sfx2/sidebar/Tools.hxx" 29 #include "TitleBar.hxx" 30 #include <vcl/button.hxx> 31 #include <vcl/toolbox.hxx> 32 #include <toolkit/helper/vclunohelper.hxx> 33 34 35 namespace sfx2 { namespace sidebar { 36 37 FocusManager::FocusLocation::FocusLocation (const PanelComponent eComponent, const sal_Int32 nIndex) 38 : meComponent(eComponent), 39 mnIndex(nIndex) 40 { 41 } 42 43 44 45 46 FocusManager::FocusManager (const ::boost::function<void(const Panel&)>& rShowPanelFunctor) 47 : mpDeckTitleBar(), 48 maPanels(), 49 maButtons(), 50 maShowPanelFunctor(rShowPanelFunctor), 51 mbObservingContentControlFocus(false), 52 mpFirstFocusedContentControl(NULL) 53 { 54 } 55 56 57 58 59 FocusManager::~FocusManager (void) 60 { 61 Clear(); 62 } 63 64 65 66 67 void FocusManager::GrabFocus (void) 68 { 69 FocusDeckTitle(); 70 } 71 72 73 74 75 void FocusManager::Clear (void) 76 { 77 SetDeckTitle(NULL); 78 ClearPanels(); 79 ClearButtons(); 80 } 81 82 83 84 85 void FocusManager::ClearPanels (void) 86 { 87 ::std::vector<Panel*> aPanels; 88 aPanels.swap(maPanels); 89 for (::std::vector<Panel*>::iterator iPanel(aPanels.begin()),iEnd(aPanels.end()); 90 iPanel!=iEnd; 91 ++iPanel) 92 { 93 UnregisterWindow(**iPanel); 94 if ((*iPanel)->GetTitleBar() != NULL) 95 { 96 UnregisterWindow(*(*iPanel)->GetTitleBar()); 97 UnregisterWindow((*iPanel)->GetTitleBar()->GetToolBox()); 98 } 99 100 (*iPanel)->RemoveChildEventListener(LINK(this, FocusManager, ChildEventListener)); 101 } 102 } 103 104 105 106 107 void FocusManager::ClearButtons (void) 108 { 109 ::std::vector<Button*> aButtons; 110 aButtons.swap(maButtons); 111 for (::std::vector<Button*>::iterator iButton(aButtons.begin()),iEnd(aButtons.end()); 112 iButton!=iEnd; 113 ++iButton) 114 { 115 UnregisterWindow(**iButton); 116 } 117 } 118 119 120 121 122 void FocusManager::SetDeckTitle (DeckTitleBar* pDeckTitleBar) 123 { 124 if (mpDeckTitleBar != NULL) 125 { 126 UnregisterWindow(*mpDeckTitleBar); 127 UnregisterWindow(mpDeckTitleBar->GetToolBox()); 128 } 129 mpDeckTitleBar = pDeckTitleBar; 130 131 if (mpDeckTitleBar != NULL) 132 { 133 RegisterWindow(*mpDeckTitleBar); 134 RegisterWindow(mpDeckTitleBar->GetToolBox()); 135 } 136 } 137 138 139 140 141 void FocusManager::SetPanels (const SharedPanelContainer& rPanels) 142 { 143 ClearPanels(); 144 for(SharedPanelContainer::const_iterator iPanel(rPanels.begin()),iEnd(rPanels.end()); 145 iPanel!=iEnd; 146 ++iPanel) 147 { 148 RegisterWindow(**iPanel); 149 if ((*iPanel)->GetTitleBar() != NULL) 150 { 151 RegisterWindow(*(*iPanel)->GetTitleBar()); 152 RegisterWindow((*iPanel)->GetTitleBar()->GetToolBox()); 153 } 154 155 // Register also as child event listener at the panel. 156 (*iPanel)->AddChildEventListener(LINK(this, FocusManager, ChildEventListener)); 157 158 maPanels.push_back(iPanel->get()); 159 } 160 } 161 162 163 164 165 void FocusManager::SetButtons (const ::std::vector<Button*>& rButtons) 166 { 167 ClearButtons(); 168 for (::std::vector<Button*>::const_iterator iButton(rButtons.begin()),iEnd(rButtons.end()); 169 iButton!=iEnd; 170 ++iButton) 171 { 172 RegisterWindow(**iButton); 173 maButtons.push_back(*iButton); 174 } 175 } 176 177 178 179 180 void FocusManager::RegisterWindow (Window& rWindow) 181 { 182 rWindow.AddEventListener(LINK(this, FocusManager, WindowEventListener)); 183 } 184 185 186 187 188 void FocusManager::UnregisterWindow (Window& rWindow) 189 { 190 rWindow.RemoveEventListener(LINK(this, FocusManager, WindowEventListener)); 191 } 192 193 194 195 196 FocusManager::FocusLocation FocusManager::GetFocusLocation (const Window& rWindow) const 197 { 198 // Check the deck title. 199 if (mpDeckTitleBar != NULL) 200 { 201 if (mpDeckTitleBar == &rWindow) 202 return FocusLocation(PC_DeckTitle, -1); 203 else if (&mpDeckTitleBar->GetToolBox() == &rWindow) 204 return FocusLocation(PC_DeckToolBox, -1); 205 } 206 207 // Search the panels. 208 for (sal_Int32 nIndex=0,nCount(maPanels.size()); nIndex<nCount; ++nIndex) 209 { 210 if (maPanels[nIndex] == &rWindow) 211 return FocusLocation(PC_PanelContent, nIndex); 212 TitleBar* pTitleBar = maPanels[nIndex]->GetTitleBar(); 213 if (pTitleBar == &rWindow) 214 return FocusLocation(PC_PanelTitle, nIndex); 215 if (pTitleBar!=NULL && &pTitleBar->GetToolBox()==&rWindow) 216 return FocusLocation(PC_PanelToolBox, nIndex); 217 } 218 219 // Search the buttons. 220 for (sal_Int32 nIndex=0,nCount(maButtons.size()); nIndex<nCount; ++nIndex) 221 if (maButtons[nIndex] == &rWindow) 222 return FocusLocation(PC_TabBar, nIndex); 223 224 return FocusLocation(PC_None, -1); 225 } 226 227 228 229 230 bool FocusManager::IsAnyPanelFocused (void) const 231 { 232 for (::std::vector<Panel*>::const_iterator iPanel(maPanels.begin()),iEnd(maPanels.end()); 233 iPanel!=iEnd; 234 ++iPanel) 235 { 236 if ((*iPanel)->HasFocus()) 237 return true; 238 else if ((*iPanel)->HasChildPathFocus()) 239 return true; 240 } 241 return false; 242 } 243 244 245 246 247 bool FocusManager::IsAnyButtonFocused (void) const 248 { 249 for (::std::vector<Button*>::const_iterator iButton(maButtons.begin()),iEnd(maButtons.end()); 250 iButton!=iEnd; 251 ++iButton) 252 { 253 if ((*iButton)->HasFocus()) 254 return true; 255 } 256 return false; 257 } 258 259 260 261 262 void FocusManager::FocusDeckTitle (void) 263 { 264 if (mpDeckTitleBar != NULL) 265 { 266 if (IsDeckTitleVisible()) 267 { 268 mpDeckTitleBar->GrabFocus(); 269 } 270 else if (mpDeckTitleBar->GetToolBox().GetItemCount() > 0) 271 { 272 ToolBox& rToolBox = mpDeckTitleBar->GetToolBox(); 273 rToolBox.GrabFocus(); 274 rToolBox.Invalidate(); 275 } 276 else 277 FocusPanel(0, false); 278 } 279 else 280 FocusPanel(0, false); 281 } 282 283 284 285 286 bool FocusManager::IsDeckTitleVisible (void) const 287 { 288 return mpDeckTitleBar != NULL && mpDeckTitleBar->IsVisible(); 289 } 290 291 292 293 294 bool FocusManager::IsPanelTitleVisible (const sal_Int32 nPanelIndex) const 295 { 296 if (nPanelIndex<0 || nPanelIndex>=static_cast<sal_Int32>(maPanels.size())) 297 return false; 298 299 TitleBar* pTitleBar = maPanels[nPanelIndex]->GetTitleBar(); 300 if (pTitleBar==NULL) 301 return false; 302 return pTitleBar->IsVisible(); 303 } 304 305 306 307 308 void FocusManager::FocusPanel ( 309 const sal_Int32 nPanelIndex, 310 const bool bFallbackToDeckTitle) 311 { 312 if (nPanelIndex<0 || nPanelIndex>=static_cast<sal_Int32>(maPanels.size())) 313 { 314 if (bFallbackToDeckTitle) 315 FocusDeckTitle(); 316 return; 317 } 318 319 Panel& rPanel (*maPanels[nPanelIndex]); 320 TitleBar* pTitleBar = rPanel.GetTitleBar(); 321 if (pTitleBar!=NULL && pTitleBar->IsVisible()) 322 { 323 rPanel.SetExpanded(true); 324 pTitleBar->GrabFocus(); 325 } 326 else if (bFallbackToDeckTitle) 327 { 328 // The panel title is not visible, fall back to the deck 329 // title. 330 // Make sure that the desk title is visible here to prevent a 331 // loop when both the title of panel 0 and the deck title are 332 // not present. 333 if (IsDeckTitleVisible()) 334 FocusDeckTitle(); 335 else 336 FocusPanelContent(nPanelIndex); 337 } 338 else 339 FocusPanelContent(nPanelIndex); 340 341 if (maShowPanelFunctor) 342 maShowPanelFunctor(rPanel); 343 } 344 345 346 347 348 void FocusManager::FocusPanelContent (const sal_Int32 nPanelIndex) 349 { 350 Window* pWindow = VCLUnoHelper::GetWindow(maPanels[nPanelIndex]->GetElementWindow()); 351 if (pWindow != NULL) 352 { 353 mbObservingContentControlFocus = true; 354 pWindow->GrabFocus(); 355 mbObservingContentControlFocus = false; 356 } 357 } 358 359 360 361 362 void FocusManager::FocusButton (const sal_Int32 nButtonIndex) 363 { 364 maButtons[nButtonIndex]->GrabFocus(); 365 maButtons[nButtonIndex]->Invalidate(); 366 } 367 368 369 370 371 void FocusManager::ClickButton (const sal_Int32 nButtonIndex) 372 { 373 maButtons[nButtonIndex]->Click(); 374 if (nButtonIndex > 0) 375 if ( ! maPanels.empty()) 376 FocusPanel(0, true); 377 maButtons[nButtonIndex]->GetParent()->Invalidate(); 378 } 379 380 381 382 383 void FocusManager::RemoveWindow (Window& rWindow) 384 { 385 ::std::vector<Panel*>::iterator iPanel (::std::find(maPanels.begin(), maPanels.end(), &rWindow)); 386 if (iPanel != maPanels.end()) 387 { 388 UnregisterWindow(rWindow); 389 if ((*iPanel)->GetTitleBar() != NULL) 390 { 391 UnregisterWindow(*(*iPanel)->GetTitleBar()); 392 UnregisterWindow((*iPanel)->GetTitleBar()->GetToolBox()); 393 } 394 maPanels.erase(iPanel); 395 return; 396 } 397 398 ::std::vector<Button*>::iterator iButton (::std::find(maButtons.begin(), maButtons.end(), &rWindow)); 399 if (iButton != maButtons.end()) 400 { 401 UnregisterWindow(rWindow); 402 maButtons.erase(iButton); 403 return; 404 } 405 } 406 407 408 409 410 bool FocusManager::MoveFocusInsidePanel ( 411 const FocusLocation aFocusLocation, 412 const sal_Int32 nDirection) 413 { 414 const bool bHasToolBoxItem ( 415 maPanels[aFocusLocation.mnIndex]->GetTitleBar()->GetToolBox().GetItemCount() > 0); 416 switch (aFocusLocation.meComponent) 417 { 418 case PC_PanelTitle: 419 if (nDirection > 0 && bHasToolBoxItem) 420 maPanels[aFocusLocation.mnIndex]->GetTitleBar()->GetToolBox().GrabFocus(); 421 else 422 FocusPanelContent(aFocusLocation.mnIndex); 423 return true; 424 425 case PC_PanelToolBox: 426 if (nDirection < 0 && bHasToolBoxItem) 427 maPanels[aFocusLocation.mnIndex]->GetTitleBar()->GrabFocus(); 428 else 429 FocusPanelContent(aFocusLocation.mnIndex); 430 return true; 431 432 default: 433 return false; 434 } 435 } 436 437 438 439 440 bool FocusManager::MoveFocusInsideDeckTitle ( 441 const FocusLocation aFocusLocation, 442 const sal_Int32 nDirection) 443 { 444 // Note that when the title bar of the first (and only) panel is 445 // not visible then the deck title takes its place and the focus 446 // is moved between a) deck title, b) deck closer and c) content 447 // of panel 0. 448 const bool bHasToolBoxItem ( 449 mpDeckTitleBar->GetToolBox().GetItemCount() > 0); 450 switch (aFocusLocation.meComponent) 451 { 452 case PC_DeckTitle: 453 if (nDirection<0 && ! IsPanelTitleVisible(0)) 454 FocusPanelContent(0); 455 else if (bHasToolBoxItem) 456 mpDeckTitleBar->GetToolBox().GrabFocus(); 457 return true; 458 459 case PC_DeckToolBox: 460 if (nDirection>0 && ! IsPanelTitleVisible(0)) 461 FocusPanelContent(0); 462 else 463 mpDeckTitleBar->GrabFocus(); 464 return true; 465 466 default: 467 return false; 468 } 469 } 470 471 472 473 474 void FocusManager::HandleKeyEvent ( 475 const KeyCode& rKeyCode, 476 const Window& rWindow) 477 { 478 const FocusLocation aLocation (GetFocusLocation(rWindow)); 479 mpLastFocusedWindow = NULL; 480 481 switch (rKeyCode.GetCode()) 482 { 483 case KEY_SPACE: 484 switch (aLocation.meComponent) 485 { 486 case PC_PanelTitle: 487 // Toggle panel between expanded and collapsed. 488 maPanels[aLocation.mnIndex]->SetExpanded( ! maPanels[aLocation.mnIndex]->IsExpanded()); 489 break; 490 491 case PC_TabBar: 492 // Activate the button. 493 ClickButton(aLocation.mnIndex); 494 break; 495 496 default: 497 break; 498 } 499 return; 500 501 case KEY_RETURN: 502 switch (aLocation.meComponent) 503 { 504 case PC_DeckToolBox: 505 FocusButton(0); 506 break; 507 508 case PC_PanelTitle: 509 // Enter the panel. 510 FocusPanelContent(aLocation.mnIndex); 511 break; 512 513 case PC_TabBar: 514 // Activate the button. 515 ClickButton(aLocation.mnIndex); 516 break; 517 518 default: 519 break; 520 } 521 return; 522 523 case KEY_TAB: 524 { 525 const sal_Int32 nDirection ( 526 rKeyCode.IsShift() 527 ? -1 528 : +1); 529 switch (aLocation.meComponent) 530 { 531 case PC_PanelTitle: 532 case PC_PanelToolBox: 533 case PC_PanelContent: 534 MoveFocusInsidePanel(aLocation, nDirection); 535 break; 536 537 case PC_DeckTitle: 538 case PC_DeckToolBox: 539 MoveFocusInsideDeckTitle(aLocation, nDirection); 540 break; 541 542 default: 543 break; 544 } 545 break; 546 } 547 548 case KEY_LEFT: 549 case KEY_UP: 550 switch (aLocation.meComponent) 551 { 552 case PC_PanelTitle: 553 case PC_PanelToolBox: 554 case PC_PanelContent: 555 // Go to previous panel or the deck title. 556 if (aLocation.mnIndex > 0) 557 FocusPanel(aLocation.mnIndex-1, true); 558 else if (IsDeckTitleVisible()) 559 FocusDeckTitle(); 560 else 561 FocusButton(maButtons.size()-1); 562 break; 563 564 case PC_DeckTitle: 565 case PC_DeckToolBox: 566 // Focus the last button. 567 FocusButton(maButtons.size()-1); 568 break; 569 570 case PC_TabBar: 571 // Go to previous tab bar item. 572 if (aLocation.mnIndex == 0) 573 FocusPanel(maPanels.size()-1, true); 574 else 575 FocusButton((aLocation.mnIndex + maButtons.size() - 1) % maButtons.size()); 576 break; 577 578 default: 579 break; 580 } 581 break; 582 583 case KEY_RIGHT: 584 case KEY_DOWN: 585 switch(aLocation.meComponent) 586 { 587 case PC_PanelTitle: 588 case PC_PanelToolBox: 589 case PC_PanelContent: 590 // Go to next panel. 591 if (aLocation.mnIndex < static_cast<sal_Int32>(maPanels.size())-1) 592 FocusPanel(aLocation.mnIndex+1, false); 593 else 594 FocusButton(0); 595 break; 596 597 case PC_DeckTitle: 598 case PC_DeckToolBox: 599 // Focus the first panel. 600 if (IsPanelTitleVisible(0)) 601 FocusPanel(0, false); 602 else 603 FocusButton(0); 604 break; 605 606 case PC_TabBar: 607 // Go to next tab bar item. 608 if (aLocation.mnIndex < static_cast<sal_Int32>(maButtons.size())-1) 609 FocusButton(aLocation.mnIndex + 1); 610 else if (IsDeckTitleVisible()) 611 FocusDeckTitle(); 612 else 613 FocusPanel(0, true); 614 break; 615 616 default: 617 break; 618 } 619 break; 620 } 621 } 622 623 624 625 626 IMPL_LINK(FocusManager, WindowEventListener, VclSimpleEvent*, pEvent) 627 { 628 if (pEvent == NULL) 629 return 0; 630 631 if ( ! pEvent->ISA(VclWindowEvent)) 632 return 0; 633 634 VclWindowEvent* pWindowEvent = static_cast<VclWindowEvent*>(pEvent); 635 Window* pSource = pWindowEvent->GetWindow(); 636 if (pSource == NULL) 637 return 0; 638 639 switch (pWindowEvent->GetId()) 640 { 641 case VCLEVENT_WINDOW_KEYINPUT: 642 { 643 KeyEvent* pKeyEvent = static_cast<KeyEvent*>(pWindowEvent->GetData()); 644 HandleKeyEvent(pKeyEvent->GetKeyCode(), *pSource); 645 return 1; 646 } 647 648 case VCLEVENT_OBJECT_DYING: 649 RemoveWindow(*pSource); 650 return 1; 651 652 case VCLEVENT_WINDOW_GETFOCUS: 653 case VCLEVENT_WINDOW_LOSEFOCUS: 654 pSource->Invalidate(); 655 return 1; 656 657 default: 658 break; 659 } 660 661 return 0; 662 } 663 664 665 666 667 IMPL_LINK(FocusManager, ChildEventListener, VclSimpleEvent*, pEvent) 668 { 669 if (pEvent == NULL) 670 return 0; 671 672 if ( ! pEvent->ISA(VclWindowEvent)) 673 return 0; 674 675 VclWindowEvent* pWindowEvent = static_cast<VclWindowEvent*>(pEvent); 676 Window* pSource = pWindowEvent->GetWindow(); 677 if (pSource == NULL) 678 return 0; 679 680 switch (pWindowEvent->GetId()) 681 { 682 case VCLEVENT_WINDOW_KEYINPUT: 683 { 684 KeyEvent* pKeyEvent = static_cast<KeyEvent*>(pWindowEvent->GetData()); 685 686 // Go up the window hierarchy to find out whether the 687 // parent of the event source is known to us. 688 Window* pWindow = pSource; 689 FocusLocation aLocation (PC_None, -1); 690 while (true) 691 { 692 if (pWindow == NULL) 693 break; 694 aLocation = GetFocusLocation(*pWindow); 695 if (aLocation.meComponent != PC_None) 696 break; 697 pWindow = pWindow->GetParent(); 698 } 699 700 if (aLocation.meComponent != PC_None) 701 { 702 switch (pKeyEvent->GetKeyCode().GetCode()) 703 { 704 case KEY_ESCAPE: 705 // Return focus back to the panel title. 706 FocusPanel(aLocation.mnIndex, true); 707 break; 708 709 case KEY_TAB: 710 if (mpFirstFocusedContentControl!=NULL 711 && mpLastFocusedWindow == mpFirstFocusedContentControl) 712 { 713 // Move focus back to panel (or deck) 714 // title. 715 FocusPanel(aLocation.mnIndex, true); 716 } 717 break; 718 719 default: 720 break; 721 } 722 } 723 return 1; 724 } 725 726 case VCLEVENT_WINDOW_GETFOCUS: 727 // Keep track of focused controls in panel content. 728 // Remember the first focused control. When it is later 729 // focused again due to pressing the TAB key then the 730 // focus is moved to the panel or deck title. 731 mpLastFocusedWindow = pSource; 732 if (mbObservingContentControlFocus) 733 mpFirstFocusedContentControl = pSource; 734 break; 735 736 default: 737 break; 738 } 739 740 return 0; 741 } 742 743 744 } } // end of namespace sfx2::sidebar 745