1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sc.hxx" 30 31 // INCLUDE --------------------------------------------------------------- 32 33 #include "dpcontrol.hxx" 34 #include "dpcontrol.hrc" 35 36 #include <vcl/outdev.hxx> 37 #include <vcl/settings.hxx> 38 #include <tools/wintypes.hxx> 39 #include <vcl/decoview.hxx> 40 #include "strload.hxx" 41 #include "global.hxx" 42 #include "scitems.hxx" 43 #include "document.hxx" 44 #include "docpool.hxx" 45 #include "patattr.hxx" 46 47 #include "AccessibleFilterMenu.hxx" 48 #include "AccessibleFilterTopWindow.hxx" 49 50 #include <com/sun/star/accessibility/XAccessible.hpp> 51 #include <com/sun/star/accessibility/XAccessibleContext.hpp> 52 53 using ::com::sun::star::uno::Reference; 54 using ::com::sun::star::accessibility::XAccessible; 55 using ::com::sun::star::accessibility::XAccessibleContext; 56 using ::rtl::OUString; 57 using ::rtl::OUStringHash; 58 using ::std::vector; 59 using ::std::hash_map; 60 using ::std::auto_ptr; 61 62 ScDPFieldButton::ScDPFieldButton(OutputDevice* pOutDev, const StyleSettings* pStyle, const Fraction* pZoomX, const Fraction* pZoomY, ScDocument* pDoc) : 63 mpDoc(pDoc), 64 mpOutDev(pOutDev), 65 mpStyle(pStyle), 66 mbBaseButton(true), 67 mbPopupButton(false), 68 mbHasHiddenMember(false), 69 mbPopupPressed(false), 70 mbPopupLeft(false) 71 { 72 if (pZoomX) 73 maZoomX = *pZoomX; 74 else 75 maZoomX = Fraction(1, 1); 76 77 if (pZoomY) 78 maZoomY = *pZoomY; 79 else 80 maZoomY = Fraction(1, 1); 81 } 82 83 ScDPFieldButton::~ScDPFieldButton() 84 { 85 } 86 87 void ScDPFieldButton::setText(const OUString& rText) 88 { 89 maText = rText; 90 } 91 92 void ScDPFieldButton::setBoundingBox(const Point& rPos, const Size& rSize, bool bLayoutRTL) 93 { 94 maPos = rPos; 95 maSize = rSize; 96 if (bLayoutRTL) 97 { 98 // rPos is the logical-left position, adjust maPos to visual-left (inside the cell border) 99 maPos.X() -= maSize.Width() - 1; 100 } 101 } 102 103 void ScDPFieldButton::setDrawBaseButton(bool b) 104 { 105 mbBaseButton = b; 106 } 107 108 void ScDPFieldButton::setDrawPopupButton(bool b) 109 { 110 mbPopupButton = b; 111 } 112 113 void ScDPFieldButton::setHasHiddenMember(bool b) 114 { 115 mbHasHiddenMember = b; 116 } 117 118 void ScDPFieldButton::setPopupPressed(bool b) 119 { 120 mbPopupPressed = b; 121 } 122 123 void ScDPFieldButton::setPopupLeft(bool b) 124 { 125 mbPopupLeft = b; 126 } 127 128 void ScDPFieldButton::draw() 129 { 130 const long nMargin = 2; 131 bool bOldMapEnablaed = mpOutDev->IsMapModeEnabled(); 132 mpOutDev->EnableMapMode(false); 133 134 if (mbBaseButton) 135 { 136 // Background 137 Rectangle aRect(maPos, maSize); 138 mpOutDev->SetLineColor(mpStyle->GetFaceColor()); 139 mpOutDev->SetFillColor(mpStyle->GetFaceColor()); 140 mpOutDev->DrawRect(aRect); 141 142 // Border lines 143 mpOutDev->SetLineColor(mpStyle->GetLightColor()); 144 mpOutDev->DrawLine(Point(maPos), Point(maPos.X(), maPos.Y()+maSize.Height()-1)); 145 mpOutDev->DrawLine(Point(maPos), Point(maPos.X()+maSize.Width()-1, maPos.Y())); 146 147 mpOutDev->SetLineColor(mpStyle->GetShadowColor()); 148 mpOutDev->DrawLine(Point(maPos.X(), maPos.Y()+maSize.Height()-1), 149 Point(maPos.X()+maSize.Width()-1, maPos.Y()+maSize.Height()-1)); 150 mpOutDev->DrawLine(Point(maPos.X()+maSize.Width()-1, maPos.Y()), 151 Point(maPos.X()+maSize.Width()-1, maPos.Y()+maSize.Height()-1)); 152 153 // Field name. 154 // Get the font and size the same way as in scenario selection (lcl_DrawOneFrame in gridwin4.cxx) 155 Font aTextFont( mpStyle->GetAppFont() ); 156 if ( mpDoc ) 157 { 158 // use ScPatternAttr::GetFont only for font size 159 Font aAttrFont; 160 static_cast<const ScPatternAttr&>(mpDoc->GetPool()->GetDefaultItem(ATTR_PATTERN)). 161 GetFont( aAttrFont, SC_AUTOCOL_BLACK, mpOutDev, &maZoomY ); 162 aTextFont.SetSize( aAttrFont.GetSize() ); 163 } 164 mpOutDev->SetFont(aTextFont); 165 mpOutDev->SetTextColor(mpStyle->GetButtonTextColor()); 166 167 Point aTextPos = maPos; 168 long nTHeight = mpOutDev->GetTextHeight(); 169 aTextPos.setX(maPos.getX() + nMargin); 170 aTextPos.setY(maPos.getY() + (maSize.Height()-nTHeight)/2); 171 172 mpOutDev->Push(PUSH_CLIPREGION); 173 mpOutDev->IntersectClipRegion(aRect); 174 mpOutDev->DrawText(aTextPos, maText); 175 mpOutDev->Pop(); 176 } 177 178 if (mbPopupButton) 179 drawPopupButton(); 180 181 mpOutDev->EnableMapMode(bOldMapEnablaed); 182 } 183 184 void ScDPFieldButton::getPopupBoundingBox(Point& rPos, Size& rSize) const 185 { 186 long nW = maSize.getWidth() / 2; 187 long nH = maSize.getHeight(); 188 if (nW > 18) 189 nW = 18; 190 if (nH > 18) 191 nH = 18; 192 193 // #i114944# AutoFilter button is left-aligned in RTL. 194 // DataPilot button is always right-aligned for now, so text output isn't affected. 195 if (mbPopupLeft) 196 rPos.setX(maPos.getX()); 197 else 198 rPos.setX(maPos.getX() + maSize.getWidth() - nW); 199 rPos.setY(maPos.getY() + maSize.getHeight() - nH); 200 rSize.setWidth(nW); 201 rSize.setHeight(nH); 202 } 203 204 void ScDPFieldButton::drawPopupButton() 205 { 206 Point aPos; 207 Size aSize; 208 getPopupBoundingBox(aPos, aSize); 209 210 // Background & outer black border 211 mpOutDev->SetLineColor(COL_BLACK); 212 mpOutDev->SetFillColor(mpStyle->GetFaceColor()); 213 mpOutDev->DrawRect(Rectangle(aPos, aSize)); 214 215 if (!mbPopupPressed) 216 { 217 // border lines 218 mpOutDev->SetLineColor(mpStyle->GetLightColor()); 219 mpOutDev->DrawLine(Point(aPos.X()+1, aPos.Y()+1), Point(aPos.X()+1, aPos.Y()+aSize.Height()-2)); 220 mpOutDev->DrawLine(Point(aPos.X()+1, aPos.Y()+1), Point(aPos.X()+aSize.Width()-2, aPos.Y()+1)); 221 222 mpOutDev->SetLineColor(mpStyle->GetShadowColor()); 223 mpOutDev->DrawLine(Point(aPos.X()+1, aPos.Y()+aSize.Height()-2), 224 Point(aPos.X()+aSize.Width()-2, aPos.Y()+aSize.Height()-2)); 225 mpOutDev->DrawLine(Point(aPos.X()+aSize.Width()-2, aPos.Y()+1), 226 Point(aPos.X()+aSize.Width()-2, aPos.Y()+aSize.Height()-2)); 227 } 228 229 // the arrowhead 230 Color aArrowColor = mbHasHiddenMember ? mpStyle->GetHighlightLinkColor() : mpStyle->GetButtonTextColor(); 231 mpOutDev->SetLineColor(aArrowColor); 232 mpOutDev->SetFillColor(aArrowColor); 233 Point aCenter(aPos.X() + (aSize.Width() >> 1), aPos.Y() + (aSize.Height() >> 1)); 234 Point aPos1, aPos2; 235 aPos1.X() = aCenter.X() - 4; 236 aPos2.X() = aCenter.X() + 4; 237 aPos1.Y() = aCenter.Y() - 3; 238 aPos2.Y() = aCenter.Y() - 3; 239 240 if (mbPopupPressed) 241 { 242 aPos1.X() += 1; 243 aPos2.X() += 1; 244 aPos1.Y() += 1; 245 aPos2.Y() += 1; 246 } 247 248 do 249 { 250 ++aPos1.X(); 251 --aPos2.X(); 252 ++aPos1.Y(); 253 ++aPos2.Y(); 254 mpOutDev->DrawLine(aPos1, aPos2); 255 } 256 while (aPos1 != aPos2); 257 258 if (mbHasHiddenMember) 259 { 260 // tiny little box to display in presence of hidden member(s). 261 Point aBoxPos(aPos.X() + aSize.Width() - 5, aPos.Y() + aSize.Height() - 5); 262 if (mbPopupPressed) 263 { 264 aBoxPos.X() += 1; 265 aBoxPos.Y() += 1; 266 } 267 Size aBoxSize(3, 3); 268 mpOutDev->DrawRect(Rectangle(aBoxPos, aBoxSize)); 269 } 270 } 271 272 // ============================================================================ 273 274 ScMenuFloatingWindow::MenuItemData::MenuItemData() : 275 mbEnabled(true), 276 mpAction(static_cast<ScDPFieldPopupWindow::Action*>(NULL)), 277 mpSubMenuWin(static_cast<ScMenuFloatingWindow*>(NULL)) 278 { 279 } 280 281 // ---------------------------------------------------------------------------- 282 283 ScMenuFloatingWindow::SubMenuItemData::SubMenuItemData(ScMenuFloatingWindow* pParent) : 284 mpSubMenu(NULL), 285 mnMenuPos(MENU_NOT_SELECTED), 286 mpParent(pParent) 287 { 288 maTimer.SetTimeoutHdl( LINK(this, ScMenuFloatingWindow::SubMenuItemData, TimeoutHdl) ); 289 maTimer.SetTimeout(mpParent->GetSettings().GetMouseSettings().GetMenuDelay()); 290 } 291 292 void ScMenuFloatingWindow::SubMenuItemData::reset() 293 { 294 mpSubMenu = NULL; 295 mnMenuPos = MENU_NOT_SELECTED; 296 maTimer.Stop(); 297 } 298 299 IMPL_LINK( ScMenuFloatingWindow::SubMenuItemData, TimeoutHdl, void*, EMPTYARG ) 300 { 301 mpParent->handleMenuTimeout(this); 302 return 0; 303 } 304 305 // ---------------------------------------------------------------------------- 306 307 size_t ScMenuFloatingWindow::MENU_NOT_SELECTED = 999; 308 309 ScMenuFloatingWindow::ScMenuFloatingWindow(Window* pParent, ScDocument* pDoc, sal_uInt16 nMenuStackLevel) : 310 PopupMenuFloatingWindow(pParent), 311 maOpenTimer(this), 312 maCloseTimer(this), 313 maName(OUString::createFromAscii("ScMenuFloatingWindow")), 314 mnSelectedMenu(MENU_NOT_SELECTED), 315 mnClickedMenu(MENU_NOT_SELECTED), 316 mpDoc(pDoc), 317 mpParentMenu(dynamic_cast<ScMenuFloatingWindow*>(pParent)), 318 mpActiveSubMenu(NULL) 319 { 320 SetMenuStackLevel(nMenuStackLevel); 321 322 // TODO: How do we get the right font to use here ? 323 const sal_uInt16 nPopupFontHeight = 12; 324 const StyleSettings& rStyle = GetSettings().GetStyleSettings(); 325 maLabelFont = rStyle.GetLabelFont(); 326 maLabelFont.SetHeight(nPopupFontHeight); 327 SetFont(maLabelFont); 328 329 SetText(OUString::createFromAscii("ScMenuFloatingWindow")); 330 SetPopupModeEndHdl( LINK(this, ScMenuFloatingWindow, PopupEndHdl) ); 331 } 332 333 ScMenuFloatingWindow::~ScMenuFloatingWindow() 334 { 335 EndPopupMode(); 336 } 337 338 void ScMenuFloatingWindow::MouseMove(const MouseEvent& rMEvt) 339 { 340 const Point& rPos = rMEvt.GetPosPixel(); 341 size_t nSelectedMenu = getEnclosingMenuItem(rPos); 342 setSelectedMenuItem(nSelectedMenu, true, false); 343 344 Window::MouseMove(rMEvt); 345 } 346 347 void ScMenuFloatingWindow::MouseButtonDown(const MouseEvent& rMEvt) 348 { 349 const Point& rPos = rMEvt.GetPosPixel(); 350 mnClickedMenu = getEnclosingMenuItem(rPos); 351 Window::MouseButtonDown(rMEvt); 352 } 353 354 void ScMenuFloatingWindow::MouseButtonUp(const MouseEvent& rMEvt) 355 { 356 executeMenuItem(mnClickedMenu); 357 mnClickedMenu = MENU_NOT_SELECTED; 358 Window::MouseButtonUp(rMEvt); 359 } 360 361 void ScMenuFloatingWindow::KeyInput(const KeyEvent& rKEvt) 362 { 363 const KeyCode& rKeyCode = rKEvt.GetKeyCode(); 364 bool bHandled = true; 365 size_t nSelectedMenu = mnSelectedMenu; 366 size_t nLastMenuPos = maMenuItems.size() - 1; 367 switch (rKeyCode.GetCode()) 368 { 369 case KEY_UP: 370 if (nSelectedMenu == MENU_NOT_SELECTED || nSelectedMenu == 0) 371 nSelectedMenu = nLastMenuPos; 372 else 373 --nSelectedMenu; 374 setSelectedMenuItem(nSelectedMenu, false, false); 375 break; 376 case KEY_DOWN: 377 if (nSelectedMenu == MENU_NOT_SELECTED || nSelectedMenu == nLastMenuPos) 378 nSelectedMenu = 0; 379 else 380 ++nSelectedMenu; 381 setSelectedMenuItem(nSelectedMenu, false, false); 382 break; 383 case KEY_LEFT: 384 if (mpParentMenu) 385 mpParentMenu->endSubMenu(this); 386 break; 387 case KEY_RIGHT: 388 { 389 if (mnSelectedMenu >= maMenuItems.size() || mnSelectedMenu == MENU_NOT_SELECTED) 390 break; 391 392 const MenuItemData& rMenu = maMenuItems[mnSelectedMenu]; 393 if (!rMenu.mbEnabled || !rMenu.mpSubMenuWin) 394 break; 395 396 maOpenTimer.mnMenuPos = mnSelectedMenu; 397 maOpenTimer.mpSubMenu = rMenu.mpSubMenuWin.get(); 398 launchSubMenu(true); 399 } 400 break; 401 case KEY_RETURN: 402 if (nSelectedMenu != MENU_NOT_SELECTED) 403 executeMenuItem(nSelectedMenu); 404 break; 405 default: 406 bHandled = false; 407 } 408 409 if (!bHandled) 410 Window::KeyInput(rKEvt); 411 } 412 413 void ScMenuFloatingWindow::Paint(const Rectangle& /*rRect*/) 414 { 415 const StyleSettings& rStyle = GetSettings().GetStyleSettings(); 416 Color aBackColor = rStyle.GetMenuColor(); 417 Color aBorderColor = rStyle.GetShadowColor(); 418 419 Rectangle aCtrlRect(Point(0, 0), GetOutputSizePixel()); 420 421 // Window background 422 bool bNativeDrawn = true; 423 if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_ENTIRE_CONTROL)) 424 { 425 SetClipRegion(); 426 bNativeDrawn = DrawNativeControl( 427 CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED, 428 ImplControlValue(), OUString()); 429 } 430 else 431 bNativeDrawn = false; 432 433 if (!bNativeDrawn) 434 { 435 SetFillColor(aBackColor); 436 SetLineColor(aBorderColor); 437 DrawRect(aCtrlRect); 438 } 439 440 // Menu items 441 SetTextColor(rStyle.GetMenuTextColor()); 442 drawAllMenuItems(); 443 } 444 445 Reference<XAccessible> ScMenuFloatingWindow::CreateAccessible() 446 { 447 if (!mxAccessible.is()) 448 { 449 Reference<XAccessible> xAccParent = mpParentMenu ? 450 mpParentMenu->GetAccessible() : GetAccessibleParentWindow()->GetAccessible(); 451 452 mxAccessible.set(new ScAccessibleFilterMenu(xAccParent, this, maName, 999, getDoc())); 453 ScAccessibleFilterMenu* p = static_cast<ScAccessibleFilterMenu*>( 454 mxAccessible.get()); 455 456 vector<MenuItemData>::const_iterator itr, itrBeg = maMenuItems.begin(), itrEnd = maMenuItems.end(); 457 for (itr = itrBeg; itr != itrEnd; ++itr) 458 { 459 size_t nPos = ::std::distance(itrBeg, itr); 460 p->appendMenuItem(itr->maText, itr->mbEnabled, nPos); 461 } 462 } 463 464 return mxAccessible; 465 } 466 467 void ScMenuFloatingWindow::addMenuItem(const OUString& rText, bool bEnabled, Action* pAction) 468 { 469 MenuItemData aItem; 470 aItem.maText = rText; 471 aItem.mbEnabled = bEnabled; 472 aItem.mpAction.reset(pAction); 473 maMenuItems.push_back(aItem); 474 } 475 476 ScMenuFloatingWindow* ScMenuFloatingWindow::addSubMenuItem(const OUString& rText, bool bEnabled) 477 { 478 MenuItemData aItem; 479 aItem.maText = rText; 480 aItem.mbEnabled = bEnabled; 481 aItem.mpSubMenuWin.reset(new ScMenuFloatingWindow(this, mpDoc, GetMenuStackLevel()+1)); 482 aItem.mpSubMenuWin->setName(rText); 483 maMenuItems.push_back(aItem); 484 return aItem.mpSubMenuWin.get(); 485 } 486 487 void ScMenuFloatingWindow::drawMenuItem(size_t nPos) 488 { 489 if (nPos >= maMenuItems.size()) 490 return; 491 492 Point aPos; 493 Size aSize; 494 getMenuItemPosSize(nPos, aPos, aSize); 495 496 DecorationView aDecoView(this); 497 long nXOffset = 5; 498 long nYOffset = (aSize.Height() - maLabelFont.GetHeight())/2; 499 DrawCtrlText(Point(aPos.X()+nXOffset, aPos.Y() + nYOffset), maMenuItems[nPos].maText, 0, STRING_LEN, 500 maMenuItems[nPos].mbEnabled ? TEXT_DRAW_MNEMONIC : TEXT_DRAW_DISABLE); 501 502 if (maMenuItems[nPos].mpSubMenuWin) 503 { 504 long nFontHeight = maLabelFont.GetHeight(); 505 Point aMarkerPos = aPos; 506 aMarkerPos.Y() += aSize.Height()/2 - nFontHeight/4 + 1; 507 aMarkerPos.X() += aSize.Width() - nFontHeight + nFontHeight/4; 508 Size aMarkerSize(nFontHeight/2, nFontHeight/2); 509 aDecoView.DrawSymbol(Rectangle(aMarkerPos, aMarkerSize), 510 SYMBOL_SPIN_RIGHT, GetTextColor(), 0); 511 } 512 } 513 514 void ScMenuFloatingWindow::drawAllMenuItems() 515 { 516 size_t n = maMenuItems.size(); 517 for (size_t i = 0; i < n; ++i) 518 highlightMenuItem(i, i == mnSelectedMenu); 519 } 520 521 const Font& ScMenuFloatingWindow::getLabelFont() const 522 { 523 return maLabelFont; 524 } 525 526 void ScMenuFloatingWindow::executeMenuItem(size_t nPos) 527 { 528 if (nPos >= maMenuItems.size()) 529 return; 530 531 if (!maMenuItems[nPos].mpAction) 532 // no action is defined. 533 return; 534 535 maMenuItems[nPos].mpAction->execute(); 536 terminateAllPopupMenus(); 537 } 538 539 void ScMenuFloatingWindow::setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu) 540 { 541 if (mnSelectedMenu == nPos) 542 // nothing to do. 543 return; 544 545 if (bEnsureSubMenu) 546 { 547 // Dismiss any child popup menu windows. 548 if (mnSelectedMenu < maMenuItems.size() && 549 maMenuItems[mnSelectedMenu].mpSubMenuWin && 550 maMenuItems[mnSelectedMenu].mpSubMenuWin->IsVisible()) 551 { 552 maMenuItems[mnSelectedMenu].mpSubMenuWin->ensureSubMenuNotVisible(); 553 } 554 555 // The popup is not visible, yet a menu item is selected. The request 556 // most likely comes from the accessible object. Make sure this 557 // window, as well as all its parent windows are visible. 558 if (!IsVisible() && mpParentMenu) 559 mpParentMenu->ensureSubMenuVisible(this); 560 } 561 562 selectMenuItem(mnSelectedMenu, false, bSubMenuTimer); 563 selectMenuItem(nPos, true, bSubMenuTimer); 564 mnSelectedMenu = nPos; 565 566 fireMenuHighlightedEvent(); 567 } 568 569 size_t ScMenuFloatingWindow::getSelectedMenuItem() const 570 { 571 return mnSelectedMenu; 572 } 573 574 void ScMenuFloatingWindow::handleMenuTimeout(SubMenuItemData* pTimer) 575 { 576 if (pTimer == &maOpenTimer) 577 { 578 // Close any open submenu immediately. 579 if (maCloseTimer.mpSubMenu) 580 { 581 maCloseTimer.mpSubMenu->EndPopupMode(); 582 maCloseTimer.mpSubMenu = NULL; 583 maCloseTimer.maTimer.Stop(); 584 } 585 586 launchSubMenu(false); 587 } 588 else if (pTimer == &maCloseTimer) 589 { 590 // end submenu. 591 if (maCloseTimer.mpSubMenu) 592 { 593 maOpenTimer.mpSubMenu = NULL; 594 595 maCloseTimer.mpSubMenu->EndPopupMode(); 596 maCloseTimer.mpSubMenu = NULL; 597 598 highlightMenuItem(maOpenTimer.mnMenuPos, false); 599 maOpenTimer.mnMenuPos = MENU_NOT_SELECTED; 600 } 601 } 602 } 603 604 void ScMenuFloatingWindow::queueLaunchSubMenu(size_t nPos, ScMenuFloatingWindow* pMenu) 605 { 606 if (!pMenu) 607 return; 608 609 // Set the submenu on launch queue. 610 if (maOpenTimer.mpSubMenu) 611 { 612 if (maOpenTimer.mpSubMenu == pMenu) 613 { 614 if (pMenu == maCloseTimer.mpSubMenu) 615 maCloseTimer.reset(); 616 return; 617 } 618 619 // new submenu is being requested. 620 queueCloseSubMenu(); 621 } 622 623 maOpenTimer.mpSubMenu = pMenu; 624 maOpenTimer.mnMenuPos = nPos; 625 maOpenTimer.maTimer.Start(); 626 } 627 628 void ScMenuFloatingWindow::queueCloseSubMenu() 629 { 630 if (!maOpenTimer.mpSubMenu) 631 // There is no submenu to close. 632 return; 633 634 // Stop any submenu on queue for opening. 635 maOpenTimer.maTimer.Stop(); 636 637 maCloseTimer.mpSubMenu = maOpenTimer.mpSubMenu; 638 maCloseTimer.mnMenuPos = maOpenTimer.mnMenuPos; 639 maCloseTimer.maTimer.Start(); 640 } 641 642 void ScMenuFloatingWindow::launchSubMenu(bool bSetMenuPos) 643 { 644 Point aPos; 645 Size aSize; 646 getMenuItemPosSize(maOpenTimer.mnMenuPos, aPos, aSize); 647 ScMenuFloatingWindow* pSubMenu = maOpenTimer.mpSubMenu; 648 649 if (!pSubMenu) 650 return; 651 652 sal_uInt32 nOldFlags = GetPopupModeFlags(); 653 SetPopupModeFlags(nOldFlags | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE); 654 pSubMenu->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly. 655 pSubMenu->StartPopupMode( 656 Rectangle(aPos,aSize), (FLOATWIN_POPUPMODE_RIGHT | FLOATWIN_POPUPMODE_GRABFOCUS)); 657 pSubMenu->AddPopupModeWindow(this); 658 if (bSetMenuPos) 659 pSubMenu->setSelectedMenuItem(0, false, false); // select menu item after the popup becomes fully visible. 660 SetPopupModeFlags(nOldFlags); 661 } 662 663 void ScMenuFloatingWindow::endSubMenu(ScMenuFloatingWindow* pSubMenu) 664 { 665 if (!pSubMenu) 666 return; 667 668 pSubMenu->EndPopupMode(); 669 maOpenTimer.reset(); 670 671 size_t nMenuPos = getSubMenuPos(pSubMenu); 672 if (nMenuPos != MENU_NOT_SELECTED) 673 { 674 highlightMenuItem(nMenuPos, true); 675 mnSelectedMenu = nMenuPos; 676 fireMenuHighlightedEvent(); 677 } 678 } 679 680 void ScMenuFloatingWindow::fillMenuItemsToAccessible(ScAccessibleFilterMenu* pAccMenu) const 681 { 682 vector<MenuItemData>::const_iterator itr, itrBeg = maMenuItems.begin(), itrEnd = maMenuItems.end(); 683 for (itr = itrBeg; itr != itrEnd; ++itr) 684 { 685 size_t nPos = ::std::distance(itrBeg, itr); 686 pAccMenu->appendMenuItem(itr->maText, itr->mbEnabled, nPos); 687 } 688 } 689 690 ScDocument* ScMenuFloatingWindow::getDoc() 691 { 692 return mpDoc; 693 } 694 695 void ScMenuFloatingWindow::resizeToFitMenuItems() 696 { 697 if (maMenuItems.empty()) 698 return; 699 700 vector<MenuItemData>::const_iterator itr = maMenuItems.begin(), itrEnd = maMenuItems.end(); 701 long nTextWidth = 0; 702 for (; itr != itrEnd; ++itr) 703 nTextWidth = ::std::max(GetTextWidth(itr->maText), nTextWidth); 704 705 size_t nLastPos = maMenuItems.size()-1; 706 Point aPos; 707 Size aSize; 708 getMenuItemPosSize(nLastPos, aPos, aSize); 709 aPos.X() += nTextWidth + 15; 710 aPos.Y() += aSize.Height() + 5; 711 SetOutputSizePixel(Size(aPos.X(), aPos.Y())); 712 } 713 714 void ScMenuFloatingWindow::selectMenuItem(size_t nPos, bool bSelected, bool bSubMenuTimer) 715 { 716 if (nPos >= maMenuItems.size() || nPos == MENU_NOT_SELECTED) 717 { 718 queueCloseSubMenu(); 719 return; 720 } 721 722 if (!maMenuItems[nPos].mbEnabled) 723 { 724 queueCloseSubMenu(); 725 return; 726 } 727 728 highlightMenuItem(nPos, bSelected); 729 730 if (bSelected) 731 { 732 if (mpParentMenu) 733 mpParentMenu->setSubMenuFocused(this); 734 735 if (bSubMenuTimer) 736 { 737 if (maMenuItems[nPos].mpSubMenuWin) 738 { 739 ScMenuFloatingWindow* pSubMenu = maMenuItems[nPos].mpSubMenuWin.get(); 740 queueLaunchSubMenu(nPos, pSubMenu); 741 } 742 else 743 queueCloseSubMenu(); 744 } 745 } 746 } 747 748 void ScMenuFloatingWindow::clearSelectedMenuItem() 749 { 750 selectMenuItem(mnSelectedMenu, false, false); 751 mnSelectedMenu = MENU_NOT_SELECTED; 752 } 753 754 ScMenuFloatingWindow* ScMenuFloatingWindow::getSubMenuWindow(size_t nPos) const 755 { 756 if (maMenuItems.size() <= nPos) 757 return NULL; 758 759 return maMenuItems[nPos].mpSubMenuWin.get(); 760 } 761 762 bool ScMenuFloatingWindow::isMenuItemSelected(size_t nPos) const 763 { 764 return nPos == mnSelectedMenu; 765 } 766 767 void ScMenuFloatingWindow::setName(const OUString& rName) 768 { 769 maName = rName; 770 } 771 772 const OUString& ScMenuFloatingWindow::getName() const 773 { 774 return maName; 775 } 776 777 void ScMenuFloatingWindow::highlightMenuItem(size_t nPos, bool bSelected) 778 { 779 if (nPos == MENU_NOT_SELECTED) 780 return; 781 782 const StyleSettings& rStyle = GetSettings().GetStyleSettings(); 783 Color aBackColor = rStyle.GetMenuColor(); 784 SetFillColor(aBackColor); 785 SetLineColor(aBackColor); 786 787 Point aPos; 788 Size aSize; 789 getMenuItemPosSize(nPos, aPos, aSize); 790 Rectangle aRegion(aPos,aSize); 791 792 if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_ENTIRE_CONTROL)) 793 { 794 Push(PUSH_CLIPREGION); 795 IntersectClipRegion(Rectangle(aPos, aSize)); 796 Rectangle aCtrlRect(Point(0,0), GetOutputSizePixel()); 797 DrawNativeControl( 798 CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED, 799 ImplControlValue(), OUString()); 800 801 Pop(); 802 } 803 804 bool bNativeDrawn = true; 805 if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_MENU_ITEM)) 806 { 807 ControlState nState = bSelected ? CTRL_STATE_SELECTED : 0; 808 if (maMenuItems[nPos].mbEnabled) 809 nState |= CTRL_STATE_ENABLED; 810 bNativeDrawn = DrawNativeControl( 811 CTRL_MENU_POPUP, PART_MENU_ITEM, aRegion, nState, ImplControlValue(), OUString()); 812 } 813 else 814 bNativeDrawn = false; 815 816 if (!bNativeDrawn) 817 { 818 if (bSelected) 819 { 820 aBackColor = rStyle.GetMenuHighlightColor(); 821 SetFillColor(aBackColor); 822 SetLineColor(aBackColor); 823 } 824 DrawRect(Rectangle(aPos,aSize)); 825 } 826 827 Color aTextColor = bSelected ? rStyle.GetMenuHighlightTextColor() : rStyle.GetMenuTextColor(); 828 SetTextColor(aTextColor); 829 drawMenuItem(nPos); 830 } 831 832 void ScMenuFloatingWindow::getMenuItemPosSize(size_t nPos, Point& rPos, Size& rSize) const 833 { 834 const sal_uInt16 nLeftMargin = 5; 835 const sal_uInt16 nTopMargin = 5; 836 const sal_uInt16 nMenuItemHeight = static_cast< sal_uInt16 >( maLabelFont.GetHeight()*1.8 ); 837 838 Size aWndSize = GetSizePixel(); 839 840 Point aPos1(nLeftMargin, nTopMargin); 841 Size aSize1(aWndSize.Width() - nLeftMargin*2, nMenuItemHeight); 842 843 rPos = aPos1; 844 rPos.Y() += aSize1.Height()*nPos; 845 rSize = aSize1; 846 } 847 848 ScMenuFloatingWindow* ScMenuFloatingWindow::getParentMenuWindow() const 849 { 850 return mpParentMenu; 851 } 852 853 size_t ScMenuFloatingWindow::getEnclosingMenuItem(const Point& rPos) const 854 { 855 size_t n = maMenuItems.size(); 856 for (size_t i = 0; i < n; ++i) 857 { 858 Point aPos; 859 Size aSize; 860 getMenuItemPosSize(i, aPos, aSize); 861 Rectangle aRect(aPos, aSize); 862 if (aRect.IsInside(rPos)) 863 return i; 864 } 865 return MENU_NOT_SELECTED; 866 } 867 868 size_t ScMenuFloatingWindow::getSubMenuPos(ScMenuFloatingWindow* pSubMenu) 869 { 870 size_t n = maMenuItems.size(); 871 for (size_t i = 0; i < n; ++i) 872 { 873 if (maMenuItems[i].mpSubMenuWin.get() == pSubMenu) 874 return i; 875 } 876 return MENU_NOT_SELECTED; 877 } 878 879 void ScMenuFloatingWindow::fireMenuHighlightedEvent() 880 { 881 if (mnSelectedMenu == MENU_NOT_SELECTED) 882 return; 883 884 if (!mxAccessible.is()) 885 return; 886 887 Reference<XAccessibleContext> xAccCxt = mxAccessible->getAccessibleContext(); 888 if (!xAccCxt.is()) 889 return; 890 891 Reference<XAccessible> xAccMenu = xAccCxt->getAccessibleChild(mnSelectedMenu); 892 if (!xAccMenu.is()) 893 return; 894 895 VclAccessibleEvent aEvent(VCLEVENT_MENU_HIGHLIGHT, xAccMenu); 896 FireVclEvent(&aEvent); 897 } 898 899 void ScMenuFloatingWindow::setSubMenuFocused(ScMenuFloatingWindow* pSubMenu) 900 { 901 maCloseTimer.reset(); 902 size_t nMenuPos = getSubMenuPos(pSubMenu); 903 if (mnSelectedMenu != nMenuPos) 904 { 905 highlightMenuItem(nMenuPos, true); 906 mnSelectedMenu = nMenuPos; 907 } 908 } 909 910 void ScMenuFloatingWindow::ensureSubMenuVisible(ScMenuFloatingWindow* pSubMenu) 911 { 912 if (mpParentMenu) 913 mpParentMenu->ensureSubMenuVisible(this); 914 915 if (pSubMenu->IsVisible()) 916 return; 917 918 // Find the menu position of the submenu. 919 size_t nMenuPos = getSubMenuPos(pSubMenu); 920 if (nMenuPos != MENU_NOT_SELECTED) 921 { 922 setSelectedMenuItem(nMenuPos, false, false); 923 924 Point aPos; 925 Size aSize; 926 getMenuItemPosSize(nMenuPos, aPos, aSize); 927 928 sal_uInt32 nOldFlags = GetPopupModeFlags(); 929 SetPopupModeFlags(nOldFlags | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE); 930 pSubMenu->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly. 931 pSubMenu->StartPopupMode( 932 Rectangle(aPos,aSize), (FLOATWIN_POPUPMODE_RIGHT | FLOATWIN_POPUPMODE_GRABFOCUS)); 933 pSubMenu->AddPopupModeWindow(this); 934 SetPopupModeFlags(nOldFlags); 935 } 936 } 937 938 void ScMenuFloatingWindow::ensureSubMenuNotVisible() 939 { 940 if (mnSelectedMenu <= maMenuItems.size() && 941 maMenuItems[mnSelectedMenu].mpSubMenuWin && 942 maMenuItems[mnSelectedMenu].mpSubMenuWin->IsVisible()) 943 { 944 maMenuItems[mnSelectedMenu].mpSubMenuWin->ensureSubMenuNotVisible(); 945 } 946 947 EndPopupMode(); 948 } 949 950 void ScMenuFloatingWindow::terminateAllPopupMenus() 951 { 952 EndPopupMode(); 953 if (mpParentMenu) 954 mpParentMenu->terminateAllPopupMenus(); 955 } 956 957 IMPL_LINK( ScMenuFloatingWindow, PopupEndHdl, void*, EMPTYARG ) 958 { 959 clearSelectedMenuItem(); 960 return 0; 961 } 962 963 // ============================================================================ 964 965 ScDPFieldPopupWindow::Member::Member() : 966 mbVisible(true) 967 { 968 } 969 970 // ---------------------------------------------------------------------------- 971 972 ScDPFieldPopupWindow::CancelButton::CancelButton(ScDPFieldPopupWindow* pParent) : 973 ::CancelButton(pParent), mpParent(pParent) {} 974 975 void ScDPFieldPopupWindow::CancelButton::Click() 976 { 977 mpParent->EndPopupMode(); 978 ::CancelButton::Click(); 979 } 980 981 // ---------------------------------------------------------------------------- 982 983 ScDPFieldPopupWindow::ScDPFieldPopupWindow(Window* pParent, ScDocument* pDoc) : 984 ScMenuFloatingWindow(pParent, pDoc), 985 maChecks(this, 0), 986 maChkToggleAll(this, 0), 987 maBtnSelectSingle (this, 0), 988 maBtnUnselectSingle(this, 0), 989 maBtnOk(this), 990 maBtnCancel(this), 991 mnCurTabStop(0), 992 mpExtendedData(NULL), 993 mpOKAction(NULL), 994 maWndSize(240, 330), 995 mePrevToggleAllState(STATE_DONTKNOW) 996 { 997 maTabStopCtrls.reserve(7); 998 maTabStopCtrls.push_back(this); 999 maTabStopCtrls.push_back(&maChecks); 1000 maTabStopCtrls.push_back(&maChkToggleAll); 1001 maTabStopCtrls.push_back(&maBtnSelectSingle); 1002 maTabStopCtrls.push_back(&maBtnUnselectSingle); 1003 maTabStopCtrls.push_back(&maBtnOk); 1004 maTabStopCtrls.push_back(&maBtnCancel); 1005 1006 const StyleSettings& rStyle = GetSettings().GetStyleSettings(); 1007 1008 Point aPos; 1009 Size aSize; 1010 getSectionPosSize(aPos, aSize, WHOLE); 1011 SetOutputSizePixel(aSize); 1012 Size aOutSize = GetOutputSizePixel(); 1013 1014 getSectionPosSize(aPos, aSize, BTN_OK); 1015 maBtnOk.SetPosSizePixel(aPos, aSize); 1016 maBtnOk.SetFont(getLabelFont()); 1017 maBtnOk.SetClickHdl( LINK(this, ScDPFieldPopupWindow, ButtonHdl) ); 1018 maBtnOk.Show(); 1019 1020 getSectionPosSize(aPos, aSize, BTN_CANCEL); 1021 maBtnCancel.SetPosSizePixel(aPos, aSize); 1022 maBtnCancel.SetFont(getLabelFont()); 1023 maBtnCancel.Show(); 1024 1025 getSectionPosSize(aPos, aSize, LISTBOX_AREA_INNER); 1026 maChecks.SetPosSizePixel(aPos, aSize); 1027 maChecks.SetFont(getLabelFont()); 1028 maChecks.SetCheckButtonHdl( LINK(this, ScDPFieldPopupWindow, CheckHdl) ); 1029 maChecks.Show(); 1030 1031 getSectionPosSize(aPos, aSize, CHECK_TOGGLE_ALL); 1032 maChkToggleAll.SetPosSizePixel(aPos, aSize); 1033 maChkToggleAll.SetFont(getLabelFont()); 1034 maChkToggleAll.SetText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_TOGGLE_ALL).GetString()); 1035 maChkToggleAll.SetControlBackground(rStyle.GetMenuColor()); 1036 maChkToggleAll.SetClickHdl( LINK(this, ScDPFieldPopupWindow, TriStateHdl) ); 1037 maChkToggleAll.Show(); 1038 1039 getSectionPosSize(aPos, aSize, BTN_SINGLE_SELECT); 1040 maBtnSelectSingle.SetPosSizePixel(aPos, aSize); 1041 maBtnSelectSingle.SetQuickHelpText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_SELECT_CURRENT).GetString()); 1042 maBtnSelectSingle.SetModeImage(Image(ScResId(RID_IMG_SELECT_CURRENT)), BMP_COLOR_NORMAL); 1043 maBtnSelectSingle.SetClickHdl( LINK(this, ScDPFieldPopupWindow, ButtonHdl) ); 1044 maBtnSelectSingle.Show(); 1045 1046 getSectionPosSize(aPos, aSize, BTN_SINGLE_UNSELECT); 1047 maBtnUnselectSingle.SetPosSizePixel(aPos, aSize); 1048 maBtnUnselectSingle.SetQuickHelpText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_UNSELECT_CURRENT).GetString()); 1049 maBtnUnselectSingle.SetModeImage(Image(ScResId(RID_IMG_UNSELECT_CURRENT)), BMP_COLOR_NORMAL); 1050 maBtnUnselectSingle.SetClickHdl( LINK(this, ScDPFieldPopupWindow, ButtonHdl) ); 1051 maBtnUnselectSingle.Show(); 1052 } 1053 1054 ScDPFieldPopupWindow::~ScDPFieldPopupWindow() 1055 { 1056 } 1057 1058 void ScDPFieldPopupWindow::getSectionPosSize(Point& rPos, Size& rSize, SectionType eType) const 1059 { 1060 // constant parameters. 1061 const sal_uInt16 nListBoxMargin = 5; // horizontal distance from the side of the dialog to the listbox border. 1062 const sal_uInt16 nListBoxInnerPadding = 5; 1063 const sal_uInt16 nTopMargin = 5; 1064 const sal_uInt16 nMenuHeight = 60; 1065 const sal_uInt16 nSingleItemBtnAreaHeight = 32; // height of the middle area below the list box where the single-action buttons are. 1066 const sal_uInt16 nBottomBtnAreaHeight = 50; // height of the bottom area where the OK and Cancel buttons are. 1067 const sal_uInt16 nBtnWidth = 90; 1068 const sal_uInt16 nLabelHeight = static_cast< sal_uInt16 >( getLabelFont().GetHeight() ); 1069 const sal_uInt16 nBtnHeight = nLabelHeight*2; 1070 const sal_uInt16 nBottomMargin = 10; 1071 const sal_uInt16 nMenuListMargin = 20; 1072 1073 // parameters calculated from constants. 1074 const sal_uInt16 nListBoxWidth = static_cast< sal_uInt16 >( maWndSize.Width() - nListBoxMargin*2 ); 1075 const sal_uInt16 nListBoxHeight = static_cast< sal_uInt16 >( maWndSize.Height() - nTopMargin - nMenuHeight - 1076 nMenuListMargin - nSingleItemBtnAreaHeight - nBottomBtnAreaHeight ); 1077 1078 const sal_uInt16 nSingleBtnAreaY = nTopMargin + nMenuHeight + nListBoxHeight + nMenuListMargin - 1; 1079 1080 switch (eType) 1081 { 1082 case WHOLE: 1083 { 1084 rPos = Point(0, 0); 1085 rSize = maWndSize; 1086 } 1087 break; 1088 case LISTBOX_AREA_OUTER: 1089 { 1090 rPos = Point(nListBoxMargin, nTopMargin + nMenuHeight + nMenuListMargin); 1091 rSize = Size(nListBoxWidth, nListBoxHeight); 1092 } 1093 break; 1094 case LISTBOX_AREA_INNER: 1095 { 1096 rPos = Point(nListBoxMargin, nTopMargin + nMenuHeight + nMenuListMargin); 1097 rPos.X() += nListBoxInnerPadding; 1098 rPos.Y() += nListBoxInnerPadding; 1099 1100 rSize = Size(nListBoxWidth, nListBoxHeight); 1101 rSize.Width() -= nListBoxInnerPadding*2; 1102 rSize.Height() -= nListBoxInnerPadding*2; 1103 } 1104 break; 1105 case SINGLE_BTN_AREA: 1106 { 1107 rPos = Point(nListBoxMargin, nSingleBtnAreaY); 1108 rSize = Size(nListBoxWidth, nSingleItemBtnAreaHeight); 1109 } 1110 break; 1111 case CHECK_TOGGLE_ALL: 1112 { 1113 long h = nLabelHeight*3/2; // check box height is heuristically 150% of the text height. 1114 rPos = Point(nListBoxMargin, nSingleBtnAreaY); 1115 rPos.X() += 5; 1116 rPos.Y() += (nSingleItemBtnAreaHeight - h)/2; 1117 rSize = Size(70, h); 1118 } 1119 break; 1120 case BTN_SINGLE_SELECT: 1121 { 1122 long h = 26; 1123 rPos = Point(nListBoxMargin, nSingleBtnAreaY); 1124 rPos.X() += 150; 1125 rPos.Y() += (nSingleItemBtnAreaHeight - h)/2; 1126 rSize = Size(h, h); 1127 } 1128 break; 1129 case BTN_SINGLE_UNSELECT: 1130 { 1131 long h = 26; 1132 rPos = Point(nListBoxMargin, nSingleBtnAreaY); 1133 rPos.X() += 150 + h + 10; 1134 rPos.Y() += (nSingleItemBtnAreaHeight - h)/2; 1135 rSize = Size(h, h); 1136 } 1137 break; 1138 case BTN_OK: 1139 { 1140 long x = (maWndSize.Width() - nBtnWidth*2)/3; 1141 long y = maWndSize.Height() - nBottomMargin - nBtnHeight; 1142 rPos = Point(x, y); 1143 rSize = Size(nBtnWidth, nBtnHeight); 1144 } 1145 break; 1146 case BTN_CANCEL: 1147 { 1148 long x = (maWndSize.Width() - nBtnWidth*2)/3*2 + nBtnWidth; 1149 long y = maWndSize.Height() - nBottomMargin - nBtnHeight; 1150 rPos = Point(x, y); 1151 rSize = Size(nBtnWidth, nBtnHeight); 1152 } 1153 break; 1154 default: 1155 ; 1156 } 1157 } 1158 1159 void ScDPFieldPopupWindow::setAllMemberState(bool bSet) 1160 { 1161 size_t n = maMembers.size(); 1162 for (size_t i = 0; i < n; ++i) 1163 maChecks.CheckEntryPos(static_cast< sal_uInt16 >( i ), bSet); 1164 } 1165 1166 void ScDPFieldPopupWindow::selectCurrentMemberOnly(bool bSet) 1167 { 1168 setAllMemberState(!bSet); 1169 sal_uInt16 nSelected = maChecks.GetSelectEntryPos(); 1170 maChecks.CheckEntryPos(nSelected, bSet); 1171 } 1172 1173 void ScDPFieldPopupWindow::cycleFocus(bool bReverse) 1174 { 1175 maTabStopCtrls[mnCurTabStop]->SetFakeFocus(false); 1176 maTabStopCtrls[mnCurTabStop]->LoseFocus(); 1177 if (mnCurTabStop == 0) 1178 clearSelectedMenuItem(); 1179 1180 if (bReverse) 1181 { 1182 if (mnCurTabStop > 0) 1183 --mnCurTabStop; 1184 else 1185 mnCurTabStop = maTabStopCtrls.size() - 1; 1186 } 1187 else 1188 { 1189 ++mnCurTabStop; 1190 if (mnCurTabStop >= maTabStopCtrls.size()) 1191 mnCurTabStop = 0; 1192 } 1193 maTabStopCtrls[mnCurTabStop]->SetFakeFocus(true); 1194 maTabStopCtrls[mnCurTabStop]->GrabFocus(); 1195 } 1196 1197 IMPL_LINK( ScDPFieldPopupWindow, ButtonHdl, Button*, pBtn ) 1198 { 1199 if (pBtn == &maBtnOk) 1200 close(true); 1201 else if (pBtn == &maBtnSelectSingle) 1202 { 1203 selectCurrentMemberOnly(true); 1204 CheckHdl(&maChecks); 1205 } 1206 else if (pBtn == &maBtnUnselectSingle) 1207 { 1208 selectCurrentMemberOnly(false); 1209 CheckHdl(&maChecks); 1210 } 1211 return 0; 1212 } 1213 1214 IMPL_LINK( ScDPFieldPopupWindow, TriStateHdl, TriStateBox*, EMPTYARG ) 1215 { 1216 switch (mePrevToggleAllState) 1217 { 1218 case STATE_NOCHECK: 1219 maChkToggleAll.SetState(STATE_CHECK); 1220 setAllMemberState(true); 1221 break; 1222 case STATE_CHECK: 1223 maChkToggleAll.SetState(STATE_NOCHECK); 1224 setAllMemberState(false); 1225 break; 1226 case STATE_DONTKNOW: 1227 default: 1228 maChkToggleAll.SetState(STATE_CHECK); 1229 setAllMemberState(true); 1230 break; 1231 } 1232 1233 mePrevToggleAllState = maChkToggleAll.GetState(); 1234 return 0; 1235 } 1236 1237 IMPL_LINK( ScDPFieldPopupWindow, CheckHdl, SvTreeListBox*, pChecks ) 1238 { 1239 if (pChecks != &maChecks) 1240 return 0; 1241 1242 size_t nNumChecked = maChecks.GetCheckedEntryCount(); 1243 if (nNumChecked == maMembers.size()) 1244 // all members visible 1245 maChkToggleAll.SetState(STATE_CHECK); 1246 else if (nNumChecked == 0) 1247 // no members visible 1248 maChkToggleAll.SetState(STATE_NOCHECK); 1249 else 1250 maChkToggleAll.SetState(STATE_DONTKNOW); 1251 1252 mePrevToggleAllState = maChkToggleAll.GetState(); 1253 return 0; 1254 } 1255 1256 void ScDPFieldPopupWindow::MouseMove(const MouseEvent& rMEvt) 1257 { 1258 ScMenuFloatingWindow::MouseMove(rMEvt); 1259 1260 size_t nSelectedMenu = getSelectedMenuItem(); 1261 if (nSelectedMenu == MENU_NOT_SELECTED) 1262 queueCloseSubMenu(); 1263 } 1264 1265 long ScDPFieldPopupWindow::Notify(NotifyEvent& rNEvt) 1266 { 1267 switch (rNEvt.GetType()) 1268 { 1269 case EVENT_KEYUP: 1270 { 1271 const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); 1272 const KeyCode& rCode = pKeyEvent->GetKeyCode(); 1273 bool bShift = rCode.IsShift(); 1274 if (rCode.GetCode() == KEY_TAB) 1275 { 1276 cycleFocus(bShift); 1277 return true; 1278 } 1279 } 1280 break; 1281 } 1282 return ScMenuFloatingWindow::Notify(rNEvt); 1283 } 1284 1285 void ScDPFieldPopupWindow::Paint(const Rectangle& rRect) 1286 { 1287 ScMenuFloatingWindow::Paint(rRect); 1288 1289 const StyleSettings& rStyle = GetSettings().GetStyleSettings(); 1290 Color aMemberBackColor = rStyle.GetFieldColor(); 1291 Color aBorderColor = rStyle.GetShadowColor(); 1292 1293 Point aPos; 1294 Size aSize; 1295 getSectionPosSize(aPos, aSize, LISTBOX_AREA_OUTER); 1296 1297 // Member list box background 1298 SetFillColor(aMemberBackColor); 1299 SetLineColor(aBorderColor); 1300 DrawRect(Rectangle(aPos,aSize)); 1301 1302 // Single-action button box 1303 getSectionPosSize(aPos, aSize, SINGLE_BTN_AREA); 1304 SetFillColor(rStyle.GetMenuColor()); 1305 DrawRect(Rectangle(aPos,aSize)); 1306 } 1307 1308 Window* ScDPFieldPopupWindow::GetPreferredKeyInputWindow() 1309 { 1310 return maTabStopCtrls[mnCurTabStop]; 1311 } 1312 1313 Reference<XAccessible> ScDPFieldPopupWindow::CreateAccessible() 1314 { 1315 if (!mxAccessible.is()) 1316 { 1317 mxAccessible.set(new ScAccessibleFilterTopWindow( 1318 GetAccessibleParentWindow()->GetAccessible(), this, getName(), getDoc())); 1319 ScAccessibleFilterTopWindow* pAccTop = static_cast<ScAccessibleFilterTopWindow*>(mxAccessible.get()); 1320 fillMenuItemsToAccessible(pAccTop); 1321 1322 pAccTop->setAccessibleChild( 1323 maChecks.CreateAccessible(), ScAccessibleFilterTopWindow::LISTBOX); 1324 pAccTop->setAccessibleChild( 1325 maChkToggleAll.CreateAccessible(), ScAccessibleFilterTopWindow::TOGGLE_ALL); 1326 pAccTop->setAccessibleChild( 1327 maBtnSelectSingle.CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_ON_BTN); 1328 pAccTop->setAccessibleChild( 1329 maBtnUnselectSingle.CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_OFF_BTN); 1330 pAccTop->setAccessibleChild( 1331 maBtnOk.CreateAccessible(), ScAccessibleFilterTopWindow::OK_BTN); 1332 pAccTop->setAccessibleChild( 1333 maBtnCancel.CreateAccessible(), ScAccessibleFilterTopWindow::CANCEL_BTN); 1334 } 1335 1336 return mxAccessible; 1337 } 1338 1339 void ScDPFieldPopupWindow::setMemberSize(size_t n) 1340 { 1341 maMembers.reserve(n); 1342 } 1343 1344 void ScDPFieldPopupWindow::addMember(const OUString& rName, bool bVisible) 1345 { 1346 Member aMember; 1347 aMember.maName = rName; 1348 aMember.mbVisible = bVisible; 1349 maMembers.push_back(aMember); 1350 } 1351 1352 void ScDPFieldPopupWindow::initMembers() 1353 { 1354 size_t n = maMembers.size(); 1355 size_t nVisMemCount = 0; 1356 for (size_t i = 0; i < n; ++i) 1357 { 1358 maChecks.InsertEntry(maMembers[i].maName); 1359 maChecks.CheckEntryPos(static_cast< sal_uInt16 >( i ), maMembers[i].mbVisible); 1360 if (maMembers[i].mbVisible) 1361 ++nVisMemCount; 1362 } 1363 if (nVisMemCount == n) 1364 { 1365 // all members visible 1366 maChkToggleAll.SetState(STATE_CHECK); 1367 mePrevToggleAllState = STATE_CHECK; 1368 } 1369 else if (nVisMemCount == 0) 1370 { 1371 // no members visible 1372 maChkToggleAll.SetState(STATE_NOCHECK); 1373 mePrevToggleAllState = STATE_NOCHECK; 1374 } 1375 else 1376 { 1377 maChkToggleAll.SetState(STATE_DONTKNOW); 1378 mePrevToggleAllState = STATE_DONTKNOW; 1379 } 1380 } 1381 1382 const Size& ScDPFieldPopupWindow::getWindowSize() const 1383 { 1384 return maWndSize; 1385 } 1386 1387 void ScDPFieldPopupWindow::getResult(hash_map<OUString, bool, OUStringHash>& rResult) 1388 { 1389 typedef hash_map<OUString, bool, OUStringHash> ResultMap; 1390 ResultMap aResult; 1391 size_t n = maMembers.size(); 1392 for (size_t i = 0; i < n; ++i) 1393 { 1394 bool bState = maChecks.IsChecked(static_cast< sal_uInt16 >( i )); 1395 aResult.insert(ResultMap::value_type(maMembers[i].maName, bState)); 1396 } 1397 rResult.swap(aResult); 1398 } 1399 1400 void ScDPFieldPopupWindow::close(bool bOK) 1401 { 1402 if (bOK && mpOKAction.get()) 1403 mpOKAction->execute(); 1404 1405 EndPopupMode(); 1406 } 1407 1408 void ScDPFieldPopupWindow::setExtendedData(ExtendedData* p) 1409 { 1410 mpExtendedData.reset(p); 1411 } 1412 1413 ScDPFieldPopupWindow::ExtendedData* ScDPFieldPopupWindow::getExtendedData() 1414 { 1415 return mpExtendedData.get(); 1416 } 1417 1418 void ScDPFieldPopupWindow::setOKAction(Action* p) 1419 { 1420 mpOKAction.reset(p); 1421 } 1422 1423