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