xref: /AOO41X/main/sc/source/ui/cctrl/dpcontrol.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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