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
ScDPFieldButton(OutputDevice * pOutDev,const StyleSettings * pStyle,const Fraction * pZoomX,const Fraction * pZoomY,ScDocument * pDoc)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
~ScDPFieldButton()79 ScDPFieldButton::~ScDPFieldButton()
80 {
81 }
82
setText(const OUString & rText)83 void ScDPFieldButton::setText(const OUString& rText)
84 {
85 maText = rText;
86 }
87
setBoundingBox(const Point & rPos,const Size & rSize,bool bLayoutRTL)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
setDrawBaseButton(bool b)99 void ScDPFieldButton::setDrawBaseButton(bool b)
100 {
101 mbBaseButton = b;
102 }
103
setDrawPopupButton(bool b)104 void ScDPFieldButton::setDrawPopupButton(bool b)
105 {
106 mbPopupButton = b;
107 }
108
setHasHiddenMember(bool b)109 void ScDPFieldButton::setHasHiddenMember(bool b)
110 {
111 mbHasHiddenMember = b;
112 }
113
setPopupPressed(bool b)114 void ScDPFieldButton::setPopupPressed(bool b)
115 {
116 mbPopupPressed = b;
117 }
118
setPopupLeft(bool b)119 void ScDPFieldButton::setPopupLeft(bool b)
120 {
121 mbPopupLeft = b;
122 }
123
draw()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
getPopupBoundingBox(Point & rPos,Size & rSize) const180 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
drawPopupButton()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
MenuItemData()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
SubMenuItemData(ScMenuFloatingWindow * pParent)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
reset()288 void ScMenuFloatingWindow::SubMenuItemData::reset()
289 {
290 mpSubMenu = NULL;
291 mnMenuPos = MENU_NOT_SELECTED;
292 maTimer.Stop();
293 }
294
IMPL_LINK(ScMenuFloatingWindow::SubMenuItemData,TimeoutHdl,void *,EMPTYARG)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
ScMenuFloatingWindow(Window * pParent,ScDocument * pDoc,sal_uInt16 nMenuStackLevel)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
~ScMenuFloatingWindow()329 ScMenuFloatingWindow::~ScMenuFloatingWindow()
330 {
331 EndPopupMode();
332 }
333
MouseMove(const MouseEvent & rMEvt)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
MouseButtonDown(const MouseEvent & rMEvt)343 void ScMenuFloatingWindow::MouseButtonDown(const MouseEvent& rMEvt)
344 {
345 const Point& rPos = rMEvt.GetPosPixel();
346 mnClickedMenu = getEnclosingMenuItem(rPos);
347 Window::MouseButtonDown(rMEvt);
348 }
349
MouseButtonUp(const MouseEvent & rMEvt)350 void ScMenuFloatingWindow::MouseButtonUp(const MouseEvent& rMEvt)
351 {
352 executeMenuItem(mnClickedMenu);
353 mnClickedMenu = MENU_NOT_SELECTED;
354 Window::MouseButtonUp(rMEvt);
355 }
356
KeyInput(const KeyEvent & rKEvt)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
Paint(const Rectangle &)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
CreateAccessible()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
addMenuItem(const OUString & rText,bool bEnabled,Action * pAction)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
addSubMenuItem(const OUString & rText,bool bEnabled)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
drawMenuItem(size_t nPos)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
drawAllMenuItems()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
getLabelFont() const517 const Font& ScMenuFloatingWindow::getLabelFont() const
518 {
519 return maLabelFont;
520 }
521
executeMenuItem(size_t nPos)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
setSelectedMenuItem(size_t nPos,bool bSubMenuTimer,bool bEnsureSubMenu)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
getSelectedMenuItem() const565 size_t ScMenuFloatingWindow::getSelectedMenuItem() const
566 {
567 return mnSelectedMenu;
568 }
569
handleMenuTimeout(SubMenuItemData * pTimer)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
queueLaunchSubMenu(size_t nPos,ScMenuFloatingWindow * pMenu)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
queueCloseSubMenu()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
launchSubMenu(bool bSetMenuPos)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
endSubMenu(ScMenuFloatingWindow * pSubMenu)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
fillMenuItemsToAccessible(ScAccessibleFilterMenu * pAccMenu) const676 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
getDoc()686 ScDocument* ScMenuFloatingWindow::getDoc()
687 {
688 return mpDoc;
689 }
690
resizeToFitMenuItems()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
selectMenuItem(size_t nPos,bool bSelected,bool bSubMenuTimer)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
clearSelectedMenuItem()744 void ScMenuFloatingWindow::clearSelectedMenuItem()
745 {
746 selectMenuItem(mnSelectedMenu, false, false);
747 mnSelectedMenu = MENU_NOT_SELECTED;
748 }
749
getSubMenuWindow(size_t nPos) const750 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
isMenuItemSelected(size_t nPos) const758 bool ScMenuFloatingWindow::isMenuItemSelected(size_t nPos) const
759 {
760 return nPos == mnSelectedMenu;
761 }
762
setName(const OUString & rName)763 void ScMenuFloatingWindow::setName(const OUString& rName)
764 {
765 maName = rName;
766 }
767
getName() const768 const OUString& ScMenuFloatingWindow::getName() const
769 {
770 return maName;
771 }
772
highlightMenuItem(size_t nPos,bool bSelected)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
getMenuItemPosSize(size_t nPos,Point & rPos,Size & rSize) const828 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
getParentMenuWindow() const844 ScMenuFloatingWindow* ScMenuFloatingWindow::getParentMenuWindow() const
845 {
846 return mpParentMenu;
847 }
848
getEnclosingMenuItem(const Point & rPos) const849 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
getSubMenuPos(ScMenuFloatingWindow * pSubMenu)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
fireMenuHighlightedEvent()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
setSubMenuFocused(ScMenuFloatingWindow * pSubMenu)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
ensureSubMenuVisible(ScMenuFloatingWindow * pSubMenu)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
ensureSubMenuNotVisible()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
terminateAllPopupMenus()946 void ScMenuFloatingWindow::terminateAllPopupMenus()
947 {
948 EndPopupMode();
949 if (mpParentMenu)
950 mpParentMenu->terminateAllPopupMenus();
951 }
952
IMPL_LINK(ScMenuFloatingWindow,PopupEndHdl,void *,EMPTYARG)953 IMPL_LINK( ScMenuFloatingWindow, PopupEndHdl, void*, EMPTYARG )
954 {
955 clearSelectedMenuItem();
956 return 0;
957 }
958
959 // ============================================================================
960
Member()961 ScDPFieldPopupWindow::Member::Member() :
962 mbVisible(true)
963 {
964 }
965
966 // ----------------------------------------------------------------------------
967
CancelButton(ScDPFieldPopupWindow * pParent)968 ScDPFieldPopupWindow::CancelButton::CancelButton(ScDPFieldPopupWindow* pParent) :
969 ::CancelButton(pParent), mpParent(pParent) {}
970
Click()971 void ScDPFieldPopupWindow::CancelButton::Click()
972 {
973 mpParent->EndPopupMode();
974 ::CancelButton::Click();
975 }
976
977 // ----------------------------------------------------------------------------
978
ScDPFieldPopupWindow(Window * pParent,ScDocument * pDoc)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
~ScDPFieldPopupWindow()1050 ScDPFieldPopupWindow::~ScDPFieldPopupWindow()
1051 {
1052 }
1053
getSectionPosSize(Point & rPos,Size & rSize,SectionType eType) const1054 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
setAllMemberState(bool bSet)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
selectCurrentMemberOnly(bool bSet)1162 void ScDPFieldPopupWindow::selectCurrentMemberOnly(bool bSet)
1163 {
1164 setAllMemberState(!bSet);
1165 sal_uInt16 nSelected = maChecks.GetSelectEntryPos();
1166 maChecks.CheckEntryPos(nSelected, bSet);
1167 }
1168
cycleFocus(bool bReverse)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
IMPL_LINK(ScDPFieldPopupWindow,ButtonHdl,Button *,pBtn)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
IMPL_LINK(ScDPFieldPopupWindow,TriStateHdl,TriStateBox *,EMPTYARG)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
IMPL_LINK(ScDPFieldPopupWindow,CheckHdl,SvTreeListBox *,pChecks)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
MouseMove(const MouseEvent & rMEvt)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
Notify(NotifyEvent & rNEvt)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
Paint(const Rectangle & rRect)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
GetPreferredKeyInputWindow()1304 Window* ScDPFieldPopupWindow::GetPreferredKeyInputWindow()
1305 {
1306 return maTabStopCtrls[mnCurTabStop];
1307 }
1308
CreateAccessible()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
setMemberSize(size_t n)1335 void ScDPFieldPopupWindow::setMemberSize(size_t n)
1336 {
1337 maMembers.reserve(n);
1338 }
1339
addMember(const OUString & rName,bool bVisible)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
initMembers()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
getWindowSize() const1378 const Size& ScDPFieldPopupWindow::getWindowSize() const
1379 {
1380 return maWndSize;
1381 }
1382
getResult(hash_map<OUString,bool,OUStringHash> & rResult)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
close(bool bOK)1396 void ScDPFieldPopupWindow::close(bool bOK)
1397 {
1398 if (bOK && mpOKAction.get())
1399 mpOKAction->execute();
1400
1401 EndPopupMode();
1402 }
1403
setExtendedData(ExtendedData * p)1404 void ScDPFieldPopupWindow::setExtendedData(ExtendedData* p)
1405 {
1406 mpExtendedData.reset(p);
1407 }
1408
getExtendedData()1409 ScDPFieldPopupWindow::ExtendedData* ScDPFieldPopupWindow::getExtendedData()
1410 {
1411 return mpExtendedData.get();
1412 }
1413
setOKAction(Action * p)1414 void ScDPFieldPopupWindow::setOKAction(Action* p)
1415 {
1416 mpOKAction.reset(p);
1417 }
1418
1419