Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "tools/debug.hxx"
21 : #include "tools/diagnose_ex.h"
22 : #include "tools/rc.h"
23 : #include "tools/stream.hxx"
24 :
25 : #include "vcl/svapp.hxx"
26 : #include "vcl/mnemonic.hxx"
27 : #include "vcl/image.hxx"
28 : #include "vcl/event.hxx"
29 : #include "vcl/help.hxx"
30 : #include "vcl/floatwin.hxx"
31 : #include "vcl/wrkwin.hxx"
32 : #include "vcl/timer.hxx"
33 : #include "vcl/decoview.hxx"
34 : #include "vcl/bitmap.hxx"
35 : #include "vcl/menu.hxx"
36 : #include "vcl/button.hxx"
37 : #include "vcl/gradient.hxx"
38 : #include "vcl/i18nhelp.hxx"
39 : #include "vcl/taskpanelist.hxx"
40 : #include "vcl/controllayout.hxx"
41 : #include "vcl/toolbox.hxx"
42 : #include "vcl/dockingarea.hxx"
43 : #include "vcl/settings.hxx"
44 :
45 : #include "salinst.hxx"
46 : #include "svdata.hxx"
47 : #include "svids.hrc"
48 : #include "window.h"
49 : #include "salmenu.hxx"
50 : #include "salframe.hxx"
51 :
52 : #include <com/sun/star/uno/Reference.h>
53 : #include <com/sun/star/i18n/XCharacterClassification.hpp>
54 : #include <com/sun/star/lang/XComponent.hpp>
55 : #include <com/sun/star/accessibility/XAccessible.hpp>
56 : #include <com/sun/star/accessibility/AccessibleRole.hpp>
57 : #include <vcl/unowrap.hxx>
58 :
59 : #include <vcl/unohelp.hxx>
60 : #include <vcl/configsettings.hxx>
61 :
62 : #include "vcl/lazydelete.hxx"
63 :
64 : #include <map>
65 : #include <vector>
66 :
67 : namespace vcl
68 : {
69 :
70 0 : struct MenuLayoutData : public ControlLayoutData
71 : {
72 : std::vector< sal_uInt16 > m_aLineItemIds;
73 : std::vector< sal_uInt16 > m_aLineItemPositions;
74 : std::map< sal_uInt16, Rectangle > m_aVisibleItemBoundRects;
75 : };
76 :
77 : }
78 :
79 : using namespace ::com::sun::star;
80 : using namespace vcl;
81 :
82 : #define ITEMPOS_INVALID 0xFFFF
83 :
84 : #define EXTRASPACEY 2
85 : #define EXTRAITEMHEIGHT 4
86 : #define GUTTERBORDER 8
87 :
88 : // document closer
89 : #define IID_DOCUMENTCLOSE 1
90 :
91 0 : static bool ImplAccelDisabled()
92 : {
93 : // display of accelerator strings may be suppressed via configuration
94 : static int nAccelDisabled = -1;
95 :
96 0 : if( nAccelDisabled == -1 )
97 : {
98 : OUString aStr =
99 : vcl::SettingsConfigItem::get()->
100 0 : getValue( "Menu", "SuppressAccelerators" );
101 0 : nAccelDisabled = aStr.equalsIgnoreAsciiCase("true") ? 1 : 0;
102 : }
103 0 : return nAccelDisabled == 1;
104 : }
105 :
106 : struct MenuItemData
107 : {
108 : sal_uInt16 nId; // SV Id
109 : MenuItemType eType; // MenuItem-Type
110 : MenuItemBits nBits; // MenuItem-Bits
111 : Menu* pSubMenu; // Pointer to SubMenu
112 : Menu* pAutoSubMenu; // Pointer to SubMenu from Resource
113 : OUString aText; // Menu-Text
114 : OUString aHelpText; // Help-String
115 : OUString aTipHelpText; // TipHelp-String (eg, expanded filenames)
116 : OUString aCommandStr; // CommandString
117 : OUString aHelpCommandStr; // Help command string (to reference external help)
118 : OString sIdent;
119 : OString aHelpId; // Help-Id
120 : sal_uLong nUserValue; // User value
121 : Image aImage; // Image
122 : KeyCode aAccelKey; // Accelerator-Key
123 : bool bChecked; // Checked
124 : bool bEnabled; // Enabled
125 : bool bVisible; // Visible (note: this flag will not override MENU_FLAG_HIDEDISABLEDENTRIES when true)
126 : bool bIsTemporary; // Temporary inserted ('No selection possible')
127 : bool bMirrorMode;
128 : long nItemImageAngle;
129 : Size aSz; // only temporarily valid
130 : OUString aAccessibleName; // accessible name
131 : OUString aAccessibleDescription; // accessible description
132 :
133 : SalMenuItem* pSalMenuItem; // access to native menu
134 :
135 0 : MenuItemData()
136 : : nId(0)
137 : , eType(MENUITEM_DONTKNOW)
138 : , nBits(0)
139 : , pSubMenu(NULL)
140 : , pAutoSubMenu(NULL)
141 : , nUserValue(0)
142 : , bChecked(false)
143 : , bEnabled(false)
144 : , bVisible(false)
145 : , bIsTemporary(false)
146 : , bMirrorMode(false)
147 : , nItemImageAngle(0)
148 0 : , pSalMenuItem(NULL)
149 : {
150 0 : }
151 0 : MenuItemData( const OUString& rStr, const Image& rImage )
152 : : nId(0)
153 : , eType(MENUITEM_DONTKNOW)
154 : , nBits(0)
155 : , pSubMenu(NULL)
156 : , pAutoSubMenu(NULL)
157 : , aText(rStr)
158 : , nUserValue(0)
159 : , aImage(rImage)
160 : , bChecked(false)
161 : , bEnabled(false)
162 : , bVisible(false)
163 : , bIsTemporary(false)
164 : , bMirrorMode(false)
165 : , nItemImageAngle(0)
166 0 : , pSalMenuItem(NULL)
167 : {
168 0 : }
169 : ~MenuItemData();
170 0 : bool HasCheck() const
171 : {
172 0 : return bChecked || ( nBits & ( MIB_RADIOCHECK | MIB_CHECKABLE | MIB_AUTOCHECK ) );
173 : }
174 : };
175 :
176 0 : MenuItemData::~MenuItemData()
177 : {
178 0 : if( pAutoSubMenu )
179 : {
180 0 : ((PopupMenu*)pAutoSubMenu)->pRefAutoSubMenu = NULL;
181 0 : delete pAutoSubMenu;
182 0 : pAutoSubMenu = NULL;
183 : }
184 0 : if( pSalMenuItem )
185 0 : ImplGetSVData()->mpDefInst->DestroyMenuItem( pSalMenuItem );
186 0 : }
187 :
188 : class MenuItemList
189 : {
190 : private:
191 : typedef ::std::vector< MenuItemData* > MenuItemDataList_impl;
192 : MenuItemDataList_impl maItemList;
193 :
194 : uno::Reference< i18n::XCharacterClassification > xCharClass;
195 :
196 : public:
197 0 : MenuItemList() {}
198 : ~MenuItemList();
199 :
200 : MenuItemData* Insert(
201 : sal_uInt16 nId,
202 : MenuItemType eType,
203 : MenuItemBits nBits,
204 : const OUString& rStr,
205 : const Image& rImage,
206 : Menu* pMenu,
207 : size_t nPos,
208 : const OString &rIdent
209 : );
210 : void InsertSeparator(const OString &rIdent, size_t nPos);
211 : void Remove( size_t nPos );
212 :
213 : MenuItemData* GetData( sal_uInt16 nSVId, size_t& rPos ) const;
214 0 : MenuItemData* GetData( sal_uInt16 nSVId ) const
215 : {
216 : size_t nTemp;
217 0 : return GetData( nSVId, nTemp );
218 : }
219 0 : MenuItemData* GetDataFromPos( size_t nPos ) const
220 : {
221 0 : return ( nPos < maItemList.size() ) ? maItemList[ nPos ] : NULL;
222 : }
223 :
224 : MenuItemData* SearchItem(
225 : sal_Unicode cSelectChar,
226 : KeyCode aKeyCode,
227 : sal_uInt16& rPos,
228 : sal_uInt16& nDuplicates,
229 : sal_uInt16 nCurrentPos
230 : ) const;
231 : size_t GetItemCount( sal_Unicode cSelectChar ) const;
232 : size_t GetItemCount( KeyCode aKeyCode ) const;
233 0 : size_t size()
234 : {
235 0 : return maItemList.size();
236 : }
237 : };
238 :
239 0 : MenuItemList::~MenuItemList()
240 : {
241 0 : for( size_t i = 0, n = maItemList.size(); i < n; ++i )
242 0 : delete maItemList[ i ];
243 0 : }
244 :
245 0 : MenuItemData* MenuItemList::Insert(
246 : sal_uInt16 nId,
247 : MenuItemType eType,
248 : MenuItemBits nBits,
249 : const OUString& rStr,
250 : const Image& rImage,
251 : Menu* pMenu,
252 : size_t nPos,
253 : const OString &rIdent
254 : )
255 : {
256 0 : MenuItemData* pData = new MenuItemData( rStr, rImage );
257 0 : pData->nId = nId;
258 0 : pData->sIdent = rIdent;
259 0 : pData->eType = eType;
260 0 : pData->nBits = nBits;
261 0 : pData->pSubMenu = NULL;
262 0 : pData->pAutoSubMenu = NULL;
263 0 : pData->nUserValue = 0;
264 0 : pData->bChecked = false;
265 0 : pData->bEnabled = true;
266 0 : pData->bVisible = true;
267 0 : pData->bIsTemporary = false;
268 0 : pData->bMirrorMode = false;
269 0 : pData->nItemImageAngle = 0;
270 :
271 0 : SalItemParams aSalMIData;
272 0 : aSalMIData.nId = nId;
273 0 : aSalMIData.eType = eType;
274 0 : aSalMIData.nBits = nBits;
275 0 : aSalMIData.pMenu = pMenu;
276 0 : aSalMIData.aText = rStr;
277 0 : aSalMIData.aImage = rImage;
278 :
279 : // Native-support: returns NULL if not supported
280 0 : pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData );
281 :
282 0 : if( nPos < maItemList.size() ) {
283 0 : maItemList.insert( maItemList.begin() + nPos, pData );
284 : } else {
285 0 : maItemList.push_back( pData );
286 : }
287 0 : return pData;
288 : }
289 :
290 0 : void MenuItemList::InsertSeparator(const OString &rIdent, size_t nPos)
291 : {
292 0 : MenuItemData* pData = new MenuItemData;
293 0 : pData->nId = 0;
294 0 : pData->sIdent = rIdent;
295 0 : pData->eType = MENUITEM_SEPARATOR;
296 0 : pData->nBits = 0;
297 0 : pData->pSubMenu = NULL;
298 0 : pData->pAutoSubMenu = NULL;
299 0 : pData->nUserValue = 0;
300 0 : pData->bChecked = false;
301 0 : pData->bEnabled = true;
302 0 : pData->bVisible = true;
303 0 : pData->bIsTemporary = false;
304 0 : pData->bMirrorMode = false;
305 0 : pData->nItemImageAngle = 0;
306 :
307 0 : SalItemParams aSalMIData;
308 0 : aSalMIData.nId = 0;
309 0 : aSalMIData.eType = MENUITEM_SEPARATOR;
310 0 : aSalMIData.nBits = 0;
311 0 : aSalMIData.pMenu = NULL;
312 0 : aSalMIData.aText = OUString();
313 0 : aSalMIData.aImage = Image();
314 :
315 : // Native-support: returns NULL if not supported
316 0 : pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData );
317 :
318 0 : if( nPos < maItemList.size() ) {
319 0 : maItemList.insert( maItemList.begin() + nPos, pData );
320 : } else {
321 0 : maItemList.push_back( pData );
322 0 : }
323 0 : }
324 :
325 0 : void MenuItemList::Remove( size_t nPos )
326 : {
327 0 : if( nPos < maItemList.size() )
328 : {
329 0 : delete maItemList[ nPos ];
330 0 : maItemList.erase( maItemList.begin() + nPos );
331 : }
332 0 : }
333 :
334 0 : MenuItemData* MenuItemList::GetData( sal_uInt16 nSVId, size_t& rPos ) const
335 : {
336 0 : for( size_t i = 0, n = maItemList.size(); i < n; ++i )
337 : {
338 0 : if ( maItemList[ i ]->nId == nSVId )
339 : {
340 0 : rPos = i;
341 0 : return maItemList[ i ];
342 : }
343 : }
344 0 : return NULL;
345 : }
346 :
347 0 : MenuItemData* MenuItemList::SearchItem(
348 : sal_Unicode cSelectChar,
349 : KeyCode aKeyCode,
350 : sal_uInt16& rPos,
351 : sal_uInt16& nDuplicates,
352 : sal_uInt16 nCurrentPos
353 : ) const
354 : {
355 0 : const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
356 :
357 0 : size_t nListCount = maItemList.size();
358 :
359 : // try character code first
360 0 : nDuplicates = GetItemCount( cSelectChar ); // return number of duplicates
361 0 : if( nDuplicates )
362 : {
363 0 : for ( rPos = 0; rPos < nListCount; rPos++)
364 : {
365 0 : MenuItemData* pData = maItemList[ rPos ];
366 0 : if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
367 : {
368 0 : if( nDuplicates > 1 && rPos == nCurrentPos )
369 0 : continue; // select next entry with the same mnemonic
370 : else
371 0 : return pData;
372 : }
373 : }
374 : }
375 :
376 : // nothing found, try keycode instead
377 0 : nDuplicates = GetItemCount( aKeyCode ); // return number of duplicates
378 :
379 0 : if( nDuplicates )
380 : {
381 0 : char ascii = 0;
382 0 : if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
383 0 : ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
384 :
385 0 : for ( rPos = 0; rPos < nListCount; rPos++)
386 : {
387 0 : MenuItemData* pData = maItemList[ rPos ];
388 0 : if ( pData->bEnabled )
389 : {
390 0 : sal_Int32 n = pData->aText.indexOf('~');
391 0 : if ( n != -1 )
392 : {
393 0 : KeyCode mnKeyCode;
394 0 : sal_Unicode mnUnicode = pData->aText[n+1];
395 0 : Window* pDefWindow = ImplGetDefaultWindow();
396 0 : if( ( pDefWindow
397 0 : && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( mnUnicode,
398 0 : Application::GetSettings().GetUILanguageTag().getLanguageType(), mnKeyCode )
399 0 : && aKeyCode.GetCode() == mnKeyCode.GetCode()
400 : )
401 0 : || ( ascii
402 0 : && rI18nHelper.MatchMnemonic( pData->aText, ascii )
403 : )
404 : )
405 : {
406 0 : if( nDuplicates > 1 && rPos == nCurrentPos )
407 0 : continue; // select next entry with the same mnemonic
408 : else
409 0 : return pData;
410 : }
411 : }
412 : }
413 : }
414 : }
415 :
416 0 : return NULL;
417 : }
418 :
419 0 : size_t MenuItemList::GetItemCount( sal_Unicode cSelectChar ) const
420 : {
421 : // returns number of entries with same mnemonic
422 0 : const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
423 :
424 0 : size_t nItems = 0;
425 0 : for ( size_t nPos = maItemList.size(); nPos; )
426 : {
427 0 : MenuItemData* pData = maItemList[ --nPos ];
428 0 : if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
429 0 : nItems++;
430 : }
431 :
432 0 : return nItems;
433 : }
434 :
435 0 : size_t MenuItemList::GetItemCount( KeyCode aKeyCode ) const
436 : {
437 : // returns number of entries with same mnemonic
438 : // uses key codes instead of character codes
439 0 : const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
440 0 : char ascii = 0;
441 0 : if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
442 0 : ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
443 :
444 0 : size_t nItems = 0;
445 0 : for ( size_t nPos = maItemList.size(); nPos; )
446 : {
447 0 : MenuItemData* pData = maItemList[ --nPos ];
448 0 : if ( pData->bEnabled )
449 : {
450 0 : sal_Int32 n = pData->aText.indexOf('~');
451 0 : if (n != -1)
452 : {
453 0 : KeyCode mnKeyCode;
454 : // if MapUnicodeToKeyCode fails or is unsupported we try the pure ascii mapping of the keycodes
455 : // so we have working shortcuts when ascii mnemonics are used
456 0 : Window* pDefWindow = ImplGetDefaultWindow();
457 0 : if( ( pDefWindow
458 0 : && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( pData->aText[n+1],
459 0 : Application::GetSettings().GetUILanguageTag().getLanguageType(), mnKeyCode )
460 0 : && aKeyCode.GetCode() == mnKeyCode.GetCode()
461 : )
462 0 : || ( ascii
463 0 : && rI18nHelper.MatchMnemonic( pData->aText, ascii )
464 : )
465 : )
466 0 : nItems++;
467 : }
468 : }
469 : }
470 :
471 0 : return nItems;
472 : }
473 :
474 : // - MenuFloatingWindow -
475 :
476 : class MenuFloatingWindow : public FloatingWindow
477 : {
478 : friend void Menu::ImplFillLayoutData() const;
479 : friend Menu::~Menu();
480 :
481 : private:
482 : Menu* pMenu;
483 : PopupMenu* pActivePopup;
484 : Timer aHighlightChangedTimer;
485 : Timer aSubmenuCloseTimer;
486 : Timer aScrollTimer;
487 : sal_uLong nSaveFocusId;
488 : sal_uInt16 nHighlightedItem; // highlighted/selected Item
489 : sal_uInt16 nMBDownPos;
490 : sal_uInt16 nScrollerHeight;
491 : sal_uInt16 nFirstEntry;
492 : sal_uInt16 nBorder;
493 : sal_uInt16 nPosInParent;
494 : bool bInExecute;
495 :
496 : bool bScrollMenu;
497 : bool bScrollUp;
498 : bool bScrollDown;
499 : bool bIgnoreFirstMove;
500 : bool bKeyInput;
501 :
502 : DECL_LINK(PopupEnd, void *);
503 : DECL_LINK( HighlightChanged, Timer* );
504 : DECL_LINK(SubmenuClose, void *);
505 : DECL_LINK(AutoScroll, void *);
506 : DECL_LINK( ShowHideListener, VclWindowEvent* );
507 :
508 : void StateChanged( StateChangedType nType ) SAL_OVERRIDE;
509 : void DataChanged( const DataChangedEvent& rDCEvt ) SAL_OVERRIDE;
510 : protected:
511 : Region ImplCalcClipRegion( bool bIncludeLogo = true ) const;
512 : void ImplInitClipRegion();
513 : void ImplDrawScroller( bool bUp );
514 : using Window::ImplScroll;
515 : void ImplScroll( const Point& rMousePos );
516 : void ImplScroll( bool bUp );
517 : void ImplCursorUpDown( bool bUp, bool bHomeEnd = false );
518 : void ImplHighlightItem( const MouseEvent& rMEvt, bool bMBDown );
519 : long ImplGetStartY() const;
520 : Rectangle ImplGetItemRect( sal_uInt16 nPos );
521 :
522 : public:
523 : MenuFloatingWindow( Menu* pMenu, Window* pParent, WinBits nStyle );
524 : virtual ~MenuFloatingWindow();
525 :
526 : void doShutdown();
527 :
528 : virtual void MouseMove( const MouseEvent& rMEvt ) SAL_OVERRIDE;
529 : virtual void MouseButtonDown( const MouseEvent& rMEvt ) SAL_OVERRIDE;
530 : virtual void MouseButtonUp( const MouseEvent& rMEvt ) SAL_OVERRIDE;
531 : virtual void KeyInput( const KeyEvent& rKEvent ) SAL_OVERRIDE;
532 : virtual void Command( const CommandEvent& rCEvt ) SAL_OVERRIDE;
533 : virtual void Paint( const Rectangle& rRect ) SAL_OVERRIDE;
534 : virtual void RequestHelp( const HelpEvent& rHEvt ) SAL_OVERRIDE;
535 : virtual void Resize() SAL_OVERRIDE;
536 :
537 0 : void SetFocusId( sal_uLong nId ) { nSaveFocusId = nId; }
538 0 : sal_uLong GetFocusId() const { return nSaveFocusId; }
539 :
540 : void EnableScrollMenu( bool b );
541 0 : bool IsScrollMenu() const { return bScrollMenu; }
542 0 : sal_uInt16 GetScrollerHeight() const { return nScrollerHeight; }
543 :
544 : void Execute();
545 : void StopExecute( sal_uLong nFocusId = 0 );
546 : void EndExecute();
547 : void EndExecute( sal_uInt16 nSelectId );
548 :
549 0 : PopupMenu* GetActivePopup() const { return pActivePopup; }
550 : void KillActivePopup( PopupMenu* pThisOnly = NULL );
551 :
552 : void HighlightItem( sal_uInt16 nPos, bool bHighlight );
553 : void ChangeHighlightItem( sal_uInt16 n, bool bStartPopupTimer );
554 0 : sal_uInt16 GetHighlightedItem() const { return nHighlightedItem; }
555 :
556 0 : void SetPosInParent( sal_uInt16 nPos ) { nPosInParent = nPos; }
557 :
558 : virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible() SAL_OVERRIDE;
559 : };
560 :
561 : // To get the transparent mouse-over look, the closer is actually a toolbox
562 : // overload DataChange to handle style changes correctly
563 0 : class DecoToolBox : public ToolBox
564 : {
565 : long lastSize;
566 : Size maMinSize;
567 :
568 : using Window::ImplInit;
569 : public:
570 : DecoToolBox( Window* pParent, WinBits nStyle = 0 );
571 : void ImplInit();
572 :
573 : void DataChanged( const DataChangedEvent& rDCEvt ) SAL_OVERRIDE;
574 :
575 : void SetImages( long nMaxHeight = 0, bool bForce = false );
576 :
577 : void calcMinSize();
578 : Size getMinSize();
579 :
580 : Image maImage;
581 : };
582 :
583 0 : DecoToolBox::DecoToolBox( Window* pParent, WinBits nStyle ) :
584 0 : ToolBox( pParent, nStyle )
585 : {
586 0 : ImplInit();
587 0 : }
588 :
589 0 : void DecoToolBox::ImplInit()
590 : {
591 0 : lastSize = -1;
592 0 : calcMinSize();
593 0 : }
594 :
595 0 : void DecoToolBox::DataChanged( const DataChangedEvent& rDCEvt )
596 : {
597 0 : Window::DataChanged( rDCEvt );
598 :
599 0 : if ( rDCEvt.GetFlags() & SETTINGS_STYLE )
600 : {
601 0 : calcMinSize();
602 0 : SetBackground();
603 0 : SetImages( 0, true);
604 : }
605 0 : }
606 :
607 0 : void DecoToolBox::calcMinSize()
608 : {
609 0 : ToolBox aTbx( GetParent() );
610 0 : if( GetItemCount() == 0 )
611 : {
612 0 : ResMgr* pResMgr = ImplGetResMgr();
613 :
614 0 : Bitmap aBitmap;
615 0 : if( pResMgr )
616 0 : aBitmap = Bitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) );
617 0 : aTbx.InsertItem( IID_DOCUMENTCLOSE, Image( aBitmap ) );
618 : }
619 : else
620 : {
621 0 : sal_uInt16 nItems = GetItemCount();
622 0 : for( sal_uInt16 i = 0; i < nItems; i++ )
623 : {
624 0 : sal_uInt16 nId = GetItemId( i );
625 0 : aTbx.InsertItem( nId, GetItemImage( nId ) );
626 : }
627 : }
628 0 : aTbx.SetOutStyle( TOOLBOX_STYLE_FLAT );
629 0 : maMinSize = aTbx.CalcWindowSizePixel();
630 0 : }
631 :
632 0 : Size DecoToolBox::getMinSize()
633 : {
634 0 : return maMinSize;
635 : }
636 :
637 0 : void DecoToolBox::SetImages( long nMaxHeight, bool bForce )
638 : {
639 0 : long border = getMinSize().Height() - maImage.GetSizePixel().Height();
640 :
641 0 : if( !nMaxHeight && lastSize != -1 )
642 0 : nMaxHeight = lastSize + border; // don't change anything if called with 0
643 :
644 0 : if( nMaxHeight < getMinSize().Height() )
645 0 : nMaxHeight = getMinSize().Height();
646 :
647 0 : if( (lastSize != nMaxHeight - border) || bForce )
648 : {
649 0 : lastSize = nMaxHeight - border;
650 :
651 0 : Color aEraseColor( 255, 255, 255, 255 );
652 0 : BitmapEx aBmpExDst( maImage.GetBitmapEx() );
653 0 : BitmapEx aBmpExSrc( aBmpExDst );
654 :
655 0 : aEraseColor.SetTransparency( 255 );
656 0 : aBmpExDst.Erase( aEraseColor );
657 0 : aBmpExDst.SetSizePixel( Size( lastSize, lastSize ) );
658 :
659 0 : Rectangle aSrcRect( Point(0,0), maImage.GetSizePixel() );
660 0 : Rectangle aDestRect( Point((lastSize - maImage.GetSizePixel().Width())/2,
661 0 : (lastSize - maImage.GetSizePixel().Height())/2 ),
662 0 : maImage.GetSizePixel() );
663 :
664 0 : aBmpExDst.CopyPixel( aDestRect, aSrcRect, &aBmpExSrc );
665 0 : SetItemImage( IID_DOCUMENTCLOSE, Image( aBmpExDst ) );
666 : }
667 0 : }
668 :
669 : // a basic class for both (due to pActivePopup, Timer,...) would be nice,
670 : // but a container class should have been created then, as they
671 : // would be derived from different windows
672 : // In most functions we would have to create exceptions for
673 : // menubar, popupmenu, hence we made two classes
674 :
675 : class MenuBarWindow : public Window
676 : {
677 : friend class MenuBar;
678 : friend class Menu;
679 :
680 : private:
681 : struct AddButtonEntry
682 : {
683 : sal_uInt16 m_nId;
684 : Link m_aSelectLink;
685 : Link m_aHighlightLink;
686 :
687 0 : AddButtonEntry() : m_nId( 0 ) {}
688 : };
689 :
690 : Menu* pMenu;
691 : PopupMenu* pActivePopup;
692 : sal_uInt16 nHighlightedItem;
693 : sal_uInt16 nRolloveredItem;
694 : sal_uLong nSaveFocusId;
695 : bool mbAutoPopup;
696 : bool bIgnoreFirstMove;
697 : bool bStayActive;
698 :
699 : DecoToolBox aCloser;
700 : PushButton aFloatBtn;
701 : PushButton aHideBtn;
702 :
703 : std::map< sal_uInt16, AddButtonEntry > m_aAddButtons;
704 :
705 : void HighlightItem( sal_uInt16 nPos, bool bHighlight );
706 : void ChangeHighlightItem( sal_uInt16 n, bool bSelectPopupEntry, bool bAllowRestoreFocus = true, bool bDefaultToDocument = true );
707 :
708 : sal_uInt16 ImplFindEntry( const Point& rMousePos ) const;
709 : void ImplCreatePopup( bool bPreSelectFirst );
710 : bool ImplHandleKeyEvent( const KeyEvent& rKEvent, bool bFromMenu = true );
711 : Rectangle ImplGetItemRect( sal_uInt16 nPos );
712 :
713 : void ImplInitStyleSettings();
714 :
715 : DECL_LINK(CloserHdl, void *);
716 : DECL_LINK(FloatHdl, void *);
717 : DECL_LINK(HideHdl, void *);
718 : DECL_LINK( ToolboxEventHdl, VclWindowEvent* );
719 : DECL_LINK( ShowHideListener, VclWindowEvent* );
720 :
721 : void StateChanged( StateChangedType nType ) SAL_OVERRIDE;
722 : void DataChanged( const DataChangedEvent& rDCEvt ) SAL_OVERRIDE;
723 : void LoseFocus() SAL_OVERRIDE;
724 : void GetFocus() SAL_OVERRIDE;
725 :
726 : public:
727 : MenuBarWindow( Window* pParent );
728 : virtual ~MenuBarWindow();
729 :
730 : void ShowButtons( bool bClose, bool bFloat, bool bHide );
731 :
732 : virtual void MouseMove( const MouseEvent& rMEvt ) SAL_OVERRIDE;
733 : virtual void MouseButtonDown( const MouseEvent& rMEvt ) SAL_OVERRIDE;
734 : virtual void MouseButtonUp( const MouseEvent& rMEvt ) SAL_OVERRIDE;
735 : virtual void KeyInput( const KeyEvent& rKEvent ) SAL_OVERRIDE;
736 : virtual void Paint( const Rectangle& rRect ) SAL_OVERRIDE;
737 : virtual void Resize() SAL_OVERRIDE;
738 : virtual void RequestHelp( const HelpEvent& rHEvt ) SAL_OVERRIDE;
739 :
740 0 : void SetFocusId( sal_uLong nId ) { nSaveFocusId = nId; }
741 0 : sal_uLong GetFocusId() const { return nSaveFocusId; }
742 :
743 : void SetMenu( MenuBar* pMenu );
744 : void KillActivePopup();
745 : void PopupClosed( Menu* pMenu );
746 0 : sal_uInt16 GetHighlightedItem() const { return nHighlightedItem; }
747 : virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible() SAL_OVERRIDE;
748 :
749 0 : void SetAutoPopup( bool bAuto ) { mbAutoPopup = bAuto; }
750 : void ImplLayoutChanged();
751 : Size MinCloseButtonSize();
752 :
753 : // add an arbitrary button to the menubar (will appear next to closer)
754 : sal_uInt16 AddMenuBarButton( const Image&, const Link&, const OUString&, sal_uInt16 nPos );
755 : void SetMenuBarButtonHighlightHdl( sal_uInt16 nId, const Link& );
756 : Rectangle GetMenuBarButtonRectPixel( sal_uInt16 nId );
757 : void RemoveMenuBarButton( sal_uInt16 nId );
758 : bool HandleMenuButtonEvent( sal_uInt16 i_nButtonId );
759 : };
760 :
761 0 : static void ImplAddNWFSeparator( Window *pThis, const MenubarValue& rMenubarValue )
762 : {
763 : // add a separator if
764 : // - we have an adjacent docking area
765 : // - and if toolbars would draw them as well (mbDockingAreaSeparateTB must not be set, see dockingarea.cxx)
766 0 : if( rMenubarValue.maTopDockingAreaHeight && !ImplGetSVData()->maNWFData.mbDockingAreaSeparateTB && !ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames )
767 : {
768 : // note: the menubar only provides the upper (dark) half of it, the rest (bright part) is drawn by the docking area
769 :
770 0 : pThis->SetLineColor( pThis->GetSettings().GetStyleSettings().GetSeparatorColor() );
771 0 : Point aPt;
772 0 : Rectangle aRect( aPt, pThis->GetOutputSizePixel() );
773 0 : pThis->DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
774 : }
775 0 : }
776 :
777 0 : static void ImplSetMenuItemData( MenuItemData* pData )
778 : {
779 : // convert data
780 0 : if ( !pData->aImage )
781 0 : pData->eType = MENUITEM_STRING;
782 0 : else if ( pData->aText.isEmpty() )
783 0 : pData->eType = MENUITEM_IMAGE;
784 : else
785 0 : pData->eType = MENUITEM_STRINGIMAGE;
786 0 : }
787 :
788 0 : static sal_uLong ImplChangeTipTimeout( sal_uLong nTimeout, Window *pWindow )
789 : {
790 0 : AllSettings aAllSettings( pWindow->GetSettings() );
791 0 : HelpSettings aHelpSettings( aAllSettings.GetHelpSettings() );
792 0 : sal_uLong nRet = aHelpSettings.GetTipTimeout();
793 0 : aHelpSettings.SetTipTimeout( nTimeout );
794 0 : aAllSettings.SetHelpSettings( aHelpSettings );
795 0 : pWindow->SetSettings( aAllSettings );
796 0 : return nRet;
797 : }
798 :
799 0 : static bool ImplHandleHelpEvent( Window* pMenuWindow, Menu* pMenu, sal_uInt16 nHighlightedItem, const HelpEvent& rHEvt, const Rectangle &rHighlightRect )
800 : {
801 0 : if( ! pMenu )
802 0 : return false;
803 :
804 0 : bool bDone = false;
805 0 : sal_uInt16 nId = 0;
806 :
807 0 : if ( nHighlightedItem != ITEMPOS_INVALID )
808 : {
809 0 : MenuItemData* pItemData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
810 0 : if ( pItemData )
811 0 : nId = pItemData->nId;
812 : }
813 :
814 0 : if ( ( rHEvt.GetMode() & HELPMODE_BALLOON ) && pMenuWindow )
815 : {
816 0 : Point aPos;
817 0 : if( rHEvt.KeyboardActivated() )
818 0 : aPos = rHighlightRect.Center();
819 : else
820 0 : aPos = rHEvt.GetMousePosPixel();
821 :
822 0 : Rectangle aRect( aPos, Size() );
823 0 : if (!pMenu->GetHelpText(nId).isEmpty())
824 0 : Help::ShowBalloon( pMenuWindow, aPos, pMenu->GetHelpText( nId ) );
825 : else
826 : {
827 : // give user a chance to read the full filename
828 0 : sal_uLong oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow );
829 : // call always, even when strlen==0 to correctly remove tip
830 0 : Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) );
831 0 : ImplChangeTipTimeout( oldTimeout, pMenuWindow );
832 : }
833 0 : bDone = true;
834 : }
835 0 : else if ( ( rHEvt.GetMode() & HELPMODE_QUICK ) && pMenuWindow )
836 : {
837 0 : Point aPos = rHEvt.GetMousePosPixel();
838 0 : Rectangle aRect( aPos, Size() );
839 : // give user a chance to read the full filename
840 0 : sal_uLong oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow );
841 : // call always, even when strlen==0 to correctly remove tip
842 0 : Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) );
843 0 : ImplChangeTipTimeout( oldTimeout, pMenuWindow );
844 0 : bDone = true;
845 : }
846 0 : else if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
847 : {
848 : // is help in the application selected
849 0 : Help* pHelp = Application::GetHelp();
850 0 : if ( pHelp )
851 : {
852 : // is an id available, then call help with the id, otherwise
853 : // use help-index
854 0 : OUString aCommand = pMenu->GetItemCommand( nId );
855 0 : OString aHelpId( pMenu->GetHelpId( nId ) );
856 0 : if( aHelpId.isEmpty() )
857 0 : aHelpId = OOO_HELP_INDEX;
858 :
859 0 : if ( !aCommand.isEmpty() )
860 0 : pHelp->Start( aCommand, NULL );
861 : else
862 0 : pHelp->Start( OStringToOUString( aHelpId, RTL_TEXTENCODING_UTF8 ), NULL );
863 : }
864 0 : bDone = true;
865 : }
866 0 : return bDone;
867 : }
868 :
869 0 : static int ImplGetTopDockingAreaHeight( Window *pWindow )
870 : {
871 : // find docking area that is top aligned and return its height
872 : // note: dockingareas are direct children of the SystemWindow
873 0 : if( pWindow->ImplGetFrameWindow() )
874 : {
875 0 : Window *pWin = pWindow->ImplGetFrameWindow()->GetWindow( WINDOW_FIRSTCHILD ); //mpWindowImpl->mpFirstChild;
876 0 : while( pWin )
877 : {
878 0 : if( pWin->IsSystemWindow() )
879 : {
880 0 : Window *pChildWin = pWin->GetWindow( WINDOW_FIRSTCHILD ); //mpWindowImpl->mpFirstChild;
881 0 : while( pChildWin )
882 : {
883 0 : DockingAreaWindow *pDockingArea = NULL;
884 0 : if ( pChildWin->GetType() == WINDOW_DOCKINGAREA )
885 0 : pDockingArea = static_cast< DockingAreaWindow* >( pChildWin );
886 :
887 0 : if( pDockingArea && pDockingArea->GetAlign() == WINDOWALIGN_TOP &&
888 0 : pDockingArea->IsVisible() && pDockingArea->GetOutputSizePixel().Height() != 0 )
889 : {
890 0 : return pDockingArea->GetOutputSizePixel().Height();
891 : }
892 :
893 0 : pChildWin = pChildWin->GetWindow( WINDOW_NEXT ); //mpWindowImpl->mpNext;
894 : }
895 :
896 : }
897 :
898 0 : pWin = pWin->GetWindow( WINDOW_NEXT ); //mpWindowImpl->mpNext;
899 : }
900 : }
901 0 : return 0;
902 : }
903 :
904 0 : Menu::Menu()
905 : {
906 0 : bIsMenuBar = false;
907 0 : ImplInit();
908 0 : }
909 :
910 : // this constructor makes sure we're creating the native menu
911 : // with the correct type (ie, MenuBar vs. PopupMenu)
912 0 : Menu::Menu( bool bMenubar )
913 : {
914 0 : bIsMenuBar = bMenubar;
915 0 : ImplInit();
916 0 : }
917 :
918 0 : Menu::~Menu()
919 : {
920 :
921 0 : vcl::LazyDeletor<Menu>::Undelete( this );
922 :
923 0 : ImplCallEventListeners( VCLEVENT_OBJECT_DYING, ITEMPOS_INVALID );
924 :
925 : // at the window free the reference to the accessible component
926 : // and make sure the MenuFloatingWindow knows about our destruction
927 0 : if ( pWindow )
928 : {
929 0 : MenuFloatingWindow* pFloat = (MenuFloatingWindow*)pWindow;
930 0 : if( pFloat->pMenu == this )
931 0 : pFloat->pMenu = NULL;
932 0 : pWindow->SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() );
933 : }
934 :
935 : // dispose accessible components
936 0 : if ( mxAccessible.is() )
937 : {
938 0 : ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent> xComponent( mxAccessible, ::com::sun::star::uno::UNO_QUERY );
939 0 : if ( xComponent.is() )
940 0 : xComponent->dispose();
941 : }
942 :
943 0 : if ( nEventId )
944 0 : Application::RemoveUserEvent( nEventId );
945 :
946 : // Notify deletion of this menu
947 0 : ImplMenuDelData* pDelData = mpFirstDel;
948 0 : while ( pDelData )
949 : {
950 0 : pDelData->mpMenu = NULL;
951 0 : pDelData = pDelData->mpNext;
952 : }
953 :
954 0 : bKilled = true;
955 :
956 0 : delete pItemList;
957 0 : delete pLogo;
958 0 : delete mpLayoutData;
959 :
960 : // Native-support: destroy SalMenu
961 0 : ImplSetSalMenu( NULL );
962 0 : }
963 :
964 0 : void Menu::ImplInit()
965 : {
966 0 : mnHighlightedItemPos = ITEMPOS_INVALID;
967 0 : mpSalMenu = NULL;
968 0 : nMenuFlags = 0;
969 0 : nDefaultItem = 0;
970 : //bIsMenuBar = false; // this is now set in the ctor, must not be changed here!!!
971 0 : nSelectedId = 0;
972 0 : pItemList = new MenuItemList;
973 0 : pLogo = NULL;
974 0 : pStartedFrom = NULL;
975 0 : pWindow = NULL;
976 0 : nEventId = 0;
977 0 : bCanceled = false;
978 0 : bInCallback = false;
979 0 : bKilled = false;
980 0 : mpLayoutData = NULL;
981 0 : mpFirstDel = NULL; // Dtor notification list
982 : // Native-support: returns NULL if not supported
983 0 : mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu( bIsMenuBar, this );
984 0 : }
985 :
986 0 : void Menu::ImplLoadRes( const ResId& rResId )
987 : {
988 0 : ResMgr* pMgr = rResId.GetResMgr();
989 0 : if( ! pMgr )
990 0 : return;
991 :
992 0 : rResId.SetRT( RSC_MENU );
993 0 : GetRes( rResId );
994 :
995 0 : sal_uLong nObjMask = ReadLongRes();
996 :
997 0 : if( nObjMask & RSC_MENU_ITEMS )
998 : {
999 0 : sal_uLong nObjFollows = ReadLongRes();
1000 : // insert menu items
1001 0 : for( sal_uLong i = 0; i < nObjFollows; i++ )
1002 : {
1003 0 : InsertItem( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
1004 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
1005 : }
1006 : }
1007 :
1008 0 : if( nObjMask & RSC_MENU_TEXT )
1009 : {
1010 0 : if( bIsMenuBar ) // no title in menubar
1011 0 : ReadStringRes();
1012 : else
1013 0 : aTitleText = ReadStringRes();
1014 : }
1015 0 : if( nObjMask & RSC_MENU_DEFAULTITEMID )
1016 0 : SetDefaultItem( sal::static_int_cast<sal_uInt16>(ReadLongRes()) );
1017 : }
1018 :
1019 0 : void Menu::CreateAutoMnemonics()
1020 : {
1021 0 : MnemonicGenerator aMnemonicGenerator;
1022 : size_t n;
1023 0 : for ( n = 0; n < pItemList->size(); n++ )
1024 : {
1025 0 : MenuItemData* pData = pItemList->GetDataFromPos( n );
1026 0 : if ( ! (pData->nBits & MIB_NOSELECT ) )
1027 0 : aMnemonicGenerator.RegisterMnemonic( pData->aText );
1028 : }
1029 0 : for ( n = 0; n < pItemList->size(); n++ )
1030 : {
1031 0 : MenuItemData* pData = pItemList->GetDataFromPos( n );
1032 0 : if ( ! (pData->nBits & MIB_NOSELECT ) )
1033 0 : pData->aText = aMnemonicGenerator.CreateMnemonic( pData->aText );
1034 0 : }
1035 0 : }
1036 :
1037 0 : void Menu::Activate()
1038 : {
1039 0 : bInCallback = true;
1040 :
1041 0 : ImplMenuDelData aDelData( this );
1042 :
1043 0 : ImplCallEventListeners( VCLEVENT_MENU_ACTIVATE, ITEMPOS_INVALID );
1044 :
1045 0 : if( !aDelData.isDeleted() )
1046 : {
1047 0 : if ( !aActivateHdl.Call( this ) )
1048 : {
1049 0 : if( !aDelData.isDeleted() )
1050 : {
1051 0 : Menu* pStartMenu = ImplGetStartMenu();
1052 0 : if ( pStartMenu && ( pStartMenu != this ) )
1053 : {
1054 0 : pStartMenu->bInCallback = true;
1055 : // MT 11/01: Call EventListener here? I don't know...
1056 0 : pStartMenu->aActivateHdl.Call( this );
1057 0 : pStartMenu->bInCallback = false;
1058 : }
1059 : }
1060 : }
1061 0 : bInCallback = false;
1062 0 : }
1063 0 : }
1064 :
1065 0 : void Menu::Deactivate()
1066 : {
1067 0 : for ( size_t n = pItemList->size(); n; )
1068 : {
1069 0 : MenuItemData* pData = pItemList->GetDataFromPos( --n );
1070 0 : if ( pData->bIsTemporary )
1071 0 : pItemList->Remove( n );
1072 : }
1073 :
1074 0 : bInCallback = true;
1075 :
1076 0 : ImplMenuDelData aDelData( this );
1077 :
1078 0 : Menu* pStartMenu = ImplGetStartMenu();
1079 0 : ImplCallEventListeners( VCLEVENT_MENU_DEACTIVATE, ITEMPOS_INVALID );
1080 :
1081 0 : if( !aDelData.isDeleted() )
1082 : {
1083 0 : if ( !aDeactivateHdl.Call( this ) )
1084 : {
1085 0 : if( !aDelData.isDeleted() )
1086 : {
1087 0 : if ( pStartMenu && ( pStartMenu != this ) )
1088 : {
1089 0 : pStartMenu->bInCallback = true;
1090 0 : pStartMenu->aDeactivateHdl.Call( this );
1091 0 : pStartMenu->bInCallback = false;
1092 : }
1093 : }
1094 : }
1095 : }
1096 :
1097 0 : if( !aDelData.isDeleted() )
1098 : {
1099 0 : bInCallback = false;
1100 0 : }
1101 0 : }
1102 :
1103 0 : void Menu::Highlight()
1104 : {
1105 0 : ImplMenuDelData aDelData( this );
1106 :
1107 0 : Menu* pStartMenu = ImplGetStartMenu();
1108 0 : if ( !aHighlightHdl.Call( this ) && !aDelData.isDeleted() )
1109 : {
1110 0 : if ( pStartMenu && ( pStartMenu != this ) )
1111 0 : pStartMenu->aHighlightHdl.Call( this );
1112 0 : }
1113 0 : }
1114 :
1115 0 : void Menu::ImplSelect()
1116 : {
1117 0 : MenuItemData* pData = GetItemList()->GetData( nSelectedId );
1118 0 : if ( pData && (pData->nBits & MIB_AUTOCHECK) )
1119 : {
1120 0 : bool bChecked = IsItemChecked( nSelectedId );
1121 0 : if ( pData->nBits & MIB_RADIOCHECK )
1122 : {
1123 0 : if ( !bChecked )
1124 0 : CheckItem( nSelectedId, true );
1125 : }
1126 : else
1127 0 : CheckItem( nSelectedId, !bChecked );
1128 : }
1129 :
1130 : // call select
1131 0 : ImplSVData* pSVData = ImplGetSVData();
1132 0 : pSVData->maAppData.mpActivePopupMenu = NULL; // if new execute in select()
1133 0 : Application::PostUserEvent( nEventId, LINK( this, Menu, ImplCallSelect ) );
1134 0 : }
1135 :
1136 0 : void Menu::Select()
1137 : {
1138 0 : ImplMenuDelData aDelData( this );
1139 :
1140 0 : ImplCallEventListeners( VCLEVENT_MENU_SELECT, GetItemPos( GetCurItemId() ) );
1141 0 : if ( !aDelData.isDeleted() && !aSelectHdl.Call( this ) )
1142 : {
1143 0 : if( !aDelData.isDeleted() )
1144 : {
1145 0 : Menu* pStartMenu = ImplGetStartMenu();
1146 0 : if ( pStartMenu && ( pStartMenu != this ) )
1147 : {
1148 0 : pStartMenu->nSelectedId = nSelectedId;
1149 0 : pStartMenu->aSelectHdl.Call( this );
1150 : }
1151 : }
1152 0 : }
1153 0 : }
1154 :
1155 : #if defined(MACOSX)
1156 : void Menu::ImplSelectWithStart( Menu* pSMenu )
1157 : {
1158 : Menu* pOldStartedFrom = pStartedFrom;
1159 : pStartedFrom = pSMenu;
1160 : Menu* pOldStartedStarted = pOldStartedFrom ? pOldStartedFrom->pStartedFrom : NULL;
1161 : Select();
1162 : if( pOldStartedFrom )
1163 : pOldStartedFrom->pStartedFrom = pOldStartedStarted;
1164 : pStartedFrom = pOldStartedFrom;
1165 : }
1166 : #endif
1167 :
1168 0 : void Menu::RequestHelp( const HelpEvent& )
1169 : {
1170 0 : }
1171 :
1172 0 : void Menu::ImplCallEventListeners( sal_uLong nEvent, sal_uInt16 nPos )
1173 : {
1174 0 : ImplMenuDelData aDelData( this );
1175 :
1176 0 : VclMenuEvent aEvent( this, nEvent, nPos );
1177 :
1178 : // This is needed by atk accessibility bridge
1179 0 : if ( nEvent == VCLEVENT_MENU_HIGHLIGHT )
1180 : {
1181 0 : ImplGetSVData()->mpApp->ImplCallEventListeners( &aEvent );
1182 : }
1183 :
1184 0 : if ( !aDelData.isDeleted() )
1185 0 : maEventListeners.Call( &aEvent );
1186 :
1187 0 : if( !aDelData.isDeleted() )
1188 : {
1189 0 : Menu* pMenu = this;
1190 0 : while ( pMenu )
1191 : {
1192 0 : maChildEventListeners.Call( &aEvent );
1193 :
1194 0 : if( aDelData.isDeleted() )
1195 0 : break;
1196 :
1197 0 : pMenu = ( pMenu->pStartedFrom != pMenu ) ? pMenu->pStartedFrom : NULL;
1198 : }
1199 0 : }
1200 0 : }
1201 :
1202 0 : void Menu::AddEventListener( const Link& rEventListener )
1203 : {
1204 0 : maEventListeners.addListener( rEventListener );
1205 0 : }
1206 :
1207 0 : void Menu::RemoveEventListener( const Link& rEventListener )
1208 : {
1209 0 : maEventListeners.removeListener( rEventListener );
1210 0 : }
1211 :
1212 0 : void Menu::InsertItem(sal_uInt16 nItemId, const OUString& rStr, MenuItemBits nItemBits,
1213 : const OString &rIdent, sal_uInt16 nPos)
1214 : {
1215 : DBG_ASSERT( nItemId, "Menu::InsertItem(): ItemId == 0" );
1216 : DBG_ASSERT( GetItemPos( nItemId ) == MENU_ITEM_NOTFOUND,
1217 : "Menu::InsertItem(): ItemId already exists" );
1218 :
1219 : // if Position > ItemCount, append
1220 0 : if ( nPos >= pItemList->size() )
1221 0 : nPos = MENU_APPEND;
1222 :
1223 : // put Item in MenuItemList
1224 : MenuItemData* pData = pItemList->Insert(nItemId, MENUITEM_STRING,
1225 0 : nItemBits, rStr, Image(), this, nPos, rIdent);
1226 :
1227 : // update native menu
1228 0 : if( ImplGetSalMenu() && pData->pSalMenuItem )
1229 0 : ImplGetSalMenu()->InsertItem( pData->pSalMenuItem, nPos );
1230 :
1231 0 : Window* pWin = ImplGetWindow();
1232 0 : delete mpLayoutData, mpLayoutData = NULL;
1233 0 : if ( pWin )
1234 : {
1235 0 : ImplCalcSize( pWin );
1236 0 : if ( pWin->IsVisible() )
1237 0 : pWin->Invalidate();
1238 : }
1239 0 : ImplCallEventListeners( VCLEVENT_MENU_INSERTITEM, nPos );
1240 0 : }
1241 :
1242 0 : void Menu::InsertItem(sal_uInt16 nItemId, const Image& rImage,
1243 : MenuItemBits nItemBits, const OString &rIdent, sal_uInt16 nPos)
1244 : {
1245 0 : InsertItem(nItemId, OUString(), nItemBits, rIdent, nPos);
1246 0 : SetItemImage( nItemId, rImage );
1247 0 : }
1248 :
1249 0 : void Menu::InsertItem(sal_uInt16 nItemId, const OUString& rStr,
1250 : const Image& rImage, MenuItemBits nItemBits,
1251 : const OString &rIdent, sal_uInt16 nPos)
1252 : {
1253 0 : InsertItem(nItemId, rStr, nItemBits, rIdent, nPos);
1254 0 : SetItemImage( nItemId, rImage );
1255 0 : }
1256 :
1257 0 : void Menu::InsertItem( const ResId& rResId, sal_uInt16 nPos )
1258 : {
1259 0 : ResMgr* pMgr = rResId.GetResMgr();
1260 0 : if( ! pMgr )
1261 0 : return;
1262 :
1263 : sal_uLong nObjMask;
1264 :
1265 0 : GetRes( rResId.SetRT( RSC_MENUITEM ) );
1266 0 : nObjMask = ReadLongRes();
1267 :
1268 0 : bool bSep = false;
1269 0 : if ( nObjMask & RSC_MENUITEM_SEPARATOR )
1270 0 : bSep = ReadShortRes() != 0;
1271 :
1272 0 : sal_uInt16 nItemId = 1;
1273 0 : if ( nObjMask & RSC_MENUITEM_ID )
1274 0 : nItemId = sal::static_int_cast<sal_uInt16>(ReadLongRes());
1275 :
1276 0 : MenuItemBits nStatus = 0;
1277 0 : if ( nObjMask & RSC_MENUITEM_STATUS )
1278 0 : nStatus = sal::static_int_cast<MenuItemBits>(ReadLongRes());
1279 :
1280 0 : OUString aText;
1281 0 : if ( nObjMask & RSC_MENUITEM_TEXT )
1282 0 : aText = ReadStringRes();
1283 :
1284 : // create item
1285 0 : if ( nObjMask & RSC_MENUITEM_BITMAP )
1286 : {
1287 0 : if ( !bSep )
1288 : {
1289 0 : Bitmap aBmp( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
1290 0 : Image const aImg(aBmp);
1291 0 : if ( !aText.isEmpty() )
1292 0 : InsertItem( nItemId, aText, aImg, nStatus, OString(), nPos );
1293 : else
1294 0 : InsertItem( nItemId, aImg, nStatus, OString(), nPos );
1295 : }
1296 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
1297 : }
1298 0 : else if ( !bSep )
1299 0 : InsertItem(nItemId, aText, nStatus, OString(), nPos);
1300 0 : if ( bSep )
1301 0 : InsertSeparator(OString(), nPos);
1302 :
1303 0 : OUString aHelpText;
1304 0 : if ( nObjMask & RSC_MENUITEM_HELPTEXT )
1305 : {
1306 0 : aHelpText = ReadStringRes();
1307 0 : if( !bSep )
1308 0 : SetHelpText( nItemId, aHelpText );
1309 : }
1310 :
1311 0 : if ( nObjMask & RSC_MENUITEM_HELPID )
1312 : {
1313 0 : OString aHelpId( ReadByteStringRes() );
1314 0 : if ( !bSep )
1315 0 : SetHelpId( nItemId, aHelpId );
1316 : }
1317 :
1318 0 : if( !bSep )
1319 0 : SetHelpText( nItemId, aHelpText );
1320 :
1321 0 : if ( nObjMask & RSC_MENUITEM_KEYCODE )
1322 : {
1323 0 : if ( !bSep )
1324 0 : SetAccelKey( nItemId, KeyCode( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) ) );
1325 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
1326 : }
1327 0 : if( nObjMask & RSC_MENUITEM_CHECKED )
1328 : {
1329 0 : if ( !bSep )
1330 0 : CheckItem( nItemId, ReadShortRes() != 0 );
1331 : }
1332 0 : if ( nObjMask & RSC_MENUITEM_DISABLE )
1333 : {
1334 0 : if ( !bSep )
1335 0 : EnableItem( nItemId, ReadShortRes() == 0 );
1336 : }
1337 0 : if ( nObjMask & RSC_MENUITEM_COMMAND )
1338 : {
1339 0 : OUString aCommandStr = ReadStringRes();
1340 0 : if ( !bSep )
1341 0 : SetItemCommand( nItemId, aCommandStr );
1342 : }
1343 0 : if ( nObjMask & RSC_MENUITEM_MENU )
1344 : {
1345 0 : if ( !bSep )
1346 : {
1347 0 : MenuItemData* pData = GetItemList()->GetData( nItemId );
1348 0 : if ( pData )
1349 : {
1350 0 : PopupMenu* pSubMenu = new PopupMenu( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
1351 0 : pData->pAutoSubMenu = pSubMenu;
1352 : // #111060# keep track of this pointer, may be it will be deleted from outside
1353 0 : pSubMenu->pRefAutoSubMenu = &pData->pAutoSubMenu;
1354 0 : SetPopupMenu( nItemId, pSubMenu );
1355 : }
1356 : }
1357 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
1358 : }
1359 0 : delete mpLayoutData, mpLayoutData = NULL;
1360 : }
1361 :
1362 0 : void Menu::InsertSeparator(const OString &rIdent, sal_uInt16 nPos)
1363 : {
1364 : // do nothing if it's a menu bar
1365 0 : if ( bIsMenuBar )
1366 0 : return;
1367 :
1368 : // if position > ItemCount, append
1369 0 : if ( nPos >= pItemList->size() )
1370 0 : nPos = MENU_APPEND;
1371 :
1372 : // put separator in item list
1373 0 : pItemList->InsertSeparator(rIdent, nPos);
1374 :
1375 : // update native menu
1376 0 : size_t itemPos = ( nPos != MENU_APPEND ) ? nPos : pItemList->size() - 1;
1377 0 : MenuItemData *pData = pItemList->GetDataFromPos( itemPos );
1378 0 : if( ImplGetSalMenu() && pData && pData->pSalMenuItem )
1379 0 : ImplGetSalMenu()->InsertItem( pData->pSalMenuItem, nPos );
1380 :
1381 0 : delete mpLayoutData, mpLayoutData = NULL;
1382 :
1383 0 : ImplCallEventListeners( VCLEVENT_MENU_INSERTITEM, nPos );
1384 : }
1385 :
1386 0 : void Menu::RemoveItem( sal_uInt16 nPos )
1387 : {
1388 0 : bool bRemove = false;
1389 :
1390 0 : if ( nPos < GetItemCount() )
1391 : {
1392 : // update native menu
1393 0 : if( ImplGetSalMenu() )
1394 0 : ImplGetSalMenu()->RemoveItem( nPos );
1395 :
1396 0 : pItemList->Remove( nPos );
1397 0 : bRemove = true;
1398 : }
1399 :
1400 0 : Window* pWin = ImplGetWindow();
1401 0 : if ( pWin )
1402 : {
1403 0 : ImplCalcSize( pWin );
1404 0 : if ( pWin->IsVisible() )
1405 0 : pWin->Invalidate();
1406 : }
1407 0 : delete mpLayoutData, mpLayoutData = NULL;
1408 :
1409 0 : if ( bRemove )
1410 0 : ImplCallEventListeners( VCLEVENT_MENU_REMOVEITEM, nPos );
1411 0 : }
1412 :
1413 0 : void ImplCopyItem( Menu* pThis, const Menu& rMenu, sal_uInt16 nPos, sal_uInt16 nNewPos,
1414 : sal_uInt16 nMode = 0 )
1415 : {
1416 0 : MenuItemType eType = rMenu.GetItemType( nPos );
1417 :
1418 0 : if ( eType == MENUITEM_DONTKNOW )
1419 0 : return;
1420 :
1421 0 : if ( eType == MENUITEM_SEPARATOR )
1422 0 : pThis->InsertSeparator( OString(), nNewPos );
1423 : else
1424 : {
1425 0 : sal_uInt16 nId = rMenu.GetItemId( nPos );
1426 :
1427 : DBG_ASSERT( pThis->GetItemPos( nId ) == MENU_ITEM_NOTFOUND,
1428 : "Menu::CopyItem(): ItemId already exists" );
1429 :
1430 0 : MenuItemData* pData = rMenu.GetItemList()->GetData( nId );
1431 :
1432 0 : if (!pData)
1433 0 : return;
1434 :
1435 0 : if ( eType == MENUITEM_STRINGIMAGE )
1436 0 : pThis->InsertItem( nId, pData->aText, pData->aImage, pData->nBits, pData->sIdent, nNewPos );
1437 0 : else if ( eType == MENUITEM_STRING )
1438 0 : pThis->InsertItem( nId, pData->aText, pData->nBits, pData->sIdent, nNewPos );
1439 : else
1440 0 : pThis->InsertItem( nId, pData->aImage, pData->nBits, pData->sIdent, nNewPos );
1441 :
1442 0 : if ( rMenu.IsItemChecked( nId ) )
1443 0 : pThis->CheckItem( nId, true );
1444 0 : if ( !rMenu.IsItemEnabled( nId ) )
1445 0 : pThis->EnableItem( nId, false );
1446 0 : pThis->SetHelpId( nId, pData->aHelpId );
1447 0 : pThis->SetHelpText( nId, pData->aHelpText );
1448 0 : pThis->SetAccelKey( nId, pData->aAccelKey );
1449 0 : pThis->SetItemCommand( nId, pData->aCommandStr );
1450 0 : pThis->SetHelpCommand( nId, pData->aHelpCommandStr );
1451 :
1452 0 : PopupMenu* pSubMenu = rMenu.GetPopupMenu( nId );
1453 0 : if ( pSubMenu )
1454 : {
1455 : // create auto-copy
1456 0 : if ( nMode == 1 )
1457 : {
1458 0 : PopupMenu* pNewMenu = new PopupMenu( *pSubMenu );
1459 0 : pThis->SetPopupMenu( nId, pNewMenu );
1460 : }
1461 : else
1462 0 : pThis->SetPopupMenu( nId, pSubMenu );
1463 : }
1464 : }
1465 : }
1466 :
1467 0 : void Menu::CopyItem( const Menu& rMenu, sal_uInt16 nPos, sal_uInt16 nNewPos )
1468 : {
1469 0 : ImplCopyItem( this, rMenu, nPos, nNewPos );
1470 0 : }
1471 :
1472 0 : void Menu::Clear()
1473 : {
1474 0 : for ( sal_uInt16 i = GetItemCount(); i; i-- )
1475 0 : RemoveItem( 0 );
1476 0 : }
1477 :
1478 0 : sal_uInt16 Menu::GetItemCount() const
1479 : {
1480 0 : return (sal_uInt16)pItemList->size();
1481 : }
1482 :
1483 0 : sal_uInt16 Menu::ImplGetVisibleItemCount() const
1484 : {
1485 0 : sal_uInt16 nItems = 0;
1486 0 : for ( size_t n = pItemList->size(); n; )
1487 : {
1488 0 : if ( ImplIsVisible( --n ) )
1489 0 : nItems++;
1490 : }
1491 0 : return nItems;
1492 : }
1493 :
1494 0 : sal_uInt16 Menu::ImplGetFirstVisible() const
1495 : {
1496 0 : for ( size_t n = 0; n < pItemList->size(); n++ )
1497 : {
1498 0 : if ( ImplIsVisible( n ) )
1499 0 : return n;
1500 : }
1501 0 : return ITEMPOS_INVALID;
1502 : }
1503 :
1504 0 : sal_uInt16 Menu::ImplGetPrevVisible( sal_uInt16 nPos ) const
1505 : {
1506 0 : for ( size_t n = nPos; n; )
1507 : {
1508 0 : if ( n && ImplIsVisible( --n ) )
1509 0 : return n;
1510 : }
1511 0 : return ITEMPOS_INVALID;
1512 : }
1513 :
1514 0 : sal_uInt16 Menu::ImplGetNextVisible( sal_uInt16 nPos ) const
1515 : {
1516 0 : for ( size_t n = nPos+1; n < pItemList->size(); n++ )
1517 : {
1518 0 : if ( ImplIsVisible( n ) )
1519 0 : return n;
1520 : }
1521 0 : return ITEMPOS_INVALID;
1522 : }
1523 :
1524 0 : sal_uInt16 Menu::GetItemId(sal_uInt16 nPos) const
1525 : {
1526 0 : MenuItemData* pData = pItemList->GetDataFromPos( nPos );
1527 :
1528 0 : if ( pData )
1529 0 : return pData->nId;
1530 : else
1531 0 : return 0;
1532 : }
1533 :
1534 0 : sal_uInt16 Menu::GetItemId(const OString &rIdent) const
1535 : {
1536 0 : for (size_t n = 0; n < pItemList->size(); ++n)
1537 : {
1538 0 : MenuItemData* pData = pItemList->GetDataFromPos(n);
1539 0 : if (pData && pData->sIdent == rIdent)
1540 0 : return pData->nId;
1541 : }
1542 0 : return MENU_ITEM_NOTFOUND;
1543 : }
1544 :
1545 0 : sal_uInt16 Menu::GetItemPos( sal_uInt16 nItemId ) const
1546 : {
1547 : size_t nPos;
1548 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1549 :
1550 0 : if ( pData )
1551 0 : return (sal_uInt16)nPos;
1552 : else
1553 0 : return MENU_ITEM_NOTFOUND;
1554 : }
1555 :
1556 0 : MenuItemType Menu::GetItemType( sal_uInt16 nPos ) const
1557 : {
1558 0 : MenuItemData* pData = pItemList->GetDataFromPos( nPos );
1559 :
1560 0 : if ( pData )
1561 0 : return pData->eType;
1562 : else
1563 0 : return MENUITEM_DONTKNOW;
1564 : }
1565 :
1566 0 : void Menu::SetHighlightItem( sal_uInt16 nItem )
1567 : {
1568 0 : nHighlightedItem = nItem;
1569 0 : }
1570 :
1571 0 : sal_uInt16 Menu::GetCurItemId() const
1572 : {
1573 0 : return nSelectedId;
1574 : }
1575 :
1576 0 : OString Menu::GetCurItemIdent() const
1577 : {
1578 0 : const MenuItemData* pData = pItemList->GetData(nSelectedId);
1579 0 : return pData ? pData->sIdent : OString();
1580 : }
1581 :
1582 0 : OString Menu::GetItemIdent(sal_uInt16 nId) const
1583 : {
1584 0 : const MenuItemData* pData = pItemList->GetData(nId);
1585 0 : return pData ? pData->sIdent : OString();
1586 : }
1587 :
1588 0 : void Menu::SetItemBits( sal_uInt16 nItemId, MenuItemBits nBits )
1589 : {
1590 0 : MenuItemData* pData = pItemList->GetData( nItemId );
1591 0 : if ( pData )
1592 0 : pData->nBits = nBits;
1593 0 : }
1594 :
1595 0 : MenuItemBits Menu::GetItemBits( sal_uInt16 nItemId ) const
1596 : {
1597 0 : MenuItemBits nBits = 0;
1598 0 : MenuItemData* pData = pItemList->GetData( nItemId );
1599 0 : if ( pData )
1600 0 : nBits = pData->nBits;
1601 0 : return nBits;
1602 : }
1603 :
1604 0 : void Menu::SetUserValue( sal_uInt16 nItemId, sal_uLong nValue )
1605 : {
1606 0 : MenuItemData* pData = pItemList->GetData( nItemId );
1607 0 : if ( pData )
1608 0 : pData->nUserValue = nValue;
1609 0 : }
1610 :
1611 0 : sal_uLong Menu::GetUserValue( sal_uInt16 nItemId ) const
1612 : {
1613 0 : MenuItemData* pData = pItemList->GetData( nItemId );
1614 0 : return pData ? pData->nUserValue : 0;
1615 : }
1616 :
1617 0 : void Menu::SetPopupMenu( sal_uInt16 nItemId, PopupMenu* pMenu )
1618 : {
1619 : size_t nPos;
1620 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1621 :
1622 : // Item does not exist -> return NULL
1623 0 : if ( !pData )
1624 0 : return;
1625 :
1626 : // same menu, nothing to do
1627 0 : if ( (PopupMenu*)pData->pSubMenu == pMenu )
1628 0 : return;
1629 :
1630 : // data exchange
1631 0 : pData->pSubMenu = pMenu;
1632 :
1633 : // #112023# Make sure pStartedFrom does not point to invalid (old) data
1634 0 : if ( pData->pSubMenu )
1635 0 : pData->pSubMenu->pStartedFrom = 0;
1636 :
1637 : // set native submenu
1638 0 : if( ImplGetSalMenu() && pData->pSalMenuItem )
1639 : {
1640 0 : if( pMenu )
1641 0 : ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, pMenu->ImplGetSalMenu(), nPos );
1642 : else
1643 0 : ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, NULL, nPos );
1644 : }
1645 :
1646 0 : ImplCallEventListeners( VCLEVENT_MENU_SUBMENUCHANGED, nPos );
1647 : }
1648 :
1649 0 : PopupMenu* Menu::GetPopupMenu( sal_uInt16 nItemId ) const
1650 : {
1651 0 : MenuItemData* pData = pItemList->GetData( nItemId );
1652 :
1653 0 : if ( pData )
1654 0 : return (PopupMenu*)(pData->pSubMenu);
1655 : else
1656 0 : return NULL;
1657 : }
1658 :
1659 0 : void Menu::SetAccelKey( sal_uInt16 nItemId, const KeyCode& rKeyCode )
1660 : {
1661 : size_t nPos;
1662 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1663 :
1664 0 : if ( !pData )
1665 0 : return;
1666 :
1667 0 : if ( pData->aAccelKey == rKeyCode )
1668 0 : return;
1669 :
1670 0 : pData->aAccelKey = rKeyCode;
1671 :
1672 : // update native menu
1673 0 : if( ImplGetSalMenu() && pData->pSalMenuItem )
1674 0 : ImplGetSalMenu()->SetAccelerator( nPos, pData->pSalMenuItem, rKeyCode, rKeyCode.GetName() );
1675 : }
1676 :
1677 0 : KeyCode Menu::GetAccelKey( sal_uInt16 nItemId ) const
1678 : {
1679 0 : MenuItemData* pData = pItemList->GetData( nItemId );
1680 :
1681 0 : if ( pData )
1682 0 : return pData->aAccelKey;
1683 : else
1684 0 : return KeyCode();
1685 : }
1686 :
1687 0 : KeyEvent Menu::GetActivationKey( sal_uInt16 nItemId ) const
1688 : {
1689 0 : KeyEvent aRet;
1690 0 : MenuItemData* pData = pItemList->GetData( nItemId );
1691 0 : if( pData )
1692 : {
1693 0 : sal_Int32 nPos = pData->aText.indexOf( '~' );
1694 0 : if( nPos != -1 && nPos < pData->aText.getLength()-1 )
1695 : {
1696 0 : sal_uInt16 nCode = 0;
1697 0 : sal_Unicode cAccel = pData->aText[nPos+1];
1698 0 : if( cAccel >= 'a' && cAccel <= 'z' )
1699 0 : nCode = KEY_A + (cAccel-'a');
1700 0 : else if( cAccel >= 'A' && cAccel <= 'Z' )
1701 0 : nCode = KEY_A + (cAccel-'A');
1702 0 : else if( cAccel >= '0' && cAccel <= '9' )
1703 0 : nCode = KEY_0 + (cAccel-'0');
1704 0 : if(nCode )
1705 0 : aRet = KeyEvent( cAccel, KeyCode( nCode, KEY_MOD2 ) );
1706 : }
1707 :
1708 : }
1709 0 : return aRet;
1710 : }
1711 :
1712 0 : void Menu::CheckItem( sal_uInt16 nItemId, bool bCheck )
1713 : {
1714 : size_t nPos;
1715 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1716 :
1717 0 : if ( !pData || pData->bChecked == bCheck )
1718 0 : return;
1719 :
1720 : // if radio-check, then uncheck previous
1721 0 : if ( bCheck && (pData->nBits & MIB_AUTOCHECK) &&
1722 0 : (pData->nBits & MIB_RADIOCHECK) )
1723 : {
1724 : MenuItemData* pGroupData;
1725 : sal_uInt16 nGroupPos;
1726 0 : sal_uInt16 nItemCount = GetItemCount();
1727 0 : bool bFound = false;
1728 :
1729 0 : nGroupPos = nPos;
1730 0 : while ( nGroupPos )
1731 : {
1732 0 : pGroupData = pItemList->GetDataFromPos( nGroupPos-1 );
1733 0 : if ( pGroupData->nBits & MIB_RADIOCHECK )
1734 : {
1735 0 : if ( IsItemChecked( pGroupData->nId ) )
1736 : {
1737 0 : CheckItem( pGroupData->nId, false );
1738 0 : bFound = true;
1739 0 : break;
1740 : }
1741 : }
1742 : else
1743 0 : break;
1744 0 : nGroupPos--;
1745 : }
1746 :
1747 0 : if ( !bFound )
1748 : {
1749 0 : nGroupPos = nPos+1;
1750 0 : while ( nGroupPos < nItemCount )
1751 : {
1752 0 : pGroupData = pItemList->GetDataFromPos( nGroupPos );
1753 0 : if ( pGroupData->nBits & MIB_RADIOCHECK )
1754 : {
1755 0 : if ( IsItemChecked( pGroupData->nId ) )
1756 : {
1757 0 : CheckItem( pGroupData->nId, false );
1758 0 : break;
1759 : }
1760 : }
1761 : else
1762 0 : break;
1763 0 : nGroupPos++;
1764 : }
1765 : }
1766 : }
1767 :
1768 0 : pData->bChecked = bCheck;
1769 :
1770 : // update native menu
1771 0 : if( ImplGetSalMenu() )
1772 0 : ImplGetSalMenu()->CheckItem( nPos, bCheck );
1773 :
1774 0 : ImplCallEventListeners( bCheck ? VCLEVENT_MENU_ITEMCHECKED : VCLEVENT_MENU_ITEMUNCHECKED, nPos );
1775 : }
1776 :
1777 0 : bool Menu::IsItemChecked( sal_uInt16 nItemId ) const
1778 : {
1779 : size_t nPos;
1780 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1781 :
1782 0 : if ( !pData )
1783 0 : return false;
1784 :
1785 0 : return pData->bChecked;
1786 : }
1787 :
1788 0 : void Menu::EnableItem( sal_uInt16 nItemId, bool bEnable )
1789 : {
1790 : size_t nPos;
1791 0 : MenuItemData* pItemData = pItemList->GetData( nItemId, nPos );
1792 :
1793 0 : if ( pItemData && ( pItemData->bEnabled != bEnable ) )
1794 : {
1795 0 : pItemData->bEnabled = bEnable;
1796 :
1797 0 : Window* pWin = ImplGetWindow();
1798 0 : if ( pWin && pWin->IsVisible() )
1799 : {
1800 : DBG_ASSERT( bIsMenuBar, "Menu::EnableItem - Popup visible!" );
1801 0 : long nX = 0;
1802 0 : size_t nCount = pItemList->size();
1803 0 : for ( size_t n = 0; n < nCount; n++ )
1804 : {
1805 0 : MenuItemData* pData = pItemList->GetDataFromPos( n );
1806 0 : if ( n == nPos )
1807 : {
1808 0 : pWin->Invalidate( Rectangle( Point( nX, 0 ), Size( pData->aSz.Width(), pData->aSz.Height() ) ) );
1809 0 : break;
1810 : }
1811 0 : nX += pData->aSz.Width();
1812 : }
1813 : }
1814 : // update native menu
1815 0 : if( ImplGetSalMenu() )
1816 0 : ImplGetSalMenu()->EnableItem( nPos, bEnable );
1817 :
1818 0 : ImplCallEventListeners( bEnable ? VCLEVENT_MENU_ENABLE : VCLEVENT_MENU_DISABLE, nPos );
1819 : }
1820 0 : }
1821 :
1822 0 : bool Menu::IsItemEnabled( sal_uInt16 nItemId ) const
1823 : {
1824 : size_t nPos;
1825 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1826 :
1827 0 : if ( !pData )
1828 0 : return false;
1829 :
1830 0 : return pData->bEnabled;
1831 : }
1832 :
1833 0 : void Menu::ShowItem( sal_uInt16 nItemId, bool bVisible )
1834 : {
1835 : size_t nPos;
1836 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1837 :
1838 : DBG_ASSERT( !bIsMenuBar, "Menu::ShowItem - ignored for menu bar entries!" );
1839 0 : if ( !bIsMenuBar && pData && ( pData->bVisible != bVisible ) )
1840 : {
1841 0 : Window* pWin = ImplGetWindow();
1842 0 : if ( pWin && pWin->IsVisible() )
1843 : {
1844 : DBG_ASSERT( false, "Menu::ShowItem - ignored for visible popups!" );
1845 0 : return;
1846 : }
1847 0 : pData->bVisible = bVisible;
1848 :
1849 : // update native menu
1850 0 : if( ImplGetSalMenu() )
1851 0 : ImplGetSalMenu()->ShowItem( nPos, bVisible );
1852 : }
1853 : }
1854 :
1855 0 : void Menu::SetItemText( sal_uInt16 nItemId, const OUString& rStr )
1856 : {
1857 : size_t nPos;
1858 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1859 :
1860 0 : if ( !pData )
1861 0 : return;
1862 :
1863 0 : if ( !rStr.equals( pData->aText ) )
1864 : {
1865 0 : pData->aText = rStr;
1866 0 : ImplSetMenuItemData( pData );
1867 : // update native menu
1868 0 : if( ImplGetSalMenu() && pData->pSalMenuItem )
1869 0 : ImplGetSalMenu()->SetItemText( nPos, pData->pSalMenuItem, rStr );
1870 :
1871 0 : Window* pWin = ImplGetWindow();
1872 0 : delete mpLayoutData, mpLayoutData = NULL;
1873 0 : if ( pWin && IsMenuBar() )
1874 : {
1875 0 : ImplCalcSize( pWin );
1876 0 : if ( pWin->IsVisible() )
1877 0 : pWin->Invalidate();
1878 : }
1879 :
1880 0 : ImplCallEventListeners( VCLEVENT_MENU_ITEMTEXTCHANGED, nPos );
1881 : }
1882 : }
1883 :
1884 0 : OUString Menu::GetItemText( sal_uInt16 nItemId ) const
1885 : {
1886 : size_t nPos;
1887 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1888 :
1889 0 : if ( pData )
1890 0 : return pData->aText;
1891 :
1892 0 : return OUString();
1893 : }
1894 :
1895 0 : void Menu::SetItemImage( sal_uInt16 nItemId, const Image& rImage )
1896 : {
1897 : size_t nPos;
1898 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1899 :
1900 0 : if ( !pData )
1901 0 : return;
1902 :
1903 0 : pData->aImage = rImage;
1904 0 : ImplSetMenuItemData( pData );
1905 :
1906 : // update native menu
1907 0 : if( ImplGetSalMenu() && pData->pSalMenuItem )
1908 0 : ImplGetSalMenu()->SetItemImage( nPos, pData->pSalMenuItem, rImage );
1909 : }
1910 :
1911 0 : static inline Image ImplRotImage( const Image& rImage, long nAngle10 )
1912 : {
1913 0 : Image aRet;
1914 0 : BitmapEx aBmpEx( rImage.GetBitmapEx() );
1915 :
1916 0 : aBmpEx.Rotate( nAngle10, COL_WHITE );
1917 :
1918 0 : return Image( aBmpEx );
1919 : }
1920 :
1921 0 : void Menu::SetItemImageAngle( sal_uInt16 nItemId, long nAngle10 )
1922 : {
1923 : size_t nPos;
1924 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1925 :
1926 0 : if ( pData )
1927 : {
1928 0 : long nDeltaAngle = (nAngle10 - pData->nItemImageAngle) % 3600;
1929 0 : while( nDeltaAngle < 0 )
1930 0 : nDeltaAngle += 3600;
1931 :
1932 0 : pData->nItemImageAngle = nAngle10;
1933 0 : if( nDeltaAngle && !!pData->aImage )
1934 0 : pData->aImage = ImplRotImage( pData->aImage, nDeltaAngle );
1935 : }
1936 0 : }
1937 :
1938 0 : static inline Image ImplMirrorImage( const Image& rImage )
1939 : {
1940 0 : Image aRet;
1941 0 : BitmapEx aBmpEx( rImage.GetBitmapEx() );
1942 :
1943 0 : aBmpEx.Mirror( BMP_MIRROR_HORZ );
1944 :
1945 0 : return Image( aBmpEx );
1946 : }
1947 :
1948 0 : void Menu::SetItemImageMirrorMode( sal_uInt16 nItemId, bool bMirror )
1949 : {
1950 : size_t nPos;
1951 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1952 :
1953 0 : if ( pData )
1954 : {
1955 0 : if( ( pData->bMirrorMode && ! bMirror ) ||
1956 0 : ( ! pData->bMirrorMode && bMirror )
1957 : )
1958 : {
1959 0 : pData->bMirrorMode = bMirror ? true : false;
1960 0 : if( !!pData->aImage )
1961 0 : pData->aImage = ImplMirrorImage( pData->aImage );
1962 : }
1963 : }
1964 0 : }
1965 :
1966 0 : Image Menu::GetItemImage( sal_uInt16 nItemId ) const
1967 : {
1968 0 : MenuItemData* pData = pItemList->GetData( nItemId );
1969 :
1970 0 : if ( pData )
1971 0 : return pData->aImage;
1972 : else
1973 0 : return Image();
1974 : }
1975 :
1976 0 : void Menu::SetItemCommand( sal_uInt16 nItemId, const OUString& rCommand )
1977 : {
1978 : size_t nPos;
1979 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1980 :
1981 0 : if ( pData )
1982 0 : pData->aCommandStr = rCommand;
1983 0 : }
1984 :
1985 0 : OUString Menu::GetItemCommand( sal_uInt16 nItemId ) const
1986 : {
1987 0 : MenuItemData* pData = pItemList->GetData( nItemId );
1988 :
1989 0 : if (pData)
1990 0 : return pData->aCommandStr;
1991 :
1992 0 : return OUString();
1993 : }
1994 :
1995 0 : void Menu::SetHelpCommand( sal_uInt16 nItemId, const OUString& rStr )
1996 : {
1997 0 : MenuItemData* pData = pItemList->GetData( nItemId );
1998 :
1999 0 : if ( pData )
2000 0 : pData->aHelpCommandStr = rStr;
2001 0 : }
2002 :
2003 0 : OUString Menu::GetHelpCommand( sal_uInt16 nItemId ) const
2004 : {
2005 0 : MenuItemData* pData = pItemList->GetData( nItemId );
2006 :
2007 0 : if ( pData )
2008 0 : return pData->aHelpCommandStr;
2009 :
2010 0 : return OUString();
2011 : }
2012 :
2013 0 : void Menu::SetHelpText( sal_uInt16 nItemId, const OUString& rStr )
2014 : {
2015 0 : MenuItemData* pData = pItemList->GetData( nItemId );
2016 :
2017 0 : if ( pData )
2018 0 : pData->aHelpText = rStr;
2019 0 : }
2020 :
2021 0 : OUString Menu::ImplGetHelpText( sal_uInt16 nItemId ) const
2022 : {
2023 0 : MenuItemData* pData = pItemList->GetData( nItemId );
2024 :
2025 0 : if ( pData && pData->aHelpText.isEmpty() &&
2026 0 : (( !pData->aHelpId.isEmpty() ) || ( !pData->aCommandStr.isEmpty() )))
2027 : {
2028 0 : Help* pHelp = Application::GetHelp();
2029 0 : if ( pHelp )
2030 : {
2031 0 : if (!pData->aCommandStr.isEmpty())
2032 0 : pData->aHelpText = pHelp->GetHelpText( pData->aCommandStr, NULL );
2033 0 : if (pData->aHelpText.isEmpty() && !pData->aHelpId.isEmpty())
2034 0 : pData->aHelpText = pHelp->GetHelpText( OStringToOUString( pData->aHelpId, RTL_TEXTENCODING_UTF8 ), NULL );
2035 : }
2036 : }
2037 :
2038 0 : return OUString();
2039 : }
2040 :
2041 0 : OUString Menu::GetHelpText( sal_uInt16 nItemId ) const
2042 : {
2043 0 : return ImplGetHelpText( nItemId );
2044 : }
2045 :
2046 0 : void Menu::SetTipHelpText( sal_uInt16 nItemId, const OUString& rStr )
2047 : {
2048 0 : MenuItemData* pData = pItemList->GetData( nItemId );
2049 :
2050 0 : if ( pData )
2051 0 : pData->aTipHelpText = rStr;
2052 0 : }
2053 :
2054 0 : OUString Menu::GetTipHelpText( sal_uInt16 nItemId ) const
2055 : {
2056 0 : MenuItemData* pData = pItemList->GetData( nItemId );
2057 :
2058 0 : if ( pData )
2059 0 : return pData->aTipHelpText;
2060 :
2061 0 : return OUString();
2062 : }
2063 :
2064 0 : void Menu::SetHelpId( sal_uInt16 nItemId, const OString& rHelpId )
2065 : {
2066 0 : MenuItemData* pData = pItemList->GetData( nItemId );
2067 :
2068 0 : if ( pData )
2069 0 : pData->aHelpId = rHelpId;
2070 0 : }
2071 :
2072 0 : OString Menu::GetHelpId( sal_uInt16 nItemId ) const
2073 : {
2074 0 : OString aRet;
2075 :
2076 0 : MenuItemData* pData = pItemList->GetData( nItemId );
2077 :
2078 0 : if ( pData )
2079 : {
2080 0 : if ( !pData->aHelpId.isEmpty() )
2081 0 : aRet = pData->aHelpId;
2082 : else
2083 0 : aRet = OUStringToOString( pData->aCommandStr, RTL_TEXTENCODING_UTF8 );
2084 : }
2085 :
2086 0 : return aRet;
2087 : }
2088 :
2089 0 : Menu& Menu::operator=( const Menu& rMenu )
2090 : {
2091 : // clean up
2092 0 : Clear();
2093 :
2094 : // copy items
2095 0 : sal_uInt16 nCount = rMenu.GetItemCount();
2096 0 : for ( sal_uInt16 i = 0; i < nCount; i++ )
2097 0 : ImplCopyItem( this, rMenu, i, MENU_APPEND, 1 );
2098 :
2099 0 : nDefaultItem = rMenu.nDefaultItem;
2100 0 : aActivateHdl = rMenu.aActivateHdl;
2101 0 : aDeactivateHdl = rMenu.aDeactivateHdl;
2102 0 : aHighlightHdl = rMenu.aHighlightHdl;
2103 0 : aSelectHdl = rMenu.aSelectHdl;
2104 0 : aTitleText = rMenu.aTitleText;
2105 0 : bIsMenuBar = rMenu.bIsMenuBar;
2106 :
2107 0 : return *this;
2108 : }
2109 :
2110 0 : bool Menu::ImplIsVisible( sal_uInt16 nPos ) const
2111 : {
2112 0 : bool bVisible = true;
2113 :
2114 0 : MenuItemData* pData = pItemList->GetDataFromPos( nPos );
2115 : // check general visibility first
2116 0 : if( pData && !pData->bVisible )
2117 0 : bVisible = false;
2118 :
2119 0 : if ( bVisible && pData && pData->eType == MENUITEM_SEPARATOR )
2120 : {
2121 0 : if( nPos == 0 ) // no separator should be shown at the very beginning
2122 0 : bVisible = false;
2123 : else
2124 : {
2125 : // always avoid adjacent separators
2126 0 : size_t nCount = pItemList->size();
2127 : size_t n;
2128 0 : MenuItemData* pNextData = NULL;
2129 : // search next visible item
2130 0 : for( n = nPos + 1; n < nCount; n++ )
2131 : {
2132 0 : pNextData = pItemList->GetDataFromPos( n );
2133 0 : if( pNextData && pNextData->bVisible )
2134 : {
2135 0 : if( pNextData->eType == MENUITEM_SEPARATOR || ImplIsVisible(n) )
2136 0 : break;
2137 : }
2138 : }
2139 0 : if( n == nCount ) // no next visible item
2140 0 : bVisible = false;
2141 : // check for separator
2142 0 : if( pNextData && pNextData->bVisible && pNextData->eType == MENUITEM_SEPARATOR )
2143 0 : bVisible = false;
2144 :
2145 0 : if( bVisible )
2146 : {
2147 0 : for( n = nPos; n > 0; n-- )
2148 : {
2149 0 : pNextData = pItemList->GetDataFromPos( n-1 );
2150 0 : if( pNextData && pNextData->bVisible )
2151 : {
2152 0 : if( pNextData->eType != MENUITEM_SEPARATOR && ImplIsVisible(n-1) )
2153 0 : break;
2154 : }
2155 : }
2156 0 : if( n == 0 ) // no previous visible item
2157 0 : bVisible = false;
2158 : }
2159 : }
2160 : }
2161 :
2162 : // not allowed for menubar, as I do not know
2163 : // whether a menu-entry will disappear or will appear
2164 0 : if ( bVisible && !bIsMenuBar && ( nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES ) &&
2165 0 : !( nMenuFlags & MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES ) )
2166 : {
2167 0 : if( !pData ) // e.g. nPos == ITEMPOS_INVALID
2168 0 : bVisible = false;
2169 0 : else if ( pData->eType != MENUITEM_SEPARATOR ) // separators handled above
2170 : {
2171 : // bVisible = pData->bEnabled && ( !pData->pSubMenu || pData->pSubMenu->HasValidEntries( true ) );
2172 0 : bVisible = pData->bEnabled; // do not check submenus as they might be filled at Activate().
2173 : }
2174 : }
2175 :
2176 0 : return bVisible;
2177 : }
2178 :
2179 0 : bool Menu::IsItemPosVisible( sal_uInt16 nItemPos ) const
2180 : {
2181 0 : return IsMenuVisible() && ImplIsVisible( nItemPos );
2182 : }
2183 :
2184 0 : bool Menu::IsMenuVisible() const
2185 : {
2186 0 : return pWindow && pWindow->IsReallyVisible();
2187 : }
2188 :
2189 0 : bool Menu::ImplIsSelectable( sal_uInt16 nPos ) const
2190 : {
2191 0 : bool bSelectable = true;
2192 :
2193 0 : MenuItemData* pData = pItemList->GetDataFromPos( nPos );
2194 : // check general visibility first
2195 0 : if ( pData && ( pData->nBits & MIB_NOSELECT ) )
2196 0 : bSelectable = false;
2197 :
2198 0 : return bSelectable;
2199 : }
2200 :
2201 0 : void Menu::SelectItem( sal_uInt16 nItemId )
2202 : {
2203 0 : if( bIsMenuBar )
2204 0 : static_cast<MenuBar*>(this)->SelectEntry( nItemId );
2205 : else
2206 0 : static_cast<PopupMenu*>(this)->SelectEntry( nItemId );
2207 0 : }
2208 :
2209 0 : ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > Menu::GetAccessible()
2210 : {
2211 : // Since PopupMenu are sometimes shared by different instances of MenuBar, the mxAccessible member gets
2212 : // overwritten and may contain a disposed object when the initial menubar gets set again. So use the
2213 : // mxAccessible member only for sub menus.
2214 0 : if ( pStartedFrom )
2215 : {
2216 0 : for ( sal_uInt16 i = 0, nCount = pStartedFrom->GetItemCount(); i < nCount; ++i )
2217 : {
2218 0 : sal_uInt16 nItemId = pStartedFrom->GetItemId( i );
2219 0 : if ( static_cast< Menu* >( pStartedFrom->GetPopupMenu( nItemId ) ) == this )
2220 : {
2221 0 : ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xParent = pStartedFrom->GetAccessible();
2222 0 : if ( xParent.is() )
2223 : {
2224 0 : ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
2225 0 : if ( xParentContext.is() )
2226 0 : return xParentContext->getAccessibleChild( i );
2227 0 : }
2228 : }
2229 : }
2230 : }
2231 0 : else if ( !mxAccessible.is() )
2232 : {
2233 0 : UnoWrapperBase* pWrapper = Application::GetUnoWrapper();
2234 0 : if ( pWrapper )
2235 0 : mxAccessible = pWrapper->CreateAccessible( this, bIsMenuBar );
2236 : }
2237 :
2238 0 : return mxAccessible;
2239 : }
2240 :
2241 0 : void Menu::SetAccessible( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible )
2242 : {
2243 0 : mxAccessible = rxAccessible;
2244 0 : }
2245 :
2246 0 : Size Menu::ImplGetNativeCheckAndRadioSize( const Window* pWin, long& rCheckHeight, long& rRadioHeight ) const
2247 : {
2248 0 : long nCheckWidth = 0, nRadioWidth = 0;
2249 0 : rCheckHeight = rRadioHeight = 0;
2250 :
2251 0 : if( ! bIsMenuBar )
2252 : {
2253 0 : ImplControlValue aVal;
2254 0 : Rectangle aNativeBounds;
2255 0 : Rectangle aNativeContent;
2256 0 : Point tmp( 0, 0 );
2257 0 : Rectangle aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) );
2258 0 : if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_CHECK_MARK ) )
2259 : {
2260 0 : if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
2261 : ControlPart(PART_MENU_ITEM_CHECK_MARK),
2262 : aCtrlRegion,
2263 : ControlState(CTRL_STATE_ENABLED),
2264 : aVal,
2265 : OUString(),
2266 : aNativeBounds,
2267 0 : aNativeContent )
2268 : )
2269 : {
2270 0 : rCheckHeight = aNativeBounds.GetHeight();
2271 0 : nCheckWidth = aNativeContent.GetWidth();
2272 : }
2273 : }
2274 0 : if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_RADIO_MARK ) )
2275 : {
2276 0 : if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
2277 : ControlPart(PART_MENU_ITEM_RADIO_MARK),
2278 : aCtrlRegion,
2279 : ControlState(CTRL_STATE_ENABLED),
2280 : aVal,
2281 : OUString(),
2282 : aNativeBounds,
2283 0 : aNativeContent )
2284 : )
2285 : {
2286 0 : rRadioHeight = aNativeBounds.GetHeight();
2287 0 : nRadioWidth = aNativeContent.GetWidth();
2288 : }
2289 0 : }
2290 : }
2291 0 : return Size(std::max(nCheckWidth, nRadioWidth), std::max(rCheckHeight, rRadioHeight));
2292 : }
2293 :
2294 0 : bool Menu::ImplGetNativeSubmenuArrowSize( Window* pWin, Size& rArrowSize, long& rArrowSpacing ) const
2295 : {
2296 0 : ImplControlValue aVal;
2297 0 : Rectangle aNativeBounds;
2298 0 : Rectangle aNativeContent;
2299 0 : Point tmp( 0, 0 );
2300 0 : Rectangle aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) );
2301 0 : if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
2302 0 : PART_MENU_SUBMENU_ARROW ) )
2303 : {
2304 0 : if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
2305 : ControlPart(PART_MENU_SUBMENU_ARROW),
2306 : aCtrlRegion,
2307 : ControlState(CTRL_STATE_ENABLED),
2308 : aVal,
2309 : OUString(),
2310 : aNativeBounds,
2311 0 : aNativeContent )
2312 : )
2313 : {
2314 : Size aSize( Size ( aNativeContent.GetWidth(),
2315 0 : aNativeContent.GetHeight() ) );
2316 0 : rArrowSize = aSize;
2317 0 : rArrowSpacing = aNativeBounds.GetWidth() - aNativeContent.GetWidth();
2318 :
2319 0 : return true;
2320 : }
2321 : }
2322 0 : return false;
2323 : }
2324 :
2325 0 : void Menu::ImplAddDel( ImplMenuDelData& rDel )
2326 : {
2327 : DBG_ASSERT( !rDel.mpMenu, "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !" );
2328 0 : if( !rDel.mpMenu )
2329 : {
2330 0 : rDel.mpMenu = this;
2331 0 : rDel.mpNext = mpFirstDel;
2332 0 : mpFirstDel = &rDel;
2333 : }
2334 0 : }
2335 :
2336 0 : void Menu::ImplRemoveDel( ImplMenuDelData& rDel )
2337 : {
2338 0 : rDel.mpMenu = NULL;
2339 0 : if ( mpFirstDel == &rDel )
2340 : {
2341 0 : mpFirstDel = rDel.mpNext;
2342 : }
2343 : else
2344 : {
2345 0 : ImplMenuDelData* pData = mpFirstDel;
2346 0 : while ( pData && (pData->mpNext != &rDel) )
2347 0 : pData = pData->mpNext;
2348 :
2349 : DBG_ASSERT( pData, "Menu::ImplRemoveDel(): ImplMenuDelData not registered !" );
2350 0 : if( pData )
2351 0 : pData->mpNext = rDel.mpNext;
2352 : }
2353 0 : }
2354 :
2355 0 : Size Menu::ImplCalcSize( const Window* pWin )
2356 : {
2357 : // | Check/Radio/Image| Text| Accel/Popup|
2358 :
2359 : // for symbols: nFontHeight x nFontHeight
2360 0 : long nFontHeight = pWin->GetTextHeight();
2361 0 : long nExtra = nFontHeight/4;
2362 :
2363 0 : long nMinMenuItemHeight = nFontHeight;
2364 0 : long nCheckHeight = 0, nRadioHeight = 0;
2365 0 : Size aMaxSize = ImplGetNativeCheckAndRadioSize(pWin, nCheckHeight, nRadioHeight);
2366 0 : if( aMaxSize.Height() > nMinMenuItemHeight )
2367 0 : nMinMenuItemHeight = aMaxSize.Height();
2368 :
2369 0 : Size aMaxImgSz;
2370 :
2371 0 : const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
2372 0 : if ( rSettings.GetUseImagesInMenus() )
2373 : {
2374 0 : if ( 16 > nMinMenuItemHeight )
2375 0 : nMinMenuItemHeight = 16;
2376 0 : for ( size_t i = pItemList->size(); i; )
2377 : {
2378 0 : MenuItemData* pData = pItemList->GetDataFromPos( --i );
2379 0 : if ( ImplIsVisible( i )
2380 0 : && ( ( pData->eType == MENUITEM_IMAGE )
2381 0 : || ( pData->eType == MENUITEM_STRINGIMAGE )
2382 : )
2383 : )
2384 : {
2385 0 : Size aImgSz = pData->aImage.GetSizePixel();
2386 0 : if ( aImgSz.Height() > aMaxImgSz.Height() )
2387 0 : aMaxImgSz.Height() = aImgSz.Height();
2388 0 : if ( aImgSz.Height() > nMinMenuItemHeight )
2389 0 : nMinMenuItemHeight = aImgSz.Height();
2390 0 : break;
2391 : }
2392 : }
2393 : }
2394 :
2395 0 : Size aSz;
2396 0 : long nCheckWidth = 0;
2397 0 : long nMaxWidth = 0;
2398 :
2399 0 : for ( size_t n = pItemList->size(); n; )
2400 : {
2401 0 : MenuItemData* pData = pItemList->GetDataFromPos( --n );
2402 :
2403 0 : pData->aSz.Height() = 0;
2404 0 : pData->aSz.Width() = 0;
2405 :
2406 0 : if ( ImplIsVisible( n ) )
2407 : {
2408 0 : long nWidth = 0;
2409 :
2410 : // Separator
2411 0 : if ( !bIsMenuBar && ( pData->eType == MENUITEM_SEPARATOR ) )
2412 : {
2413 : DBG_ASSERT( !bIsMenuBar, "Separator in MenuBar ?! " );
2414 0 : pData->aSz.Height() = 4;
2415 : }
2416 :
2417 : // Image:
2418 0 : if ( !bIsMenuBar && ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
2419 : {
2420 0 : Size aImgSz = pData->aImage.GetSizePixel();
2421 0 : aImgSz.Height() += 4; // add a border for native marks
2422 0 : aImgSz.Width() += 4; // add a border for native marks
2423 0 : if ( aImgSz.Width() > aMaxImgSz.Width() )
2424 0 : aMaxImgSz.Width() = aImgSz.Width();
2425 0 : if ( aImgSz.Height() > aMaxImgSz.Height() )
2426 0 : aMaxImgSz.Height() = aImgSz.Height();
2427 0 : if ( aImgSz.Height() > pData->aSz.Height() )
2428 0 : pData->aSz.Height() = aImgSz.Height();
2429 : }
2430 :
2431 : // Check Buttons:
2432 0 : if ( !bIsMenuBar && pData->HasCheck() )
2433 : {
2434 0 : nCheckWidth = aMaxSize.Width();
2435 : // checks / images take the same place
2436 0 : if( ! ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
2437 0 : nWidth += nCheckWidth + nExtra * 2;
2438 : }
2439 :
2440 : // Text:
2441 0 : if ( (pData->eType == MENUITEM_STRING) || (pData->eType == MENUITEM_STRINGIMAGE) )
2442 : {
2443 0 : long nTextWidth = pWin->GetCtrlTextWidth( pData->aText );
2444 0 : long nTextHeight = pWin->GetTextHeight();
2445 :
2446 0 : if ( bIsMenuBar )
2447 : {
2448 0 : if ( nTextHeight > pData->aSz.Height() )
2449 0 : pData->aSz.Height() = nTextHeight;
2450 :
2451 0 : pData->aSz.Width() = nTextWidth + 4*nExtra;
2452 0 : aSz.Width() += pData->aSz.Width();
2453 : }
2454 : else
2455 0 : pData->aSz.Height() = std::max( std::max( nTextHeight, pData->aSz.Height() ), nMinMenuItemHeight );
2456 :
2457 0 : nWidth += nTextWidth;
2458 : }
2459 :
2460 : // Accel
2461 0 : if ( !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
2462 : {
2463 0 : OUString aName = pData->aAccelKey.GetName();
2464 0 : long nAccWidth = pWin->GetTextWidth( aName );
2465 0 : nAccWidth += nExtra;
2466 0 : nWidth += nAccWidth;
2467 : }
2468 :
2469 : // SubMenu?
2470 0 : if ( !bIsMenuBar && pData->pSubMenu )
2471 : {
2472 0 : if ( nFontHeight > nWidth )
2473 0 : nWidth += nFontHeight;
2474 :
2475 0 : pData->aSz.Height() = std::max( std::max( nFontHeight, pData->aSz.Height() ), nMinMenuItemHeight );
2476 : }
2477 :
2478 0 : pData->aSz.Height() += EXTRAITEMHEIGHT; // little bit more distance
2479 :
2480 0 : if ( !bIsMenuBar )
2481 0 : aSz.Height() += (long)pData->aSz.Height();
2482 :
2483 0 : if ( nWidth > nMaxWidth )
2484 0 : nMaxWidth = nWidth;
2485 :
2486 : }
2487 : }
2488 :
2489 0 : if ( !bIsMenuBar )
2490 : {
2491 : // popup menus should not be wider than half the screen
2492 : // except on rather small screens
2493 : // TODO: move GetScreenNumber from SystemWindow to Window ?
2494 : // currently we rely on internal privileges
2495 0 : unsigned int nDisplayScreen = pWin->ImplGetWindowImpl()->mpFrame->maGeometry.nDisplayScreenNumber;
2496 0 : Rectangle aDispRect( Application::GetScreenPosSizePixel( nDisplayScreen ) );
2497 0 : long nScreenWidth = aDispRect.GetWidth() >= 800 ? aDispRect.GetWidth() : 800;
2498 0 : if( nMaxWidth > nScreenWidth/2 )
2499 0 : nMaxWidth = nScreenWidth/2;
2500 :
2501 0 : sal_uInt16 gfxExtra = (sal_uInt16) std::max( nExtra, 7L ); // #107710# increase space between checkmarks/images/text
2502 0 : nImgOrChkPos = (sal_uInt16)nExtra;
2503 0 : long nImgOrChkWidth = 0;
2504 0 : if( aMaxSize.Height() > 0 ) // NWF case
2505 0 : nImgOrChkWidth = aMaxSize.Height() + nExtra;
2506 : else // non NWF case
2507 0 : nImgOrChkWidth = nFontHeight/2 + gfxExtra;
2508 0 : nImgOrChkWidth = std::max( nImgOrChkWidth, aMaxImgSz.Width() + gfxExtra );
2509 0 : nTextPos = (sal_uInt16)(nImgOrChkPos + nImgOrChkWidth);
2510 0 : nTextPos = nTextPos + gfxExtra;
2511 :
2512 0 : aSz.Width() = nTextPos + nMaxWidth + nExtra;
2513 0 : aSz.Width() += 4*nExtra; // a _little_ more ...
2514 :
2515 0 : aSz.Width() += 2*ImplGetSVData()->maNWFData.mnMenuFormatBorderX;
2516 0 : aSz.Height() += 2*ImplGetSVData()->maNWFData.mnMenuFormatBorderY;
2517 : }
2518 : else
2519 : {
2520 0 : nTextPos = (sal_uInt16)(2*nExtra);
2521 0 : aSz.Height() = nFontHeight+6;
2522 :
2523 : // get menubar height from native methods if supported
2524 0 : if( pWindow->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
2525 : {
2526 0 : ImplControlValue aVal;
2527 0 : Rectangle aNativeBounds;
2528 0 : Rectangle aNativeContent;
2529 0 : Point tmp( 0, 0 );
2530 0 : Rectangle aCtrlRegion( tmp, Size( 100, 15 ) );
2531 0 : if( pWindow->GetNativeControlRegion( ControlType(CTRL_MENUBAR),
2532 : ControlPart(PART_ENTIRE_CONTROL),
2533 : aCtrlRegion,
2534 : ControlState(CTRL_STATE_ENABLED),
2535 : aVal,
2536 : OUString(),
2537 : aNativeBounds,
2538 0 : aNativeContent )
2539 : )
2540 : {
2541 0 : int nNativeHeight = aNativeBounds.GetHeight();
2542 0 : if( nNativeHeight > aSz.Height() )
2543 0 : aSz.Height() = nNativeHeight;
2544 0 : }
2545 : }
2546 :
2547 : // account for the size of the close button, which actually is a toolbox
2548 : // due to NWF this is variable
2549 0 : long nCloserHeight = ((MenuBarWindow*) pWindow)->MinCloseButtonSize().Height();
2550 0 : if( aSz.Height() < nCloserHeight )
2551 0 : aSz.Height() = nCloserHeight;
2552 : }
2553 :
2554 0 : if ( pLogo )
2555 0 : aSz.Width() += pLogo->aBitmap.GetSizePixel().Width();
2556 :
2557 0 : return aSz;
2558 : }
2559 :
2560 0 : static void ImplPaintCheckBackground( Window* i_pWindow, const Rectangle& i_rRect, bool i_bHighlight )
2561 : {
2562 0 : bool bNativeOk = false;
2563 0 : if( i_pWindow->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) )
2564 : {
2565 0 : ImplControlValue aControlValue;
2566 0 : Rectangle aCtrlRegion( i_rRect );
2567 0 : ControlState nState = CTRL_STATE_PRESSED | CTRL_STATE_ENABLED;
2568 :
2569 0 : aControlValue.setTristateVal( BUTTONVALUE_ON );
2570 :
2571 : bNativeOk = i_pWindow->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON,
2572 : aCtrlRegion, nState, aControlValue,
2573 0 : OUString() );
2574 : }
2575 :
2576 0 : if( ! bNativeOk )
2577 : {
2578 0 : const StyleSettings& rSettings = i_pWindow->GetSettings().GetStyleSettings();
2579 0 : Color aColor( i_bHighlight ? rSettings.GetMenuHighlightTextColor() : rSettings.GetHighlightColor() );
2580 0 : i_pWindow->DrawSelectionBackground( i_rRect, 0, i_bHighlight, true, false, 2, NULL, &aColor );
2581 : }
2582 0 : }
2583 :
2584 0 : static OUString getShortenedString( const OUString& i_rLong, Window* i_pWin, long i_nMaxWidth )
2585 : {
2586 0 : sal_Int32 nPos = -1;
2587 0 : OUString aNonMnem( OutputDevice::GetNonMnemonicString( i_rLong, nPos ) );
2588 0 : aNonMnem = i_pWin->GetEllipsisString( aNonMnem, i_nMaxWidth, TEXT_DRAW_CENTERELLIPSIS );
2589 : // re-insert mnemonic
2590 0 : if( nPos != -1 )
2591 : {
2592 0 : if( nPos < aNonMnem.getLength() && i_rLong[nPos+1] == aNonMnem[nPos] )
2593 : {
2594 0 : OUStringBuffer aBuf( i_rLong.getLength() );
2595 0 : aBuf.append( aNonMnem.copy( 0, nPos) );
2596 0 : aBuf.append( '~' );
2597 0 : aBuf.append( aNonMnem.copy(nPos) );
2598 0 : aNonMnem = aBuf.makeStringAndClear();
2599 : }
2600 : }
2601 0 : return aNonMnem;
2602 : }
2603 :
2604 0 : void Menu::ImplPaint( Window* pWin, sal_uInt16 nBorder, long nStartY, MenuItemData* pThisItemOnly, bool bHighlighted, bool bLayout, bool bRollover ) const
2605 : {
2606 : // for symbols: nFontHeight x nFontHeight
2607 0 : long nFontHeight = pWin->GetTextHeight();
2608 0 : long nExtra = nFontHeight/4;
2609 :
2610 0 : long nCheckHeight = 0, nRadioHeight = 0;
2611 0 : ImplGetNativeCheckAndRadioSize( pWin, nCheckHeight, nRadioHeight );
2612 :
2613 0 : DecorationView aDecoView( pWin );
2614 0 : const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
2615 :
2616 0 : Point aTopLeft, aTmpPos;
2617 :
2618 0 : if ( pLogo )
2619 0 : aTopLeft.X() = pLogo->aBitmap.GetSizePixel().Width();
2620 :
2621 0 : int nOuterSpaceX = 0;
2622 0 : if( !bIsMenuBar )
2623 : {
2624 0 : nOuterSpaceX = ImplGetSVData()->maNWFData.mnMenuFormatBorderX;
2625 0 : aTopLeft.X() += nOuterSpaceX;
2626 0 : aTopLeft.Y() += ImplGetSVData()->maNWFData.mnMenuFormatBorderY;
2627 : }
2628 :
2629 0 : Size aOutSz = pWin->GetOutputSizePixel();
2630 0 : size_t nCount = pItemList->size();
2631 0 : if( bLayout )
2632 0 : mpLayoutData->m_aVisibleItemBoundRects.clear();
2633 :
2634 0 : for ( size_t n = 0; n < nCount; n++ )
2635 : {
2636 0 : MenuItemData* pData = pItemList->GetDataFromPos( n );
2637 0 : if ( ImplIsVisible( n ) && ( !pThisItemOnly || ( pData == pThisItemOnly ) ) )
2638 : {
2639 0 : if ( pThisItemOnly )
2640 : {
2641 0 : if ( bIsMenuBar && bRollover )
2642 0 : pWin->SetTextColor( rSettings.GetMenuBarRolloverTextColor() );
2643 0 : else if ( bHighlighted )
2644 0 : pWin->SetTextColor( rSettings.GetMenuHighlightTextColor() );
2645 : }
2646 :
2647 0 : Point aPos( aTopLeft );
2648 0 : aPos.Y() += nBorder;
2649 0 : aPos.Y() += nStartY;
2650 :
2651 0 : if ( aPos.Y() >= 0 )
2652 : {
2653 0 : long nTextOffsetY = ((pData->aSz.Height()-nFontHeight)/2);
2654 0 : if( bIsMenuBar )
2655 0 : nTextOffsetY += (aOutSz.Height()-pData->aSz.Height()) / 2;
2656 0 : sal_uInt16 nTextStyle = 0;
2657 0 : sal_uInt16 nSymbolStyle = 0;
2658 0 : sal_uInt16 nImageStyle = 0;
2659 :
2660 : // submenus without items are not disabled when no items are
2661 : // contained. The application itself should check for this!
2662 : // Otherwise it could happen entries are disabled due to
2663 : // asynchronous loading
2664 0 : if ( !pData->bEnabled )
2665 : {
2666 0 : nTextStyle |= TEXT_DRAW_DISABLE;
2667 0 : nSymbolStyle |= SYMBOL_DRAW_DISABLE;
2668 0 : nImageStyle |= IMAGE_DRAW_DISABLE;
2669 : }
2670 :
2671 : // Separator
2672 0 : if ( !bLayout && !bIsMenuBar && ( pData->eType == MENUITEM_SEPARATOR ) )
2673 : {
2674 0 : bool bNativeOk = false;
2675 0 : if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
2676 0 : PART_MENU_SEPARATOR ) )
2677 : {
2678 0 : ControlState nState = 0;
2679 0 : if ( pData->bEnabled )
2680 0 : nState |= CTRL_STATE_ENABLED;
2681 0 : if ( bHighlighted )
2682 0 : nState |= CTRL_STATE_SELECTED;
2683 0 : Size aSz( pData->aSz );
2684 0 : aSz.Width() = aOutSz.Width() - 2*nOuterSpaceX;
2685 0 : Rectangle aItemRect( aPos, aSz );
2686 0 : MenupopupValue aVal( nTextPos-GUTTERBORDER, aItemRect );
2687 : bNativeOk = pWin->DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_SEPARATOR,
2688 : aItemRect,
2689 : nState,
2690 : aVal,
2691 0 : OUString() );
2692 : }
2693 0 : if( ! bNativeOk )
2694 : {
2695 0 : aTmpPos.Y() = aPos.Y() + ((pData->aSz.Height()-2)/2);
2696 0 : aTmpPos.X() = aPos.X() + 2 + nOuterSpaceX;
2697 0 : pWin->SetLineColor( rSettings.GetShadowColor() );
2698 0 : pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpaceX, aTmpPos.Y() ) );
2699 0 : aTmpPos.Y()++;
2700 0 : pWin->SetLineColor( rSettings.GetLightColor() );
2701 0 : pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpaceX, aTmpPos.Y() ) );
2702 0 : pWin->SetLineColor();
2703 : }
2704 : }
2705 :
2706 0 : Rectangle aOuterCheckRect( Point( aPos.X()+nImgOrChkPos, aPos.Y() ), Size( pData->aSz.Height(), pData->aSz.Height() ) );
2707 0 : aOuterCheckRect.Left() += 1;
2708 0 : aOuterCheckRect.Right() -= 1;
2709 0 : aOuterCheckRect.Top() += 1;
2710 0 : aOuterCheckRect.Bottom() -= 1;
2711 :
2712 : // CheckMark
2713 0 : if ( !bLayout && !bIsMenuBar && pData->HasCheck() )
2714 : {
2715 : // draw selection transparent marker if checked
2716 : // onto that either a checkmark or the item image
2717 : // will be painted
2718 : // however do not do this if native checks will be painted since
2719 : // the selection color too often does not fit the theme's check and/or radio
2720 :
2721 0 : if( ! ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
2722 : {
2723 0 : if ( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
2724 0 : (pData->nBits & MIB_RADIOCHECK)
2725 : ? PART_MENU_ITEM_CHECK_MARK
2726 0 : : PART_MENU_ITEM_RADIO_MARK ) )
2727 : {
2728 0 : ControlPart nPart = ((pData->nBits & MIB_RADIOCHECK)
2729 : ? PART_MENU_ITEM_RADIO_MARK
2730 0 : : PART_MENU_ITEM_CHECK_MARK);
2731 :
2732 0 : ControlState nState = 0;
2733 :
2734 0 : if ( pData->bChecked )
2735 0 : nState |= CTRL_STATE_PRESSED;
2736 :
2737 0 : if ( pData->bEnabled )
2738 0 : nState |= CTRL_STATE_ENABLED;
2739 :
2740 0 : if ( bHighlighted )
2741 0 : nState |= CTRL_STATE_SELECTED;
2742 :
2743 0 : long nCtrlHeight = (pData->nBits & MIB_RADIOCHECK) ? nCheckHeight : nRadioHeight;
2744 0 : aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - nCtrlHeight)/2;
2745 0 : aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - nCtrlHeight)/2;
2746 :
2747 0 : Rectangle aCheckRect( aTmpPos, Size( nCtrlHeight, nCtrlHeight ) );
2748 0 : Size aSz( pData->aSz );
2749 0 : aSz.Width() = aOutSz.Width() - 2*nOuterSpaceX;
2750 0 : Rectangle aItemRect( aPos, aSz );
2751 0 : MenupopupValue aVal( nTextPos-GUTTERBORDER, aItemRect );
2752 : pWin->DrawNativeControl( CTRL_MENU_POPUP, nPart,
2753 : aCheckRect,
2754 : nState,
2755 : aVal,
2756 0 : OUString() );
2757 : }
2758 0 : else if ( pData->bChecked ) // by default do nothing for unchecked items
2759 : {
2760 0 : ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted );
2761 :
2762 : SymbolType eSymbol;
2763 0 : Size aSymbolSize;
2764 0 : if ( pData->nBits & MIB_RADIOCHECK )
2765 : {
2766 0 : eSymbol = SYMBOL_RADIOCHECKMARK;
2767 0 : aSymbolSize = Size( nFontHeight/2, nFontHeight/2 );
2768 : }
2769 : else
2770 : {
2771 0 : eSymbol = SYMBOL_CHECKMARK;
2772 0 : aSymbolSize = Size( (nFontHeight*25)/40, nFontHeight/2 );
2773 : }
2774 0 : aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - aSymbolSize.Width())/2;
2775 0 : aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - aSymbolSize.Height())/2;
2776 0 : Rectangle aRect( aTmpPos, aSymbolSize );
2777 0 : aDecoView.DrawSymbol( aRect, eSymbol, pWin->GetTextColor(), nSymbolStyle );
2778 : }
2779 : }
2780 : }
2781 :
2782 : // Image:
2783 0 : if ( !bLayout && !bIsMenuBar && ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
2784 : {
2785 : // Don't render an image for a check thing
2786 0 : if( pData->bChecked )
2787 0 : ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted );
2788 0 : aTmpPos = aOuterCheckRect.TopLeft();
2789 0 : aTmpPos.X() += (aOuterCheckRect.GetWidth()-pData->aImage.GetSizePixel().Width())/2;
2790 0 : aTmpPos.Y() += (aOuterCheckRect.GetHeight()-pData->aImage.GetSizePixel().Height())/2;
2791 0 : pWin->DrawImage( aTmpPos, pData->aImage, nImageStyle );
2792 : }
2793 :
2794 : // Text:
2795 0 : if ( ( pData->eType == MENUITEM_STRING ) || ( pData->eType == MENUITEM_STRINGIMAGE ) )
2796 : {
2797 0 : aTmpPos.X() = aPos.X() + nTextPos;
2798 0 : aTmpPos.Y() = aPos.Y();
2799 0 : aTmpPos.Y() += nTextOffsetY;
2800 0 : sal_uInt16 nStyle = nTextStyle|TEXT_DRAW_MNEMONIC;
2801 0 : if ( pData->bIsTemporary )
2802 0 : nStyle |= TEXT_DRAW_DISABLE;
2803 0 : MetricVector* pVector = bLayout ? &mpLayoutData->m_aUnicodeBoundRects : NULL;
2804 0 : OUString* pDisplayText = bLayout ? &mpLayoutData->m_aDisplayText : NULL;
2805 0 : if( bLayout )
2806 : {
2807 0 : mpLayoutData->m_aLineIndices.push_back( mpLayoutData->m_aDisplayText.getLength() );
2808 0 : mpLayoutData->m_aLineItemIds.push_back( pData->nId );
2809 0 : mpLayoutData->m_aLineItemPositions.push_back( n );
2810 : }
2811 : // #i47946# with NWF painted menus the background is transparent
2812 : // since DrawCtrlText can depend on the background (e.g. for
2813 : // TEXT_DRAW_DISABLE), temporarily set a background which
2814 : // hopefully matches the NWF background since it is read
2815 : // from the system style settings
2816 0 : bool bSetTmpBackground = !pWin->IsBackground() && pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL );
2817 0 : if( bSetTmpBackground )
2818 : {
2819 : Color aBg = bIsMenuBar ?
2820 0 : pWin->GetSettings().GetStyleSettings().GetMenuBarColor() :
2821 0 : pWin->GetSettings().GetStyleSettings().GetMenuColor();
2822 0 : pWin->SetBackground( Wallpaper( aBg ) );
2823 : }
2824 : // how much space is there for the text ?
2825 0 : long nMaxItemTextWidth = aOutSz.Width() - aTmpPos.X() - nExtra - nOuterSpaceX;
2826 0 : if( !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
2827 : {
2828 0 : OUString aAccText = pData->aAccelKey.GetName();
2829 0 : nMaxItemTextWidth -= pWin->GetTextWidth( aAccText ) + 3*nExtra;
2830 : }
2831 0 : if( !bIsMenuBar && pData->pSubMenu )
2832 : {
2833 0 : nMaxItemTextWidth -= nFontHeight - nExtra;
2834 : }
2835 0 : OUString aItemText( getShortenedString( pData->aText, pWin, nMaxItemTextWidth ) );
2836 0 : pWin->DrawCtrlText( aTmpPos, aItemText, 0, aItemText.getLength(), nStyle, pVector, pDisplayText );
2837 0 : if( bSetTmpBackground )
2838 0 : pWin->SetBackground();
2839 : }
2840 :
2841 : // Accel
2842 0 : if ( !bLayout && !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
2843 : {
2844 0 : OUString aAccText = pData->aAccelKey.GetName();
2845 0 : aTmpPos.X() = aOutSz.Width() - pWin->GetTextWidth( aAccText );
2846 0 : aTmpPos.X() -= 4*nExtra;
2847 :
2848 0 : aTmpPos.X() -= nOuterSpaceX;
2849 0 : aTmpPos.Y() = aPos.Y();
2850 0 : aTmpPos.Y() += nTextOffsetY;
2851 0 : pWin->DrawCtrlText( aTmpPos, aAccText, 0, aAccText.getLength(), nTextStyle );
2852 : }
2853 :
2854 : // SubMenu?
2855 0 : if ( !bLayout && !bIsMenuBar && pData->pSubMenu )
2856 : {
2857 0 : bool bNativeOk = false;
2858 0 : if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
2859 0 : PART_MENU_SUBMENU_ARROW ) )
2860 : {
2861 0 : ControlState nState = 0;
2862 0 : Size aTmpSz( 0, 0 );
2863 0 : long aSpacing = 0;
2864 :
2865 0 : if( !ImplGetNativeSubmenuArrowSize( pWin,
2866 0 : aTmpSz, aSpacing ) )
2867 : {
2868 0 : aTmpSz = Size( nFontHeight, nFontHeight );
2869 0 : aSpacing = nOuterSpaceX;
2870 : }
2871 :
2872 0 : if ( pData->bEnabled )
2873 0 : nState |= CTRL_STATE_ENABLED;
2874 0 : if ( bHighlighted )
2875 0 : nState |= CTRL_STATE_SELECTED;
2876 :
2877 0 : aTmpPos.X() = aOutSz.Width() - aTmpSz.Width() - aSpacing - nOuterSpaceX;
2878 0 : aTmpPos.Y() = aPos.Y() + ( pData->aSz.Height() - aTmpSz.Height() ) / 2;
2879 0 : aTmpPos.Y() += nExtra/2;
2880 :
2881 0 : Rectangle aItemRect( aTmpPos, aTmpSz );
2882 0 : MenupopupValue aVal( nTextPos-GUTTERBORDER, aItemRect );
2883 : bNativeOk = pWin->DrawNativeControl( CTRL_MENU_POPUP,
2884 : PART_MENU_SUBMENU_ARROW,
2885 : aItemRect,
2886 : nState,
2887 : aVal,
2888 0 : OUString() );
2889 : }
2890 0 : if( ! bNativeOk )
2891 : {
2892 0 : aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpaceX;
2893 0 : aTmpPos.Y() = aPos.Y();
2894 0 : aTmpPos.Y() += nExtra/2;
2895 0 : aTmpPos.Y() += ( pData->aSz.Height() / 2 ) - ( nFontHeight/4 );
2896 0 : if ( pData->nBits & MIB_POPUPSELECT )
2897 : {
2898 0 : pWin->SetTextColor( rSettings.GetMenuTextColor() );
2899 0 : Point aTmpPos2( aPos );
2900 0 : aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4;
2901 : aDecoView.DrawFrame(
2902 0 : Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pData->aSz.Height() ) ), FRAME_DRAW_GROUP );
2903 : }
2904 : aDecoView.DrawSymbol(
2905 : Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ),
2906 0 : SYMBOL_SPIN_RIGHT, pWin->GetTextColor(), nSymbolStyle );
2907 : }
2908 : }
2909 :
2910 0 : if ( pThisItemOnly && bHighlighted )
2911 : {
2912 : // This restores the normal menu or menu bar text
2913 : // color for when it is no longer highlighted.
2914 0 : if ( bIsMenuBar )
2915 0 : pWin->SetTextColor( rSettings.GetMenuBarTextColor() );
2916 : else
2917 0 : pWin->SetTextColor( rSettings.GetMenuTextColor() );
2918 : }
2919 : }
2920 0 : if( bLayout )
2921 : {
2922 0 : if ( !bIsMenuBar )
2923 0 : mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, Size( aOutSz.Width(), pData->aSz.Height() ) );
2924 : else
2925 0 : mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, pData->aSz );
2926 : }
2927 : }
2928 :
2929 0 : if ( !bIsMenuBar )
2930 : {
2931 0 : aTopLeft.Y() += pData->aSz.Height();
2932 : }
2933 : else
2934 : {
2935 0 : aTopLeft.X() += pData->aSz.Width();
2936 : }
2937 : }
2938 :
2939 0 : if ( !bLayout && !pThisItemOnly && pLogo )
2940 : {
2941 0 : Size aLogoSz = pLogo->aBitmap.GetSizePixel();
2942 :
2943 0 : Rectangle aRect( Point( 0, 0 ), Point( aLogoSz.Width()-1, aOutSz.Height() ) );
2944 0 : if ( pWin->GetColorCount() >= 256 )
2945 : {
2946 0 : Gradient aGrad( GradientStyle_LINEAR, pLogo->aStartColor, pLogo->aEndColor );
2947 0 : aGrad.SetAngle( 1800 );
2948 0 : aGrad.SetBorder( 15 );
2949 0 : pWin->DrawGradient( aRect, aGrad );
2950 : }
2951 : else
2952 : {
2953 0 : pWin->SetFillColor( pLogo->aStartColor );
2954 0 : pWin->DrawRect( aRect );
2955 : }
2956 :
2957 0 : Point aLogoPos( 0, aOutSz.Height() - aLogoSz.Height() );
2958 0 : pLogo->aBitmap.Draw( pWin, aLogoPos );
2959 : }
2960 0 : }
2961 :
2962 0 : Menu* Menu::ImplGetStartMenu()
2963 : {
2964 0 : Menu* pStart = this;
2965 0 : while ( pStart && pStart->pStartedFrom && ( pStart->pStartedFrom != pStart ) )
2966 0 : pStart = pStart->pStartedFrom;
2967 0 : return pStart;
2968 : }
2969 :
2970 0 : void Menu::ImplCallHighlight(sal_uInt16 nItem)
2971 : {
2972 0 : ImplMenuDelData aDelData( this );
2973 :
2974 0 : nSelectedId = 0;
2975 0 : MenuItemData* pData = pItemList->GetDataFromPos(nItem);
2976 0 : if ( pData )
2977 0 : nSelectedId = pData->nId;
2978 0 : ImplCallEventListeners( VCLEVENT_MENU_HIGHLIGHT, GetItemPos( GetCurItemId() ) );
2979 :
2980 0 : if( !aDelData.isDeleted() )
2981 : {
2982 0 : Highlight();
2983 0 : nSelectedId = 0;
2984 0 : }
2985 0 : }
2986 :
2987 0 : IMPL_LINK_NOARG(Menu, ImplCallSelect)
2988 : {
2989 0 : nEventId = 0;
2990 0 : Select();
2991 0 : return 0;
2992 : }
2993 :
2994 0 : Menu* Menu::ImplFindSelectMenu()
2995 : {
2996 0 : Menu* pSelMenu = nEventId ? this : NULL;
2997 :
2998 0 : for ( size_t n = GetItemList()->size(); n && !pSelMenu; )
2999 : {
3000 0 : MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
3001 :
3002 0 : if ( pData->pSubMenu )
3003 0 : pSelMenu = pData->pSubMenu->ImplFindSelectMenu();
3004 : }
3005 :
3006 0 : return pSelMenu;
3007 : }
3008 :
3009 0 : Menu* Menu::ImplFindMenu( sal_uInt16 nItemId )
3010 : {
3011 0 : Menu* pSelMenu = NULL;
3012 :
3013 0 : for ( size_t n = GetItemList()->size(); n && !pSelMenu; )
3014 : {
3015 0 : MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
3016 :
3017 0 : if( pData->nId == nItemId )
3018 0 : pSelMenu = this;
3019 0 : else if ( pData->pSubMenu )
3020 0 : pSelMenu = pData->pSubMenu->ImplFindMenu( nItemId );
3021 : }
3022 :
3023 0 : return pSelMenu;
3024 : }
3025 :
3026 0 : void Menu::RemoveDisabledEntries( bool bCheckPopups, bool bRemoveEmptyPopups )
3027 : {
3028 0 : for ( sal_uInt16 n = 0; n < GetItemCount(); n++ )
3029 : {
3030 0 : bool bRemove = false;
3031 0 : MenuItemData* pItem = pItemList->GetDataFromPos( n );
3032 0 : if ( pItem->eType == MENUITEM_SEPARATOR )
3033 : {
3034 0 : if ( !n || ( GetItemType( n-1 ) == MENUITEM_SEPARATOR ) )
3035 0 : bRemove = true;
3036 : }
3037 : else
3038 0 : bRemove = !pItem->bEnabled;
3039 :
3040 0 : if ( bCheckPopups && pItem->pSubMenu )
3041 : {
3042 0 : pItem->pSubMenu->RemoveDisabledEntries( true );
3043 0 : if ( bRemoveEmptyPopups && !pItem->pSubMenu->GetItemCount() )
3044 0 : bRemove = true;
3045 : }
3046 :
3047 0 : if ( bRemove )
3048 0 : RemoveItem( n-- );
3049 : }
3050 :
3051 0 : if ( GetItemCount() )
3052 : {
3053 0 : sal_uInt16 nLast = GetItemCount() - 1;
3054 0 : MenuItemData* pItem = pItemList->GetDataFromPos( nLast );
3055 0 : if ( pItem->eType == MENUITEM_SEPARATOR )
3056 0 : RemoveItem( nLast );
3057 : }
3058 0 : delete mpLayoutData, mpLayoutData = NULL;
3059 0 : }
3060 :
3061 0 : bool Menu::HasValidEntries( bool bCheckPopups )
3062 : {
3063 0 : bool bValidEntries = false;
3064 0 : sal_uInt16 nCount = GetItemCount();
3065 0 : for ( sal_uInt16 n = 0; !bValidEntries && ( n < nCount ); n++ )
3066 : {
3067 0 : MenuItemData* pItem = pItemList->GetDataFromPos( n );
3068 0 : if ( pItem->bEnabled && ( pItem->eType != MENUITEM_SEPARATOR ) )
3069 : {
3070 0 : if ( bCheckPopups && pItem->pSubMenu )
3071 0 : bValidEntries = pItem->pSubMenu->HasValidEntries( true );
3072 : else
3073 0 : bValidEntries = true;
3074 : }
3075 : }
3076 0 : return bValidEntries;
3077 : }
3078 :
3079 0 : void Menu::ImplKillLayoutData() const
3080 : {
3081 0 : delete mpLayoutData, mpLayoutData = NULL;
3082 0 : }
3083 :
3084 0 : void Menu::ImplFillLayoutData() const
3085 : {
3086 0 : if( pWindow && pWindow->IsReallyVisible() )
3087 : {
3088 0 : mpLayoutData = new MenuLayoutData();
3089 0 : if( bIsMenuBar )
3090 : {
3091 0 : ImplPaint( pWindow, 0, 0, 0, false, true );
3092 : }
3093 : else
3094 : {
3095 0 : MenuFloatingWindow* pFloat = (MenuFloatingWindow*)pWindow;
3096 0 : ImplPaint( pWindow, pFloat->nScrollerHeight, pFloat->ImplGetStartY(), 0, false, true );
3097 : }
3098 : }
3099 0 : }
3100 :
3101 0 : Rectangle Menu::GetCharacterBounds( sal_uInt16 nItemID, long nIndex ) const
3102 : {
3103 0 : long nItemIndex = -1;
3104 0 : if( ! mpLayoutData )
3105 0 : ImplFillLayoutData();
3106 0 : if( mpLayoutData )
3107 : {
3108 0 : for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ )
3109 : {
3110 0 : if( mpLayoutData->m_aLineItemIds[i] == nItemID )
3111 : {
3112 0 : nItemIndex = mpLayoutData->m_aLineIndices[i];
3113 0 : break;
3114 : }
3115 : }
3116 : }
3117 0 : return (mpLayoutData && nItemIndex != -1) ? mpLayoutData->GetCharacterBounds( nItemIndex+nIndex ) : Rectangle();
3118 : }
3119 :
3120 0 : long Menu::GetIndexForPoint( const Point& rPoint, sal_uInt16& rItemID ) const
3121 : {
3122 0 : long nIndex = -1;
3123 0 : rItemID = 0;
3124 0 : if( ! mpLayoutData )
3125 0 : ImplFillLayoutData();
3126 0 : if( mpLayoutData )
3127 : {
3128 0 : nIndex = mpLayoutData->GetIndexForPoint( rPoint );
3129 0 : for( size_t i = 0; i < mpLayoutData->m_aLineIndices.size(); i++ )
3130 : {
3131 0 : if( mpLayoutData->m_aLineIndices[i] <= nIndex &&
3132 0 : (i == mpLayoutData->m_aLineIndices.size()-1 || mpLayoutData->m_aLineIndices[i+1] > nIndex) )
3133 : {
3134 : // make index relative to item
3135 0 : nIndex -= mpLayoutData->m_aLineIndices[i];
3136 0 : rItemID = mpLayoutData->m_aLineItemIds[i];
3137 0 : break;
3138 : }
3139 : }
3140 : }
3141 0 : return nIndex;
3142 : }
3143 :
3144 0 : Rectangle Menu::GetBoundingRectangle( sal_uInt16 nPos ) const
3145 : {
3146 0 : Rectangle aRet;
3147 :
3148 0 : if( ! mpLayoutData )
3149 0 : ImplFillLayoutData();
3150 0 : if( mpLayoutData )
3151 : {
3152 0 : std::map< sal_uInt16, Rectangle >::const_iterator it = mpLayoutData->m_aVisibleItemBoundRects.find( nPos );
3153 0 : if( it != mpLayoutData->m_aVisibleItemBoundRects.end() )
3154 0 : aRet = it->second;
3155 : }
3156 0 : return aRet;
3157 : }
3158 :
3159 0 : void Menu::SetAccessibleName( sal_uInt16 nItemId, const OUString& rStr )
3160 : {
3161 : size_t nPos;
3162 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
3163 :
3164 0 : if ( pData && !rStr.equals( pData->aAccessibleName ) )
3165 : {
3166 0 : pData->aAccessibleName = rStr;
3167 0 : ImplCallEventListeners( VCLEVENT_MENU_ACCESSIBLENAMECHANGED, nPos );
3168 : }
3169 0 : }
3170 :
3171 0 : OUString Menu::GetAccessibleName( sal_uInt16 nItemId ) const
3172 : {
3173 0 : MenuItemData* pData = pItemList->GetData( nItemId );
3174 :
3175 0 : if ( pData )
3176 0 : return pData->aAccessibleName;
3177 :
3178 0 : return OUString();
3179 : }
3180 :
3181 0 : void Menu::ImplSetSalMenu( SalMenu *pSalMenu )
3182 : {
3183 0 : if( mpSalMenu )
3184 0 : ImplGetSVData()->mpDefInst->DestroyMenu( mpSalMenu );
3185 0 : mpSalMenu = pSalMenu;
3186 0 : }
3187 :
3188 0 : bool Menu::GetSystemMenuData( SystemMenuData* pData ) const
3189 : {
3190 0 : Menu* pMenu = (Menu*)this;
3191 0 : if( pData && pMenu->ImplGetSalMenu() )
3192 : {
3193 0 : pMenu->ImplGetSalMenu()->GetSystemMenuData( pData );
3194 0 : return true;
3195 : }
3196 : else
3197 0 : return false;
3198 : }
3199 :
3200 0 : bool Menu::IsHighlighted( sal_uInt16 nItemPos ) const
3201 : {
3202 0 : bool bRet = false;
3203 :
3204 0 : if( pWindow )
3205 : {
3206 0 : if( bIsMenuBar )
3207 0 : bRet = ( nItemPos == static_cast< MenuBarWindow * > (pWindow)->GetHighlightedItem() );
3208 : else
3209 0 : bRet = ( nItemPos == static_cast< MenuFloatingWindow * > (pWindow)->GetHighlightedItem() );
3210 : }
3211 :
3212 0 : return bRet;
3213 : }
3214 :
3215 0 : void Menu::HighlightItem( sal_uInt16 nItemPos )
3216 : {
3217 0 : if ( pWindow )
3218 : {
3219 0 : if ( bIsMenuBar )
3220 : {
3221 0 : MenuBarWindow* pMenuWin = static_cast< MenuBarWindow* >( pWindow );
3222 0 : pMenuWin->SetAutoPopup( false );
3223 0 : pMenuWin->ChangeHighlightItem( nItemPos, false );
3224 : }
3225 : else
3226 : {
3227 0 : static_cast< MenuFloatingWindow* >( pWindow )->ChangeHighlightItem( nItemPos, false );
3228 : }
3229 : }
3230 0 : }
3231 :
3232 : // - MenuBar -
3233 :
3234 0 : MenuBar::MenuBar() : Menu( true )
3235 : {
3236 0 : mbDisplayable = true;
3237 0 : mbCloserVisible = false;
3238 0 : mbFloatBtnVisible = false;
3239 0 : mbHideBtnVisible = false;
3240 0 : }
3241 :
3242 0 : MenuBar::MenuBar( const MenuBar& rMenu ) : Menu( true )
3243 : {
3244 0 : mbDisplayable = true;
3245 0 : mbCloserVisible = false;
3246 0 : mbFloatBtnVisible = false;
3247 0 : mbHideBtnVisible = false;
3248 0 : *this = rMenu;
3249 0 : bIsMenuBar = true;
3250 0 : }
3251 :
3252 0 : MenuBar::~MenuBar()
3253 : {
3254 0 : ImplDestroy( this, true );
3255 0 : }
3256 :
3257 0 : void MenuBar::ShowCloser( bool bShow )
3258 : {
3259 0 : ShowButtons( bShow, mbFloatBtnVisible, mbHideBtnVisible );
3260 0 : }
3261 :
3262 0 : void MenuBar::ShowButtons( bool bClose, bool bFloat, bool bHide )
3263 : {
3264 0 : if ( (bClose != mbCloserVisible) ||
3265 0 : (bFloat != mbFloatBtnVisible) ||
3266 0 : (bHide != mbHideBtnVisible) )
3267 : {
3268 0 : mbCloserVisible = bClose;
3269 0 : mbFloatBtnVisible = bFloat;
3270 0 : mbHideBtnVisible = bHide;
3271 0 : if ( ImplGetWindow() )
3272 0 : ((MenuBarWindow*)ImplGetWindow())->ShowButtons( bClose, bFloat, bHide );
3273 : }
3274 0 : }
3275 :
3276 0 : void MenuBar::SetDisplayable( bool bDisplayable )
3277 : {
3278 0 : if( bDisplayable != mbDisplayable )
3279 : {
3280 0 : mbDisplayable = bDisplayable;
3281 0 : MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow();
3282 0 : if( pMenuWin )
3283 0 : pMenuWin->ImplLayoutChanged();
3284 : }
3285 0 : }
3286 :
3287 0 : Window* MenuBar::ImplCreate( Window* pParent, Window* pWindow, MenuBar* pMenu )
3288 : {
3289 0 : if ( !pWindow )
3290 0 : pWindow = new MenuBarWindow( pParent );
3291 :
3292 0 : pMenu->pStartedFrom = 0;
3293 0 : pMenu->pWindow = pWindow;
3294 0 : ((MenuBarWindow*)pWindow)->SetMenu( pMenu );
3295 0 : long nHeight = pMenu->ImplCalcSize( pWindow ).Height();
3296 :
3297 : // depending on the native implementation or the displayable flag
3298 : // the menubar windows is supressed (ie, height=0)
3299 0 : if( !((MenuBar*) pMenu)->IsDisplayable() ||
3300 0 : ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) )
3301 0 : nHeight = 0;
3302 :
3303 0 : pWindow->setPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT );
3304 0 : return pWindow;
3305 : }
3306 :
3307 0 : void MenuBar::ImplDestroy( MenuBar* pMenu, bool bDelete )
3308 : {
3309 0 : MenuBarWindow* pWindow = (MenuBarWindow*) pMenu->ImplGetWindow();
3310 0 : if ( pWindow && bDelete )
3311 : {
3312 0 : pWindow->KillActivePopup();
3313 0 : delete pWindow;
3314 : }
3315 0 : pMenu->pWindow = NULL;
3316 0 : }
3317 :
3318 0 : bool MenuBar::ImplHandleKeyEvent( const KeyEvent& rKEvent, bool bFromMenu )
3319 : {
3320 0 : bool bDone = false;
3321 :
3322 : // No keyboard processing when system handles the menu or our menubar is invisible
3323 0 : if( !IsDisplayable() ||
3324 0 : ( ImplGetSalMenu() && ImplGetSalMenu()->VisibleMenuBar() ) )
3325 0 : return bDone;
3326 :
3327 : // check for enabled, if this method is called from another window...
3328 0 : Window* pWin = ImplGetWindow();
3329 0 : if ( pWin && pWin->IsEnabled() && pWin->IsInputEnabled() && ! pWin->IsInModalMode() )
3330 0 : bDone = ((MenuBarWindow*)pWin)->ImplHandleKeyEvent( rKEvent, bFromMenu );
3331 0 : return bDone;
3332 : }
3333 :
3334 0 : void MenuBar::SelectEntry( sal_uInt16 nId )
3335 : {
3336 0 : MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow();
3337 :
3338 0 : if( pMenuWin )
3339 : {
3340 0 : pMenuWin->GrabFocus();
3341 0 : nId = GetItemPos( nId );
3342 :
3343 : // #99705# popup the selected menu
3344 0 : pMenuWin->SetAutoPopup( true );
3345 0 : if( ITEMPOS_INVALID != pMenuWin->nHighlightedItem )
3346 : {
3347 0 : pMenuWin->KillActivePopup();
3348 0 : pMenuWin->ChangeHighlightItem( ITEMPOS_INVALID, false );
3349 : }
3350 0 : if( nId != ITEMPOS_INVALID )
3351 0 : pMenuWin->ChangeHighlightItem( nId, false );
3352 : }
3353 0 : }
3354 :
3355 : // handler for native menu selection and command events
3356 :
3357 0 : bool MenuBar::HandleMenuActivateEvent( Menu *pMenu ) const
3358 : {
3359 0 : if( pMenu )
3360 : {
3361 0 : ImplMenuDelData aDelData( this );
3362 :
3363 0 : pMenu->pStartedFrom = (Menu*)this;
3364 0 : pMenu->bInCallback = true;
3365 0 : pMenu->Activate();
3366 :
3367 0 : if( !aDelData.isDeleted() )
3368 0 : pMenu->bInCallback = false;
3369 : }
3370 0 : return true;
3371 : }
3372 :
3373 0 : bool MenuBar::HandleMenuDeActivateEvent( Menu *pMenu ) const
3374 : {
3375 0 : if( pMenu )
3376 : {
3377 0 : ImplMenuDelData aDelData( this );
3378 :
3379 0 : pMenu->pStartedFrom = (Menu*)this;
3380 0 : pMenu->bInCallback = true;
3381 0 : pMenu->Deactivate();
3382 0 : if( !aDelData.isDeleted() )
3383 0 : pMenu->bInCallback = false;
3384 : }
3385 0 : return true;
3386 : }
3387 :
3388 0 : bool MenuBar::HandleMenuHighlightEvent( Menu *pMenu, sal_uInt16 nHighlightEventId ) const
3389 : {
3390 0 : if( !pMenu )
3391 0 : pMenu = ((Menu*) this)->ImplFindMenu( nHighlightEventId );
3392 0 : if( pMenu )
3393 : {
3394 0 : ImplMenuDelData aDelData( pMenu );
3395 :
3396 0 : if( mnHighlightedItemPos != ITEMPOS_INVALID )
3397 0 : pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, mnHighlightedItemPos );
3398 :
3399 0 : if( !aDelData.isDeleted() )
3400 : {
3401 0 : pMenu->mnHighlightedItemPos = pMenu->GetItemPos( nHighlightEventId );
3402 0 : pMenu->nSelectedId = nHighlightEventId;
3403 0 : pMenu->pStartedFrom = (Menu*)this;
3404 0 : pMenu->ImplCallHighlight( pMenu->mnHighlightedItemPos );
3405 : }
3406 0 : return true;
3407 : }
3408 : else
3409 0 : return false;
3410 : }
3411 :
3412 0 : bool MenuBar::HandleMenuCommandEvent( Menu *pMenu, sal_uInt16 nCommandEventId ) const
3413 : {
3414 0 : if( !pMenu )
3415 0 : pMenu = ((Menu*) this)->ImplFindMenu( nCommandEventId );
3416 0 : if( pMenu )
3417 : {
3418 0 : pMenu->nSelectedId = nCommandEventId;
3419 0 : pMenu->pStartedFrom = (Menu*)this;
3420 0 : pMenu->ImplSelect();
3421 0 : return true;
3422 : }
3423 : else
3424 0 : return false;
3425 : }
3426 :
3427 0 : sal_uInt16 MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const OUString& i_rToolTip, sal_uInt16 i_nPos )
3428 : {
3429 0 : return pWindow ? static_cast<MenuBarWindow*>(pWindow)->AddMenuBarButton( i_rImage, i_rLink, i_rToolTip, i_nPos ) : 0;
3430 : }
3431 :
3432 0 : void MenuBar::SetMenuBarButtonHighlightHdl( sal_uInt16 nId, const Link& rLink )
3433 : {
3434 0 : if( pWindow )
3435 0 : static_cast<MenuBarWindow*>(pWindow)->SetMenuBarButtonHighlightHdl( nId, rLink );
3436 0 : }
3437 :
3438 0 : Rectangle MenuBar::GetMenuBarButtonRectPixel( sal_uInt16 nId )
3439 : {
3440 0 : return pWindow ? static_cast<MenuBarWindow*>(pWindow)->GetMenuBarButtonRectPixel( nId ) : Rectangle();
3441 : }
3442 :
3443 0 : void MenuBar::RemoveMenuBarButton( sal_uInt16 nId )
3444 : {
3445 0 : if( pWindow )
3446 0 : static_cast<MenuBarWindow*>(pWindow)->RemoveMenuBarButton( nId );
3447 0 : }
3448 :
3449 0 : bool MenuBar::HandleMenuButtonEvent( Menu *, sal_uInt16 i_nButtonId ) const
3450 : {
3451 0 : return static_cast<MenuBarWindow*>(pWindow)->HandleMenuButtonEvent( i_nButtonId );
3452 : }
3453 :
3454 : // bool PopupMenu::bAnyPopupInExecute = false;
3455 :
3456 0 : PopupMenu::PopupMenu()
3457 : {
3458 0 : pRefAutoSubMenu = NULL;
3459 0 : }
3460 :
3461 0 : PopupMenu::PopupMenu( const ResId& rResId )
3462 : {
3463 0 : pRefAutoSubMenu = NULL;
3464 0 : ImplLoadRes( rResId );
3465 0 : }
3466 :
3467 0 : PopupMenu::PopupMenu( const PopupMenu& rMenu ) : Menu()
3468 : {
3469 0 : pRefAutoSubMenu = NULL;
3470 0 : *this = rMenu;
3471 0 : }
3472 :
3473 0 : PopupMenu::~PopupMenu()
3474 : {
3475 0 : if( pRefAutoSubMenu && *pRefAutoSubMenu == this )
3476 0 : *pRefAutoSubMenu = NULL; // #111060# avoid second delete in ~MenuItemData
3477 0 : }
3478 :
3479 0 : bool PopupMenu::IsInExecute()
3480 : {
3481 0 : return GetActivePopupMenu() ? true : false;
3482 : }
3483 :
3484 0 : PopupMenu* PopupMenu::GetActivePopupMenu()
3485 : {
3486 0 : ImplSVData* pSVData = ImplGetSVData();
3487 0 : return pSVData->maAppData.mpActivePopupMenu;
3488 : }
3489 :
3490 0 : void PopupMenu::EndExecute( sal_uInt16 nSelectId )
3491 : {
3492 0 : if ( ImplGetWindow() )
3493 0 : ImplGetFloatingWindow()->EndExecute( nSelectId );
3494 0 : }
3495 :
3496 0 : void PopupMenu::SelectEntry( sal_uInt16 nId )
3497 : {
3498 0 : if ( ImplGetWindow() )
3499 : {
3500 0 : if( nId != ITEMPOS_INVALID )
3501 : {
3502 0 : size_t nPos = 0;
3503 0 : MenuItemData* pData = GetItemList()->GetData( nId, nPos );
3504 0 : if (pData && pData->pSubMenu)
3505 0 : ImplGetFloatingWindow()->ChangeHighlightItem( nPos, true );
3506 : else
3507 0 : ImplGetFloatingWindow()->EndExecute( nId );
3508 : }
3509 : else
3510 : {
3511 0 : MenuFloatingWindow* pFloat = ImplGetFloatingWindow();
3512 0 : pFloat->GrabFocus();
3513 :
3514 0 : for( size_t nPos = 0; nPos < GetItemList()->size(); nPos++ )
3515 : {
3516 0 : MenuItemData* pData = GetItemList()->GetDataFromPos( nPos );
3517 0 : if( pData->pSubMenu )
3518 : {
3519 0 : pFloat->KillActivePopup();
3520 : }
3521 : }
3522 0 : pFloat->ChangeHighlightItem( ITEMPOS_INVALID, false );
3523 : }
3524 : }
3525 0 : }
3526 :
3527 0 : void PopupMenu::SetSelectedEntry( sal_uInt16 nId )
3528 : {
3529 0 : nSelectedId = nId;
3530 0 : }
3531 :
3532 0 : sal_uInt16 PopupMenu::Execute( Window* pExecWindow, const Point& rPopupPos )
3533 : {
3534 0 : return Execute( pExecWindow, Rectangle( rPopupPos, rPopupPos ), POPUPMENU_EXECUTE_DOWN );
3535 : }
3536 :
3537 0 : sal_uInt16 PopupMenu::Execute( Window* pExecWindow, const Rectangle& rRect, sal_uInt16 nFlags )
3538 : {
3539 0 : ENSURE_OR_RETURN( pExecWindow, "PopupMenu::Execute: need a non-NULL window!", 0 );
3540 :
3541 0 : sal_uLong nPopupModeFlags = 0;
3542 0 : if ( nFlags & POPUPMENU_EXECUTE_DOWN )
3543 0 : nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
3544 0 : else if ( nFlags & POPUPMENU_EXECUTE_UP )
3545 0 : nPopupModeFlags = FLOATWIN_POPUPMODE_UP;
3546 0 : else if ( nFlags & POPUPMENU_EXECUTE_LEFT )
3547 0 : nPopupModeFlags = FLOATWIN_POPUPMODE_LEFT;
3548 0 : else if ( nFlags & POPUPMENU_EXECUTE_RIGHT )
3549 0 : nPopupModeFlags = FLOATWIN_POPUPMODE_RIGHT;
3550 : else
3551 0 : nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
3552 :
3553 0 : if (nFlags & POPUPMENU_NOMOUSEUPCLOSE ) // allow popup menus to stay open on mouse button up
3554 0 : nPopupModeFlags |= FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE; // useful if the menu was opened on mousebutton down (eg toolbox configuration)
3555 :
3556 0 : if (nFlags & POPUPMENU_NOHORZ_PLACEMENT)
3557 0 : nPopupModeFlags |= FLOATWIN_POPUPMODE_NOHORZPLACEMENT;
3558 :
3559 0 : return ImplExecute( pExecWindow, rRect, nPopupModeFlags, 0, false );
3560 : }
3561 :
3562 0 : sal_uInt16 PopupMenu::ImplExecute( Window* pW, const Rectangle& rRect, sal_uLong nPopupModeFlags, Menu* pSFrom, bool bPreSelectFirst )
3563 : {
3564 0 : if ( !pSFrom && ( PopupMenu::IsInExecute() || !GetItemCount() ) )
3565 0 : return 0;
3566 :
3567 0 : delete mpLayoutData, mpLayoutData = NULL;
3568 :
3569 0 : ImplSVData* pSVData = ImplGetSVData();
3570 :
3571 0 : pStartedFrom = pSFrom;
3572 0 : nSelectedId = 0;
3573 0 : bCanceled = false;
3574 :
3575 0 : sal_uLong nFocusId = 0;
3576 0 : bool bRealExecute = false;
3577 0 : if ( !pStartedFrom )
3578 : {
3579 0 : pSVData->maWinData.mbNoDeactivate = true;
3580 0 : nFocusId = Window::SaveFocus();
3581 0 : bRealExecute = true;
3582 : }
3583 : else
3584 : {
3585 : // assure that only one menu is open at a time
3586 0 : if( pStartedFrom->bIsMenuBar && pSVData->maWinData.mpFirstFloat )
3587 0 : pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
3588 : }
3589 :
3590 : DBG_ASSERT( !ImplGetWindow(), "Win?!" );
3591 0 : Rectangle aRect( rRect );
3592 0 : aRect.SetPos( pW->OutputToScreenPixel( aRect.TopLeft() ) );
3593 :
3594 0 : WinBits nStyle = WB_BORDER;
3595 0 : if ( bRealExecute )
3596 0 : nPopupModeFlags |= FLOATWIN_POPUPMODE_NEWLEVEL;
3597 0 : if ( !pStartedFrom || !pStartedFrom->bIsMenuBar )
3598 0 : nPopupModeFlags |= FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK | FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE;
3599 :
3600 0 : nPopupModeFlags |= FLOATWIN_POPUPMODE_NOKEYCLOSE;
3601 :
3602 : // could be useful during debugging.
3603 : // nPopupModeFlags |= FLOATWIN_POPUPMODE_NOFOCUSCLOSE;
3604 :
3605 0 : ImplDelData aDelData;
3606 0 : pW->ImplAddDel( &aDelData );
3607 :
3608 0 : bInCallback = true; // set it here, if Activate overloaded
3609 0 : Activate();
3610 0 : bInCallback = false;
3611 :
3612 0 : if ( aDelData.IsDead() )
3613 0 : return 0; // Error
3614 :
3615 0 : pW->ImplRemoveDel( &aDelData );
3616 :
3617 0 : if ( bCanceled || bKilled )
3618 0 : return 0;
3619 :
3620 0 : if ( !GetItemCount() )
3621 0 : return 0;
3622 :
3623 : // The flag MENU_FLAG_HIDEDISABLEDENTRIES is inherited.
3624 0 : if ( pSFrom )
3625 : {
3626 0 : if ( pSFrom->nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES )
3627 0 : nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES;
3628 : else
3629 0 : nMenuFlags &= ~MENU_FLAG_HIDEDISABLEDENTRIES;
3630 : }
3631 : else
3632 : // #102790# context menus shall never show disabled entries
3633 0 : nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES;
3634 :
3635 0 : sal_uInt16 nVisibleEntries = ImplGetVisibleItemCount();
3636 0 : if ( !nVisibleEntries )
3637 : {
3638 0 : ResMgr* pResMgr = ImplGetResMgr();
3639 0 : if( pResMgr )
3640 : {
3641 0 : OUString aTmpEntryText( ResId( SV_RESID_STRING_NOSELECTIONPOSSIBLE, *pResMgr ) );
3642 : MenuItemData* pData = pItemList->Insert(
3643 0 : 0xFFFF, MENUITEM_STRING, 0, aTmpEntryText, Image(), NULL, 0xFFFF, OString() );
3644 0 : size_t nPos = 0;
3645 0 : pData = pItemList->GetData( pData->nId, nPos );
3646 : assert(pData);
3647 0 : pData->bIsTemporary = true;
3648 0 : ImplCallEventListeners(VCLEVENT_MENU_SUBMENUCHANGED, nPos);
3649 : }
3650 : }
3651 0 : else if ( Application::GetSettings().GetStyleSettings().GetAutoMnemonic() && !( nMenuFlags & MENU_FLAG_NOAUTOMNEMONICS ) )
3652 : {
3653 0 : CreateAutoMnemonics();
3654 : }
3655 :
3656 0 : MenuFloatingWindow* pWin = new MenuFloatingWindow( this, pW, nStyle | WB_SYSTEMWINDOW );
3657 0 : if( pSVData->maNWFData.mbFlatMenu )
3658 0 : pWin->SetBorderStyle( WINDOW_BORDER_NOBORDER );
3659 : else
3660 0 : pWin->SetBorderStyle( pWin->GetBorderStyle() | WINDOW_BORDER_MENU );
3661 0 : pWindow = pWin;
3662 :
3663 0 : Size aSz = ImplCalcSize( pWin );
3664 :
3665 0 : Rectangle aDesktopRect(pWin->GetDesktopRectPixel());
3666 0 : if( Application::GetScreenCount() > 1 && Application::IsUnifiedDisplay() )
3667 : {
3668 0 : Window* pDeskW = pWindow->GetWindow( WINDOW_REALPARENT );
3669 0 : if( ! pDeskW )
3670 0 : pDeskW = pWindow;
3671 0 : Point aDesktopTL( pDeskW->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) );
3672 : aDesktopRect = Application::GetScreenPosSizePixel(
3673 0 : Application::GetBestScreen( Rectangle( aDesktopTL, aRect.GetSize() ) ));
3674 : }
3675 :
3676 0 : long nMaxHeight = aDesktopRect.GetHeight();
3677 :
3678 : //rhbz#1021915. If a menu won't fit in the desired location the default
3679 : //mode is to place it somewhere it will fit. e.g. above, left, right. For
3680 : //some cases, e.g. menubars, it's desirable to limit the options to
3681 : //above/below and force the menu to scroll if it won't fit
3682 0 : if (nPopupModeFlags & FLOATWIN_POPUPMODE_NOHORZPLACEMENT)
3683 : {
3684 0 : Window* pRef = pWin;
3685 0 : if ( pRef->GetParent() )
3686 0 : pRef = pRef->GetParent();
3687 :
3688 0 : Rectangle devRect( pRef->OutputToAbsoluteScreenPixel( aRect.TopLeft() ),
3689 0 : pRef->OutputToAbsoluteScreenPixel( aRect.BottomRight() ) );
3690 :
3691 0 : long nHeightAbove = devRect.Top() - aDesktopRect.Top();
3692 0 : long nHeightBelow = aDesktopRect.Bottom() - devRect.Bottom();
3693 0 : nMaxHeight = std::min(nMaxHeight, std::max(nHeightAbove, nHeightBelow));
3694 : }
3695 :
3696 0 : if ( pStartedFrom && pStartedFrom->bIsMenuBar )
3697 0 : nMaxHeight -= pW->GetSizePixel().Height();
3698 : sal_Int32 nLeft, nTop, nRight, nBottom;
3699 0 : pWindow->GetBorder( nLeft, nTop, nRight, nBottom );
3700 0 : nMaxHeight -= nTop+nBottom;
3701 0 : if ( aSz.Height() > nMaxHeight )
3702 : {
3703 0 : pWin->EnableScrollMenu( true );
3704 0 : sal_uInt16 nStart = ImplGetFirstVisible();
3705 0 : sal_uInt16 nEntries = ImplCalcVisEntries( nMaxHeight, nStart );
3706 0 : aSz.Height() = ImplCalcHeight( nEntries );
3707 : }
3708 :
3709 0 : pWin->SetFocusId( nFocusId );
3710 0 : pWin->SetOutputSizePixel( aSz );
3711 : // #102158# menus must never grab the focus, otherwise
3712 : // they will be closed immediately
3713 : // from now on focus grabbing is only prohibited automatically if
3714 : // FLOATWIN_POPUPMODE_GRABFOCUS was set (which is done below), because some
3715 : // floaters (like floating toolboxes) may grab the focus
3716 : // pWin->GrabFocus();
3717 0 : if ( GetItemCount() )
3718 : {
3719 0 : SalMenu* pMenu = ImplGetSalMenu();
3720 0 : if( pMenu && bRealExecute && pMenu->ShowNativePopupMenu( pWin, aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS ) )
3721 : {
3722 0 : pWin->StopExecute(0);
3723 0 : pWin->doShutdown();
3724 0 : pWindow->doLazyDelete();
3725 0 : pWindow = NULL;
3726 0 : return nSelectedId;
3727 : }
3728 : else
3729 : {
3730 0 : pWin->StartPopupMode( aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS );
3731 : }
3732 0 : if( pSFrom )
3733 : {
3734 : sal_uInt16 aPos;
3735 0 : if( pSFrom->bIsMenuBar )
3736 0 : aPos = ((MenuBarWindow *) pSFrom->pWindow)->GetHighlightedItem();
3737 : else
3738 0 : aPos = ((MenuFloatingWindow *) pSFrom->pWindow)->GetHighlightedItem();
3739 :
3740 0 : pWin->SetPosInParent( aPos ); // store position to be sent in SUBMENUDEACTIVATE
3741 0 : pSFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUACTIVATE, aPos );
3742 : }
3743 : }
3744 0 : if ( bPreSelectFirst )
3745 : {
3746 0 : size_t nCount = pItemList->size();
3747 0 : for ( size_t n = 0; n < nCount; n++ )
3748 : {
3749 0 : MenuItemData* pData = pItemList->GetDataFromPos( n );
3750 0 : if ( ( pData->bEnabled
3751 0 : || !Application::GetSettings().GetStyleSettings().GetSkipDisabledInMenus()
3752 : )
3753 0 : && ( pData->eType != MENUITEM_SEPARATOR )
3754 0 : && ImplIsVisible( n )
3755 0 : && ImplIsSelectable( n )
3756 : )
3757 : {
3758 0 : pWin->ChangeHighlightItem( n, false );
3759 0 : break;
3760 : }
3761 : }
3762 : }
3763 0 : if ( bRealExecute )
3764 : {
3765 0 : pWin->ImplAddDel( &aDelData );
3766 :
3767 0 : ImplDelData aModalWinDel;
3768 0 : pW->ImplAddDel( &aModalWinDel );
3769 0 : pW->ImplIncModalCount();
3770 :
3771 0 : pWin->Execute();
3772 :
3773 : DBG_ASSERT( ! aModalWinDel.IsDead(), "window for popup died, modal count incorrect !" );
3774 0 : if( ! aModalWinDel.IsDead() )
3775 0 : pW->ImplDecModalCount();
3776 :
3777 0 : if ( !aDelData.IsDead() )
3778 0 : pWin->ImplRemoveDel( &aDelData );
3779 : else
3780 0 : return 0;
3781 :
3782 : // Restore focus (could already have been
3783 : // restored in Select)
3784 0 : nFocusId = pWin->GetFocusId();
3785 0 : if ( nFocusId )
3786 : {
3787 0 : pWin->SetFocusId( 0 );
3788 0 : pSVData->maWinData.mbNoDeactivate = false;
3789 : }
3790 0 : pWin->ImplEndPopupMode( 0, nFocusId );
3791 :
3792 0 : if ( nSelectedId ) // then clean up .. ( otherwise done by TH )
3793 : {
3794 0 : PopupMenu* pSub = pWin->GetActivePopup();
3795 0 : while ( pSub )
3796 : {
3797 0 : pSub->ImplGetFloatingWindow()->EndPopupMode();
3798 0 : pSub = pSub->ImplGetFloatingWindow()->GetActivePopup();
3799 : }
3800 : }
3801 0 : pWin->doShutdown();
3802 0 : pWindow->doLazyDelete();
3803 0 : pWindow = NULL;
3804 :
3805 : // is there still Select?
3806 0 : Menu* pSelect = ImplFindSelectMenu();
3807 0 : if ( pSelect )
3808 : {
3809 : // Select should be called prior to leaving execute in a popup menu!
3810 0 : Application::RemoveUserEvent( pSelect->nEventId );
3811 0 : pSelect->nEventId = 0;
3812 0 : pSelect->Select();
3813 0 : }
3814 : }
3815 :
3816 0 : return bRealExecute ? nSelectedId : 0;
3817 : }
3818 :
3819 0 : sal_uInt16 PopupMenu::ImplCalcVisEntries( long nMaxHeight, sal_uInt16 nStartEntry, sal_uInt16* pLastVisible ) const
3820 : {
3821 0 : nMaxHeight -= 2 * ImplGetFloatingWindow()->GetScrollerHeight();
3822 :
3823 0 : long nHeight = 0;
3824 0 : size_t nEntries = pItemList->size();
3825 0 : sal_uInt16 nVisEntries = 0;
3826 :
3827 0 : if ( pLastVisible )
3828 0 : *pLastVisible = 0;
3829 :
3830 0 : for ( size_t n = nStartEntry; n < nEntries; n++ )
3831 : {
3832 0 : if ( ImplIsVisible( n ) )
3833 : {
3834 0 : MenuItemData* pData = pItemList->GetDataFromPos( n );
3835 0 : nHeight += pData->aSz.Height();
3836 0 : if ( nHeight > nMaxHeight )
3837 0 : break;
3838 :
3839 0 : if ( pLastVisible )
3840 0 : *pLastVisible = n;
3841 0 : nVisEntries++;
3842 : }
3843 : }
3844 0 : return nVisEntries;
3845 : }
3846 :
3847 0 : long PopupMenu::ImplCalcHeight( sal_uInt16 nEntries ) const
3848 : {
3849 0 : long nHeight = 0;
3850 :
3851 0 : sal_uInt16 nFound = 0;
3852 0 : for ( size_t n = 0; ( nFound < nEntries ) && ( n < pItemList->size() ); n++ )
3853 : {
3854 0 : if ( ImplIsVisible( (sal_uInt16) n ) )
3855 : {
3856 0 : MenuItemData* pData = pItemList->GetDataFromPos( n );
3857 0 : nHeight += pData->aSz.Height();
3858 0 : nFound++;
3859 : }
3860 : }
3861 :
3862 0 : nHeight += 2*ImplGetFloatingWindow()->GetScrollerHeight();
3863 :
3864 0 : return nHeight;
3865 : }
3866 :
3867 0 : static void ImplInitMenuWindow( Window* pWin, bool bFont, bool bMenuBar )
3868 : {
3869 0 : const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
3870 :
3871 0 : if ( bFont )
3872 0 : pWin->SetPointFont( rStyleSettings.GetMenuFont() );
3873 0 : if( bMenuBar )
3874 : {
3875 0 : const BitmapEx& rPersonaBitmap = Application::GetSettings().GetStyleSettings().GetPersonaHeader();
3876 0 : if ( !rPersonaBitmap.IsEmpty() )
3877 : {
3878 0 : Wallpaper aWallpaper( rPersonaBitmap );
3879 0 : aWallpaper.SetStyle( WALLPAPER_TOPRIGHT );
3880 0 : aWallpaper.SetColor( Application::GetSettings().GetStyleSettings().GetWorkspaceColor() );
3881 :
3882 0 : pWin->SetBackground( aWallpaper );
3883 0 : pWin->SetPaintTransparent( false );
3884 0 : pWin->SetParentClipMode( 0 );
3885 : }
3886 0 : else if ( pWin->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
3887 : {
3888 0 : pWin->SetBackground(); // background will be drawn by NWF
3889 : }
3890 : else
3891 : {
3892 0 : Wallpaper aWallpaper;
3893 0 : aWallpaper.SetStyle( WALLPAPER_APPLICATIONGRADIENT );
3894 0 : pWin->SetBackground( aWallpaper );
3895 0 : pWin->SetPaintTransparent( false );
3896 0 : pWin->SetParentClipMode( 0 );
3897 0 : }
3898 : }
3899 : else
3900 : {
3901 0 : if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
3902 : {
3903 0 : pWin->SetBackground(); // background will be drawn by NWF
3904 : }
3905 : else
3906 0 : pWin->SetBackground( Wallpaper( rStyleSettings.GetMenuColor() ) );
3907 : }
3908 :
3909 0 : if ( bMenuBar )
3910 0 : pWin->SetTextColor( rStyleSettings.GetMenuBarTextColor() );
3911 : else
3912 0 : pWin->SetTextColor( rStyleSettings.GetMenuTextColor() );
3913 0 : pWin->SetTextFillColor();
3914 0 : pWin->SetLineColor();
3915 0 : }
3916 :
3917 0 : MenuFloatingWindow::MenuFloatingWindow( Menu* pMen, Window* pParent, WinBits nStyle ) :
3918 0 : FloatingWindow( pParent, nStyle )
3919 : {
3920 0 : mpWindowImpl->mbMenuFloatingWindow= true;
3921 0 : pMenu = pMen;
3922 0 : pActivePopup = 0;
3923 0 : nSaveFocusId = 0;
3924 0 : bInExecute = false;
3925 0 : bScrollMenu = false;
3926 0 : nHighlightedItem = ITEMPOS_INVALID;
3927 0 : nMBDownPos = ITEMPOS_INVALID;
3928 0 : nPosInParent = ITEMPOS_INVALID;
3929 0 : nScrollerHeight = 0;
3930 0 : nBorder = EXTRASPACEY;
3931 0 : nFirstEntry = 0;
3932 0 : bScrollUp = false;
3933 0 : bScrollDown = false;
3934 0 : bIgnoreFirstMove = true;
3935 0 : bKeyInput = false;
3936 :
3937 0 : EnableSaveBackground();
3938 0 : ImplInitMenuWindow( this, true, false );
3939 :
3940 0 : SetPopupModeEndHdl( LINK( this, MenuFloatingWindow, PopupEnd ) );
3941 :
3942 0 : aHighlightChangedTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, HighlightChanged ) );
3943 0 : aHighlightChangedTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() );
3944 0 : aSubmenuCloseTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() );
3945 0 : aSubmenuCloseTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, SubmenuClose ) );
3946 0 : aScrollTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, AutoScroll ) );
3947 :
3948 0 : AddEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) );
3949 0 : }
3950 :
3951 0 : void MenuFloatingWindow::doShutdown()
3952 : {
3953 0 : if( pMenu )
3954 : {
3955 : // #105373# notify toolkit that highlight was removed
3956 : // otherwise the entry will not be read when the menu is opened again
3957 0 : if( nHighlightedItem != ITEMPOS_INVALID )
3958 0 : pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
3959 0 : pMenu->SetHighlightItem(ITEMPOS_INVALID);
3960 0 : if( !bKeyInput && pMenu && pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
3961 : {
3962 : // #102461# remove highlight in parent
3963 : MenuItemData* pData;
3964 0 : size_t i, nCount = pMenu->pStartedFrom->pItemList->size();
3965 0 : for(i = 0; i < nCount; i++)
3966 : {
3967 0 : pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i );
3968 0 : if( pData && ( pData->pSubMenu == pMenu ) )
3969 0 : break;
3970 : }
3971 0 : if( i < nCount )
3972 : {
3973 0 : MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow();
3974 0 : if( pPWin )
3975 0 : pPWin->HighlightItem( i, false );
3976 : }
3977 : }
3978 :
3979 : // free the reference to the accessible component
3980 0 : SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() );
3981 :
3982 0 : aHighlightChangedTimer.Stop();
3983 :
3984 : // #95056# invalidate screen area covered by system window
3985 : // so this can be taken into account if the commandhandler performs a scroll operation
3986 0 : if( GetParent() )
3987 : {
3988 0 : Rectangle aInvRect( GetWindowExtentsRelative( GetParent() ) );
3989 0 : GetParent()->Invalidate( aInvRect );
3990 : }
3991 0 : pMenu = NULL;
3992 0 : RemoveEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) );
3993 : }
3994 0 : }
3995 :
3996 0 : MenuFloatingWindow::~MenuFloatingWindow()
3997 : {
3998 0 : doShutdown();
3999 0 : }
4000 :
4001 0 : void MenuFloatingWindow::Resize()
4002 : {
4003 0 : ImplInitClipRegion();
4004 0 : }
4005 :
4006 0 : long MenuFloatingWindow::ImplGetStartY() const
4007 : {
4008 0 : long nY = 0;
4009 0 : if( pMenu )
4010 : {
4011 0 : for ( sal_uInt16 n = 0; n < nFirstEntry; n++ )
4012 0 : nY += pMenu->GetItemList()->GetDataFromPos( n )->aSz.Height();
4013 : }
4014 0 : return -nY;
4015 : }
4016 :
4017 0 : Region MenuFloatingWindow::ImplCalcClipRegion( bool bIncludeLogo ) const
4018 : {
4019 0 : Size aOutSz = GetOutputSizePixel();
4020 0 : Point aPos;
4021 0 : Rectangle aRect( aPos, aOutSz );
4022 0 : aRect.Top() += nScrollerHeight;
4023 0 : aRect.Bottom() -= nScrollerHeight;
4024 :
4025 0 : if ( pMenu && pMenu->pLogo && !bIncludeLogo )
4026 0 : aRect.Left() += pMenu->pLogo->aBitmap.GetSizePixel().Width();
4027 :
4028 0 : Region aRegion(aRect);
4029 0 : if ( pMenu && pMenu->pLogo && bIncludeLogo && nScrollerHeight )
4030 0 : aRegion.Union( Rectangle( Point(), Size( pMenu->pLogo->aBitmap.GetSizePixel().Width(), aOutSz.Height() ) ) );
4031 :
4032 0 : return aRegion;
4033 : }
4034 :
4035 0 : void MenuFloatingWindow::ImplInitClipRegion()
4036 : {
4037 0 : if ( IsScrollMenu() )
4038 : {
4039 0 : SetClipRegion( ImplCalcClipRegion() );
4040 : }
4041 : else
4042 : {
4043 0 : SetClipRegion();
4044 : }
4045 0 : }
4046 :
4047 0 : void MenuFloatingWindow::ImplHighlightItem( const MouseEvent& rMEvt, bool bMBDown )
4048 : {
4049 0 : if( ! pMenu )
4050 0 : return;
4051 :
4052 0 : long nY = nScrollerHeight + ImplGetSVData()->maNWFData.mnMenuFormatBorderY;
4053 0 : long nMouseY = rMEvt.GetPosPixel().Y();
4054 0 : Size aOutSz = GetOutputSizePixel();
4055 0 : if ( ( nMouseY >= nY ) && ( nMouseY < ( aOutSz.Height() - nY ) ) )
4056 : {
4057 0 : bool bHighlighted = false;
4058 0 : size_t nCount = pMenu->pItemList->size();
4059 0 : nY += ImplGetStartY(); // ggf. gescrollt.
4060 0 : for ( size_t n = 0; !bHighlighted && ( n < nCount ); n++ )
4061 : {
4062 0 : if ( pMenu->ImplIsVisible( n ) )
4063 : {
4064 0 : MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( n );
4065 0 : long nOldY = nY;
4066 0 : nY += pItemData->aSz.Height();
4067 0 : if ( ( nOldY <= nMouseY ) && ( nY > nMouseY ) && pMenu->ImplIsSelectable( n ) )
4068 : {
4069 0 : bool bPopupArea = true;
4070 0 : if ( pItemData->nBits & MIB_POPUPSELECT )
4071 : {
4072 : // only when clicked over the arrow...
4073 0 : Size aSz = GetOutputSizePixel();
4074 0 : long nFontHeight = GetTextHeight();
4075 0 : bPopupArea = ( rMEvt.GetPosPixel().X() >= ( aSz.Width() - nFontHeight - nFontHeight/4 ) );
4076 : }
4077 :
4078 0 : if ( bMBDown )
4079 : {
4080 0 : if ( n != nHighlightedItem )
4081 : {
4082 0 : ChangeHighlightItem( (sal_uInt16)n, false );
4083 : }
4084 :
4085 0 : bool bAllowNewPopup = true;
4086 0 : if ( pActivePopup )
4087 : {
4088 0 : MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
4089 0 : bAllowNewPopup = pData && ( pData->pSubMenu != pActivePopup );
4090 0 : if ( bAllowNewPopup )
4091 0 : KillActivePopup();
4092 : }
4093 :
4094 0 : if ( bPopupArea && bAllowNewPopup )
4095 : {
4096 0 : HighlightChanged( NULL );
4097 : }
4098 : }
4099 : else
4100 : {
4101 0 : if ( n != nHighlightedItem )
4102 : {
4103 0 : ChangeHighlightItem( (sal_uInt16)n, true );
4104 : }
4105 0 : else if ( pItemData->nBits & MIB_POPUPSELECT )
4106 : {
4107 0 : if ( bPopupArea && ( pActivePopup != pItemData->pSubMenu ) )
4108 0 : HighlightChanged( NULL );
4109 : }
4110 : }
4111 0 : bHighlighted = true;
4112 : }
4113 : }
4114 : }
4115 0 : if ( !bHighlighted )
4116 0 : ChangeHighlightItem( ITEMPOS_INVALID, true );
4117 : }
4118 : else
4119 : {
4120 0 : ImplScroll( rMEvt.GetPosPixel() );
4121 0 : ChangeHighlightItem( ITEMPOS_INVALID, true );
4122 : }
4123 : }
4124 :
4125 0 : IMPL_LINK_NOARG(MenuFloatingWindow, PopupEnd)
4126 : {
4127 : // "this" will be deleted before the end of this method!
4128 0 : Menu* pM = pMenu;
4129 0 : if ( bInExecute )
4130 : {
4131 0 : if ( pActivePopup )
4132 : {
4133 : //DBG_ASSERT( !pActivePopup->ImplGetWindow(), "PopupEnd, obwohl pActivePopup MIT Window!" );
4134 0 : KillActivePopup(); // should be ok to just remove it
4135 : //pActivePopup->bCanceled = true;
4136 : }
4137 0 : bInExecute = false;
4138 0 : pMenu->bInCallback = true;
4139 0 : pMenu->Deactivate();
4140 0 : pMenu->bInCallback = false;
4141 : }
4142 : else
4143 : {
4144 0 : if( pMenu )
4145 : {
4146 : // if the window was closed by TH, there is another menu
4147 : // which has this window as pActivePopup
4148 0 : if ( pMenu->pStartedFrom )
4149 : {
4150 : // pWin from parent could be 0, if the list is
4151 : // cleaned from the start, now clean up the endpopup-events
4152 0 : if ( pMenu->pStartedFrom->bIsMenuBar )
4153 : {
4154 0 : MenuBarWindow* p = (MenuBarWindow*) pMenu->pStartedFrom->ImplGetWindow();
4155 0 : if ( p )
4156 0 : p->PopupClosed( pMenu );
4157 : }
4158 : else
4159 : {
4160 0 : MenuFloatingWindow* p = (MenuFloatingWindow*) pMenu->pStartedFrom->ImplGetWindow();
4161 0 : if ( p )
4162 0 : p->KillActivePopup( (PopupMenu*)pMenu );
4163 : }
4164 : }
4165 : }
4166 : }
4167 :
4168 0 : if ( pM )
4169 0 : pM->pStartedFrom = 0;
4170 :
4171 0 : return 0;
4172 : }
4173 :
4174 0 : IMPL_LINK_NOARG(MenuFloatingWindow, AutoScroll)
4175 : {
4176 0 : ImplScroll( GetPointerPosPixel() );
4177 0 : return 1;
4178 : }
4179 :
4180 0 : IMPL_LINK( MenuFloatingWindow, HighlightChanged, Timer*, pTimer )
4181 : {
4182 0 : if( ! pMenu )
4183 0 : return 0;
4184 :
4185 0 : MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
4186 0 : if ( pItemData )
4187 : {
4188 0 : if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) )
4189 : {
4190 0 : sal_uLong nOldFlags = GetPopupModeFlags();
4191 0 : SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
4192 0 : KillActivePopup();
4193 0 : SetPopupModeFlags( nOldFlags );
4194 : }
4195 0 : if ( pItemData->bEnabled && pItemData->pSubMenu && pItemData->pSubMenu->GetItemCount() && ( pItemData->pSubMenu != pActivePopup ) )
4196 : {
4197 0 : pActivePopup = (PopupMenu*)pItemData->pSubMenu;
4198 0 : long nY = nScrollerHeight+ImplGetStartY();
4199 0 : MenuItemData* pData = 0;
4200 0 : for ( sal_uLong n = 0; n < nHighlightedItem; n++ )
4201 : {
4202 0 : pData = pMenu->pItemList->GetDataFromPos( n );
4203 0 : nY += pData->aSz.Height();
4204 : }
4205 0 : pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
4206 0 : Size MySize = GetOutputSizePixel();
4207 0 : Point aItemTopLeft( 0, nY );
4208 0 : Point aItemBottomRight( aItemTopLeft );
4209 0 : aItemBottomRight.X() += MySize.Width();
4210 0 : aItemBottomRight.Y() += pData->aSz.Height();
4211 :
4212 : // shift the popups a little
4213 0 : aItemTopLeft.X() += 2;
4214 0 : aItemBottomRight.X() -= 2;
4215 0 : if ( nHighlightedItem )
4216 0 : aItemTopLeft.Y() -= 2;
4217 : else
4218 : {
4219 : sal_Int32 nL, nT, nR, nB;
4220 0 : GetBorder( nL, nT, nR, nB );
4221 0 : aItemTopLeft.Y() -= nT;
4222 : }
4223 :
4224 : // pTest: crash due to Reschedule() in call of Activate()
4225 : // Also it is prevented that submenus are displayed which
4226 : // were for long in Activate Rescheduled and which should not be
4227 : // displayed now.
4228 0 : Menu* pTest = pActivePopup;
4229 0 : sal_uLong nOldFlags = GetPopupModeFlags();
4230 0 : SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
4231 0 : sal_uInt16 nRet = pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_RIGHT, pMenu, pTimer ? false : true );
4232 0 : SetPopupModeFlags( nOldFlags );
4233 :
4234 : // nRet != 0, wenn es waerend Activate() abgeschossen wurde...
4235 0 : if ( !nRet && ( pActivePopup == pTest ) && pActivePopup->ImplGetWindow() )
4236 0 : pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this );
4237 : }
4238 : }
4239 :
4240 0 : return 0;
4241 : }
4242 :
4243 0 : IMPL_LINK_NOARG(MenuFloatingWindow, SubmenuClose)
4244 : {
4245 0 : if( pMenu && pMenu->pStartedFrom )
4246 : {
4247 0 : MenuFloatingWindow* pWin = (MenuFloatingWindow*) pMenu->pStartedFrom->GetWindow();
4248 0 : if( pWin )
4249 0 : pWin->KillActivePopup();
4250 : }
4251 0 : return 0;
4252 : }
4253 :
4254 0 : IMPL_LINK( MenuFloatingWindow, ShowHideListener, VclWindowEvent*, pEvent )
4255 : {
4256 0 : if( ! pMenu )
4257 0 : return 0;
4258 :
4259 0 : if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW )
4260 0 : pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID );
4261 0 : else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
4262 0 : pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID );
4263 0 : return 0;
4264 : }
4265 :
4266 0 : void MenuFloatingWindow::EnableScrollMenu( bool b )
4267 : {
4268 0 : bScrollMenu = b;
4269 0 : nScrollerHeight = b ? (sal_uInt16) GetSettings().GetStyleSettings().GetScrollBarSize() /2 : 0;
4270 0 : bScrollDown = true;
4271 0 : ImplInitClipRegion();
4272 0 : }
4273 :
4274 0 : void MenuFloatingWindow::Execute()
4275 : {
4276 0 : ImplSVData* pSVData = ImplGetSVData();
4277 :
4278 0 : pSVData->maAppData.mpActivePopupMenu = (PopupMenu*)pMenu;
4279 :
4280 0 : bInExecute = true;
4281 : // bCallingSelect = false;
4282 :
4283 0 : while ( bInExecute )
4284 0 : Application::Yield();
4285 :
4286 0 : pSVData->maAppData.mpActivePopupMenu = NULL;
4287 0 : }
4288 :
4289 0 : void MenuFloatingWindow::StopExecute( sal_uLong nFocusId )
4290 : {
4291 : // restore focus
4292 : // (could have been restored in Select)
4293 0 : if ( nSaveFocusId )
4294 : {
4295 0 : Window::EndSaveFocus( nFocusId, false );
4296 0 : nFocusId = nSaveFocusId;
4297 0 : if ( nFocusId )
4298 : {
4299 0 : nSaveFocusId = 0;
4300 0 : ImplGetSVData()->maWinData.mbNoDeactivate = false;
4301 : }
4302 : }
4303 0 : ImplEndPopupMode( 0, nFocusId );
4304 :
4305 0 : aHighlightChangedTimer.Stop();
4306 0 : bInExecute = false;
4307 0 : if ( pActivePopup )
4308 : {
4309 0 : KillActivePopup();
4310 : }
4311 : // notify parent, needed for accessibility
4312 0 : if( pMenu && pMenu->pStartedFrom )
4313 0 : pMenu->pStartedFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUDEACTIVATE, nPosInParent );
4314 0 : }
4315 :
4316 0 : void MenuFloatingWindow::KillActivePopup( PopupMenu* pThisOnly )
4317 : {
4318 0 : if ( pActivePopup && ( !pThisOnly || ( pThisOnly == pActivePopup ) ) )
4319 : {
4320 0 : if( pActivePopup->pWindow != NULL )
4321 0 : if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() )
4322 0 : return; // kill it later
4323 0 : if ( pActivePopup->bInCallback )
4324 0 : pActivePopup->bCanceled = true;
4325 :
4326 : // For all actions pActivePopup = 0, if e.g.
4327 : // PopupModeEndHdl the popups to destroy were called synchronous
4328 0 : PopupMenu* pPopup = pActivePopup;
4329 0 : pActivePopup = NULL;
4330 0 : pPopup->bInCallback = true;
4331 0 : pPopup->Deactivate();
4332 0 : pPopup->bInCallback = false;
4333 0 : if ( pPopup->ImplGetWindow() )
4334 : {
4335 0 : pPopup->ImplGetFloatingWindow()->StopExecute();
4336 0 : pPopup->ImplGetFloatingWindow()->doShutdown();
4337 0 : pPopup->pWindow->doLazyDelete();
4338 0 : pPopup->pWindow = NULL;
4339 :
4340 0 : Update();
4341 : }
4342 : }
4343 : }
4344 :
4345 0 : void MenuFloatingWindow::EndExecute()
4346 : {
4347 0 : Menu* pStart = pMenu ? pMenu->ImplGetStartMenu() : NULL;
4348 0 : sal_uLong nFocusId = 0;
4349 0 : if ( pStart && pStart->bIsMenuBar )
4350 : {
4351 0 : nFocusId = ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->GetFocusId();
4352 0 : if ( nFocusId )
4353 : {
4354 0 : ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->SetFocusId( 0 );
4355 0 : ImplGetSVData()->maWinData.mbNoDeactivate = false;
4356 : }
4357 : }
4358 :
4359 : // if started else where, cleanup there as well
4360 0 : MenuFloatingWindow* pCleanUpFrom = this;
4361 0 : MenuFloatingWindow* pWin = this;
4362 0 : while ( pWin && !pWin->bInExecute &&
4363 0 : pWin->pMenu->pStartedFrom && !pWin->pMenu->pStartedFrom->bIsMenuBar )
4364 : {
4365 0 : pWin = ((PopupMenu*)pWin->pMenu->pStartedFrom)->ImplGetFloatingWindow();
4366 : }
4367 0 : if ( pWin )
4368 0 : pCleanUpFrom = pWin;
4369 :
4370 : // this window will be destroyed => store date locally...
4371 0 : Menu* pM = pMenu;
4372 0 : sal_uInt16 nItem = nHighlightedItem;
4373 :
4374 0 : pCleanUpFrom->StopExecute( nFocusId );
4375 :
4376 0 : if ( nItem != ITEMPOS_INVALID && pM )
4377 : {
4378 0 : MenuItemData* pItemData = pM->GetItemList()->GetDataFromPos( nItem );
4379 0 : if ( pItemData && !pItemData->bIsTemporary )
4380 : {
4381 0 : pM->nSelectedId = pItemData->nId;
4382 0 : if ( pStart )
4383 0 : pStart->nSelectedId = pItemData->nId;
4384 :
4385 0 : pM->ImplSelect();
4386 : }
4387 : }
4388 0 : }
4389 :
4390 0 : void MenuFloatingWindow::EndExecute( sal_uInt16 nId )
4391 : {
4392 : size_t nPos;
4393 0 : if ( pMenu && pMenu->GetItemList()->GetData( nId, nPos ) )
4394 0 : nHighlightedItem = nPos;
4395 : else
4396 0 : nHighlightedItem = ITEMPOS_INVALID;
4397 :
4398 0 : EndExecute();
4399 0 : }
4400 :
4401 0 : void MenuFloatingWindow::MouseButtonDown( const MouseEvent& rMEvt )
4402 : {
4403 : // TH creates a ToTop on this window, but the active popup
4404 : // should stay on top...
4405 : // due to focus change this would close all menus -> don't do it (#94123)
4406 : //if ( pActivePopup && pActivePopup->ImplGetWindow() && !pActivePopup->ImplGetFloatingWindow()->pActivePopup )
4407 : // pActivePopup->ImplGetFloatingWindow()->ToTop( TOTOP_NOGRABFOCUS );
4408 :
4409 0 : ImplHighlightItem( rMEvt, true );
4410 :
4411 0 : nMBDownPos = nHighlightedItem;
4412 0 : }
4413 :
4414 0 : void MenuFloatingWindow::MouseButtonUp( const MouseEvent& rMEvt )
4415 : {
4416 0 : MenuItemData* pData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL;
4417 : // nMBDownPos store in local variable and reset immediately,
4418 : // as it will be too late after EndExecute
4419 0 : sal_uInt16 _nMBDownPos = nMBDownPos;
4420 0 : nMBDownPos = ITEMPOS_INVALID;
4421 0 : if ( pData && pData->bEnabled && ( pData->eType != MENUITEM_SEPARATOR ) )
4422 : {
4423 0 : if ( !pData->pSubMenu )
4424 : {
4425 0 : EndExecute();
4426 : }
4427 0 : else if ( ( pData->nBits & MIB_POPUPSELECT ) && ( nHighlightedItem == _nMBDownPos ) && ( rMEvt.GetClicks() == 2 ) )
4428 : {
4429 : // not when clicked over the arrow...
4430 0 : Size aSz = GetOutputSizePixel();
4431 0 : long nFontHeight = GetTextHeight();
4432 0 : if ( rMEvt.GetPosPixel().X() < ( aSz.Width() - nFontHeight - nFontHeight/4 ) )
4433 0 : EndExecute();
4434 : }
4435 : }
4436 :
4437 0 : }
4438 :
4439 0 : void MenuFloatingWindow::MouseMove( const MouseEvent& rMEvt )
4440 : {
4441 0 : if ( !IsVisible() || rMEvt.IsSynthetic() || rMEvt.IsEnterWindow() )
4442 0 : return;
4443 :
4444 0 : if ( rMEvt.IsLeaveWindow() )
4445 : {
4446 : // #102461# do not remove highlight if a popup menu is open at this position
4447 0 : MenuItemData* pData = pMenu ? pMenu->pItemList->GetDataFromPos( nHighlightedItem ) : NULL;
4448 : // close popup with some delayed if we leave somewhere else
4449 0 : if( pActivePopup && pData && pData->pSubMenu != pActivePopup )
4450 0 : pActivePopup->ImplGetFloatingWindow()->aSubmenuCloseTimer.Start();
4451 :
4452 0 : if( !pActivePopup || (pData && pData->pSubMenu != pActivePopup ) )
4453 0 : ChangeHighlightItem( ITEMPOS_INVALID, false );
4454 :
4455 0 : if ( IsScrollMenu() )
4456 0 : ImplScroll( rMEvt.GetPosPixel() );
4457 : }
4458 : else
4459 : {
4460 0 : aSubmenuCloseTimer.Stop();
4461 0 : if( bIgnoreFirstMove )
4462 0 : bIgnoreFirstMove = false;
4463 : else
4464 0 : ImplHighlightItem( rMEvt, false );
4465 : }
4466 : }
4467 :
4468 0 : void MenuFloatingWindow::ImplScroll( bool bUp )
4469 : {
4470 0 : KillActivePopup();
4471 0 : Update();
4472 :
4473 0 : if( ! pMenu )
4474 0 : return;
4475 :
4476 0 : HighlightItem( nHighlightedItem, false );
4477 :
4478 0 : pMenu->ImplKillLayoutData();
4479 :
4480 0 : if ( bScrollUp && bUp )
4481 : {
4482 0 : nFirstEntry = pMenu->ImplGetPrevVisible( nFirstEntry );
4483 : DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" );
4484 :
4485 0 : long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height();
4486 :
4487 0 : if ( !bScrollDown )
4488 : {
4489 0 : bScrollDown = true;
4490 0 : ImplDrawScroller( false );
4491 : }
4492 :
4493 0 : if ( pMenu->ImplGetPrevVisible( nFirstEntry ) == ITEMPOS_INVALID )
4494 : {
4495 0 : bScrollUp = false;
4496 0 : ImplDrawScroller( true );
4497 : }
4498 :
4499 0 : Scroll( 0, nScrollEntryHeight, ImplCalcClipRegion( false ).GetBoundRect(), SCROLL_CLIP );
4500 : }
4501 0 : else if ( bScrollDown && !bUp )
4502 : {
4503 0 : long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height();
4504 :
4505 0 : nFirstEntry = pMenu->ImplGetNextVisible( nFirstEntry );
4506 : DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" );
4507 :
4508 0 : if ( !bScrollUp )
4509 : {
4510 0 : bScrollUp = true;
4511 0 : ImplDrawScroller( true );
4512 : }
4513 :
4514 0 : long nHeight = GetOutputSizePixel().Height();
4515 : sal_uInt16 nLastVisible;
4516 0 : ((PopupMenu*)pMenu)->ImplCalcVisEntries( nHeight, nFirstEntry, &nLastVisible );
4517 0 : if ( pMenu->ImplGetNextVisible( nLastVisible ) == ITEMPOS_INVALID )
4518 : {
4519 0 : bScrollDown = false;
4520 0 : ImplDrawScroller( false );
4521 : }
4522 :
4523 0 : Scroll( 0, -nScrollEntryHeight, ImplCalcClipRegion( false ).GetBoundRect(), SCROLL_CLIP );
4524 : }
4525 :
4526 0 : HighlightItem( nHighlightedItem, true );
4527 : }
4528 :
4529 0 : void MenuFloatingWindow::ImplScroll( const Point& rMousePos )
4530 : {
4531 0 : Size aOutSz = GetOutputSizePixel();
4532 :
4533 0 : long nY = nScrollerHeight;
4534 0 : long nMouseY = rMousePos.Y();
4535 0 : long nDelta = 0;
4536 :
4537 0 : if ( bScrollUp && ( nMouseY < nY ) )
4538 : {
4539 0 : ImplScroll( true );
4540 0 : nDelta = nY - nMouseY;
4541 : }
4542 0 : else if ( bScrollDown && ( nMouseY > ( aOutSz.Height() - nY ) ) )
4543 : {
4544 0 : ImplScroll( false );
4545 0 : nDelta = nMouseY - ( aOutSz.Height() - nY );
4546 : }
4547 :
4548 0 : if ( nDelta )
4549 : {
4550 0 : aScrollTimer.Stop(); // if scrolled through MouseMove.
4551 : long nTimeout;
4552 0 : if ( nDelta < 3 )
4553 0 : nTimeout = 200;
4554 0 : else if ( nDelta < 5 )
4555 0 : nTimeout = 100;
4556 0 : else if ( nDelta < 8 )
4557 0 : nTimeout = 70;
4558 0 : else if ( nDelta < 12 )
4559 0 : nTimeout = 40;
4560 : else
4561 0 : nTimeout = 20;
4562 0 : aScrollTimer.SetTimeout( nTimeout );
4563 0 : aScrollTimer.Start();
4564 : }
4565 0 : }
4566 0 : void MenuFloatingWindow::ChangeHighlightItem( sal_uInt16 n, bool bStartPopupTimer )
4567 : {
4568 : // #57934# ggf. immediately close the active, as TH's backgroundstorage works.
4569 : // #65750# we prefer to refrain from the background storage of small lines.
4570 : // otherwise the menus are difficult to operate.
4571 : // MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n );
4572 : // if ( pActivePopup && pNextData && ( pActivePopup != pNextData->pSubMenu ) )
4573 : // KillActivePopup();
4574 :
4575 0 : aSubmenuCloseTimer.Stop();
4576 0 : if( ! pMenu )
4577 0 : return;
4578 :
4579 0 : if ( nHighlightedItem != ITEMPOS_INVALID )
4580 : {
4581 0 : HighlightItem( nHighlightedItem, false );
4582 0 : pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
4583 : }
4584 :
4585 0 : nHighlightedItem = (sal_uInt16)n;
4586 : DBG_ASSERT( pMenu->ImplIsVisible( nHighlightedItem ) || nHighlightedItem == ITEMPOS_INVALID, "ChangeHighlightItem: Not visible!" );
4587 0 : if( nHighlightedItem != ITEMPOS_INVALID )
4588 : {
4589 0 : if( pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
4590 : {
4591 : // #102461# make sure parent entry is highlighted as well
4592 : MenuItemData* pData;
4593 0 : size_t i, nCount = pMenu->pStartedFrom->pItemList->size();
4594 0 : for(i = 0; i < nCount; i++)
4595 : {
4596 0 : pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i );
4597 0 : if( pData && ( pData->pSubMenu == pMenu ) )
4598 0 : break;
4599 : }
4600 0 : if( i < nCount )
4601 : {
4602 0 : MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow();
4603 0 : if( pPWin && pPWin->nHighlightedItem != i )
4604 : {
4605 0 : pPWin->HighlightItem( i, true );
4606 0 : pPWin->nHighlightedItem = i;
4607 : }
4608 : }
4609 : }
4610 0 : HighlightItem( nHighlightedItem, true );
4611 0 : pMenu->SetHighlightItem(nHighlightedItem);
4612 0 : pMenu->ImplCallHighlight( nHighlightedItem );
4613 : }
4614 : else
4615 0 : pMenu->nSelectedId = 0;
4616 :
4617 0 : if ( bStartPopupTimer )
4618 : {
4619 : // #102438# Menu items are not selectable
4620 : // If a menu item is selected by an AT-tool via the XAccessibleAction, XAccessibleValue
4621 : // or XAccessibleSelection interface, and the parent popup menus are not executed yet,
4622 : // the parent popup menus must be executed SYNCHRONOUSLY, before the menu item is selected.
4623 0 : if ( GetSettings().GetMouseSettings().GetMenuDelay() )
4624 0 : aHighlightChangedTimer.Start();
4625 : else
4626 0 : HighlightChanged( &aHighlightChangedTimer );
4627 : }
4628 : }
4629 :
4630 0 : void MenuFloatingWindow::HighlightItem( sal_uInt16 nPos, bool bHighlight )
4631 : {
4632 0 : if( ! pMenu )
4633 0 : return;
4634 :
4635 0 : Size aSz = GetOutputSizePixel();
4636 0 : long nStartY = ImplGetStartY();
4637 0 : long nY = nScrollerHeight + nStartY + ImplGetSVData()->maNWFData.mnMenuFormatBorderY;
4638 0 : long nX = 0;
4639 :
4640 0 : if ( pMenu->pLogo )
4641 0 : nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
4642 :
4643 0 : int nOuterSpaceX = ImplGetSVData()->maNWFData.mnMenuFormatBorderX;
4644 :
4645 0 : size_t nCount = pMenu->pItemList->size();
4646 0 : for ( size_t n = 0; n < nCount; n++ )
4647 : {
4648 0 : MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
4649 0 : if ( n == nPos )
4650 : {
4651 : DBG_ASSERT( pMenu->ImplIsVisible( n ), "Highlight: Item not visible!" );
4652 0 : if ( pData->eType != MENUITEM_SEPARATOR )
4653 : {
4654 0 : bool bRestoreLineColor = false;
4655 0 : Color oldLineColor;
4656 0 : bool bDrawItemRect = true;
4657 :
4658 0 : Rectangle aItemRect( Point( nX+nOuterSpaceX, nY ), Size( aSz.Width()-2*nOuterSpaceX, pData->aSz.Height() ) );
4659 0 : if ( pData->nBits & MIB_POPUPSELECT )
4660 : {
4661 0 : long nFontHeight = GetTextHeight();
4662 0 : aItemRect.Right() -= nFontHeight + nFontHeight/4;
4663 : }
4664 :
4665 0 : if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
4666 : {
4667 0 : Size aPxSize( GetOutputSizePixel() );
4668 0 : Push( PUSH_CLIPREGION );
4669 0 : IntersectClipRegion( Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) ) );
4670 0 : Rectangle aCtrlRect( Point( nX, 0 ), Size( aPxSize.Width()-nX, aPxSize.Height() ) );
4671 0 : MenupopupValue aVal( pMenu->nTextPos-GUTTERBORDER, aItemRect );
4672 : DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
4673 : aCtrlRect,
4674 : CTRL_STATE_ENABLED,
4675 : aVal,
4676 0 : OUString() );
4677 0 : if( bHighlight &&
4678 0 : IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) )
4679 : {
4680 0 : bDrawItemRect = false;
4681 0 : if( !DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM,
4682 : aItemRect,
4683 : CTRL_STATE_SELECTED | ( pData->bEnabled? CTRL_STATE_ENABLED: 0 ),
4684 : aVal,
4685 0 : OUString() ) )
4686 : {
4687 0 : bDrawItemRect = bHighlight;
4688 : }
4689 : }
4690 : else
4691 0 : bDrawItemRect = bHighlight;
4692 0 : Pop();
4693 : }
4694 0 : if( bDrawItemRect )
4695 : {
4696 0 : if ( bHighlight )
4697 : {
4698 0 : if( pData->bEnabled )
4699 0 : SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
4700 : else
4701 : {
4702 0 : SetFillColor();
4703 0 : oldLineColor = GetLineColor();
4704 0 : SetLineColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
4705 0 : bRestoreLineColor = true;
4706 : }
4707 : }
4708 : else
4709 0 : SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
4710 :
4711 0 : DrawRect( aItemRect );
4712 : }
4713 0 : pMenu->ImplPaint( this, nScrollerHeight, nStartY, pData, bHighlight );
4714 0 : if( bRestoreLineColor )
4715 0 : SetLineColor( oldLineColor );
4716 : }
4717 0 : return;
4718 : }
4719 :
4720 0 : nY += pData->aSz.Height();
4721 : }
4722 : }
4723 :
4724 0 : Rectangle MenuFloatingWindow::ImplGetItemRect( sal_uInt16 nPos )
4725 : {
4726 0 : if( ! pMenu )
4727 0 : return Rectangle();
4728 :
4729 0 : Rectangle aRect;
4730 0 : Size aSz = GetOutputSizePixel();
4731 0 : long nStartY = ImplGetStartY();
4732 0 : long nY = nScrollerHeight+nStartY;
4733 0 : long nX = 0;
4734 :
4735 0 : if ( pMenu->pLogo )
4736 0 : nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
4737 :
4738 0 : size_t nCount = pMenu->pItemList->size();
4739 0 : for ( size_t n = 0; n < nCount; n++ )
4740 : {
4741 0 : MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
4742 0 : if ( n == nPos )
4743 : {
4744 : DBG_ASSERT( pMenu->ImplIsVisible( n ), "ImplGetItemRect: Item not visible!" );
4745 0 : if ( pData->eType != MENUITEM_SEPARATOR )
4746 : {
4747 0 : aRect = Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) );
4748 0 : if ( pData->nBits & MIB_POPUPSELECT )
4749 : {
4750 0 : long nFontHeight = GetTextHeight();
4751 0 : aRect.Right() -= nFontHeight + nFontHeight/4;
4752 : }
4753 : }
4754 0 : break;
4755 : }
4756 0 : nY += pData->aSz.Height();
4757 : }
4758 0 : return aRect;
4759 : }
4760 :
4761 0 : void MenuFloatingWindow::ImplCursorUpDown( bool bUp, bool bHomeEnd )
4762 : {
4763 0 : if( ! pMenu )
4764 0 : return;
4765 :
4766 0 : const StyleSettings& rSettings = GetSettings().GetStyleSettings();
4767 :
4768 0 : sal_uInt16 n = nHighlightedItem;
4769 0 : if ( n == ITEMPOS_INVALID )
4770 : {
4771 0 : if ( bUp )
4772 0 : n = 0;
4773 : else
4774 0 : n = pMenu->GetItemCount()-1;
4775 : }
4776 :
4777 0 : sal_uInt16 nLoop = n;
4778 :
4779 0 : if( bHomeEnd )
4780 : {
4781 : // absolute positioning
4782 0 : if( bUp )
4783 : {
4784 0 : n = pMenu->GetItemCount();
4785 0 : nLoop = n-1;
4786 : }
4787 : else
4788 : {
4789 0 : n = (sal_uInt16)-1;
4790 0 : nLoop = n+1;
4791 : }
4792 : }
4793 :
4794 0 : do
4795 : {
4796 0 : if ( bUp )
4797 : {
4798 0 : if ( n )
4799 0 : n--;
4800 : else
4801 0 : if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) )
4802 0 : n = pMenu->GetItemCount()-1;
4803 : else
4804 0 : break;
4805 : }
4806 : else
4807 : {
4808 0 : n++;
4809 0 : if ( n >= pMenu->GetItemCount() )
4810 : {
4811 0 : if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) )
4812 0 : n = 0;
4813 : else
4814 0 : break;
4815 : }
4816 : }
4817 :
4818 0 : MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n );
4819 0 : if ( ( pData->bEnabled || !rSettings.GetSkipDisabledInMenus() )
4820 0 : && ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) && pMenu->ImplIsSelectable( n ) )
4821 : {
4822 : // Is selection in visible area?
4823 0 : if ( IsScrollMenu() )
4824 : {
4825 0 : ChangeHighlightItem( ITEMPOS_INVALID, false );
4826 :
4827 0 : while ( n < nFirstEntry )
4828 0 : ImplScroll( true );
4829 :
4830 0 : Size aOutSz = GetOutputSizePixel();
4831 : sal_uInt16 nLastVisible;
4832 0 : ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible );
4833 0 : while ( n > nLastVisible )
4834 : {
4835 0 : ImplScroll( false );
4836 0 : ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible );
4837 : }
4838 : }
4839 0 : ChangeHighlightItem( n, false );
4840 0 : break;
4841 : }
4842 : } while ( n != nLoop );
4843 : }
4844 :
4845 0 : void MenuFloatingWindow::KeyInput( const KeyEvent& rKEvent )
4846 : {
4847 0 : ImplDelData aDelData;
4848 0 : ImplAddDel( &aDelData );
4849 :
4850 0 : sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode();
4851 0 : bKeyInput = true;
4852 0 : switch ( nCode )
4853 : {
4854 : case KEY_UP:
4855 : case KEY_DOWN:
4856 : {
4857 0 : ImplCursorUpDown( nCode == KEY_UP );
4858 : }
4859 0 : break;
4860 : case KEY_END:
4861 : case KEY_HOME:
4862 : {
4863 0 : ImplCursorUpDown( nCode == KEY_END, true );
4864 : }
4865 0 : break;
4866 : case KEY_F6:
4867 : case KEY_ESCAPE:
4868 : {
4869 : // Ctrl-F6 acts like ESC here, the menu bar however will then put the focus in the document
4870 0 : if( nCode == KEY_F6 && !rKEvent.GetKeyCode().IsMod1() )
4871 0 : break;
4872 0 : if( pMenu )
4873 : {
4874 0 : if ( !pMenu->pStartedFrom )
4875 : {
4876 0 : StopExecute();
4877 0 : KillActivePopup();
4878 : }
4879 0 : else if ( pMenu->pStartedFrom->bIsMenuBar )
4880 : {
4881 : // Forward...
4882 0 : ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent );
4883 : }
4884 : else
4885 : {
4886 0 : StopExecute();
4887 0 : PopupMenu* pPopupMenu = (PopupMenu*)pMenu->pStartedFrom;
4888 0 : MenuFloatingWindow* pFloat = pPopupMenu->ImplGetFloatingWindow();
4889 0 : pFloat->GrabFocus();
4890 0 : pFloat->KillActivePopup();
4891 0 : pPopupMenu->ImplCallHighlight(pFloat->nHighlightedItem);
4892 : }
4893 : }
4894 : }
4895 0 : break;
4896 : case KEY_LEFT:
4897 : {
4898 0 : if ( pMenu && pMenu->pStartedFrom )
4899 : {
4900 0 : StopExecute();
4901 0 : if ( pMenu->pStartedFrom->bIsMenuBar )
4902 : {
4903 : // Forward...
4904 0 : ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent );
4905 : }
4906 : else
4907 : {
4908 0 : MenuFloatingWindow* pFloat = ((PopupMenu*)pMenu->pStartedFrom)->ImplGetFloatingWindow();
4909 0 : pFloat->GrabFocus();
4910 0 : pFloat->KillActivePopup();
4911 0 : sal_uInt16 highlightItem = pFloat->GetHighlightedItem();
4912 0 : pFloat->ChangeHighlightItem(highlightItem, false);
4913 : }
4914 : }
4915 : }
4916 0 : break;
4917 : case KEY_RIGHT:
4918 : {
4919 0 : if( pMenu )
4920 : {
4921 0 : bool bDone = false;
4922 0 : if ( nHighlightedItem != ITEMPOS_INVALID )
4923 : {
4924 0 : MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
4925 0 : if ( pData && pData->pSubMenu )
4926 : {
4927 0 : HighlightChanged( 0 );
4928 0 : bDone = true;
4929 : }
4930 : }
4931 0 : if ( !bDone )
4932 : {
4933 0 : Menu* pStart = pMenu->ImplGetStartMenu();
4934 0 : if ( pStart && pStart->bIsMenuBar )
4935 : {
4936 : // Forward...
4937 0 : pStart->ImplGetWindow()->KeyInput( rKEvent );
4938 : }
4939 : }
4940 : }
4941 : }
4942 0 : break;
4943 : case KEY_RETURN:
4944 : {
4945 0 : if( pMenu )
4946 : {
4947 0 : MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
4948 0 : if ( pData && pData->bEnabled )
4949 : {
4950 0 : if ( pData->pSubMenu )
4951 0 : HighlightChanged( 0 );
4952 : else
4953 0 : EndExecute();
4954 : }
4955 : else
4956 0 : StopExecute();
4957 : }
4958 : }
4959 0 : break;
4960 : case KEY_MENU:
4961 : {
4962 0 : if( pMenu )
4963 : {
4964 0 : Menu* pStart = pMenu->ImplGetStartMenu();
4965 0 : if ( pStart && pStart->bIsMenuBar )
4966 : {
4967 : // Forward...
4968 0 : pStart->ImplGetWindow()->KeyInput( rKEvent );
4969 : }
4970 : }
4971 : }
4972 0 : break;
4973 : default:
4974 : {
4975 0 : sal_Unicode nCharCode = rKEvent.GetCharCode();
4976 0 : sal_uInt16 nPos = 0;
4977 0 : sal_uInt16 nDuplicates = 0;
4978 0 : MenuItemData* pData = (nCharCode && pMenu) ? pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nPos, nDuplicates, nHighlightedItem ) : NULL;
4979 0 : if ( pData )
4980 : {
4981 0 : if ( pData->pSubMenu || nDuplicates > 1 )
4982 : {
4983 0 : ChangeHighlightItem( nPos, false );
4984 0 : HighlightChanged( 0 );
4985 : }
4986 : else
4987 : {
4988 0 : nHighlightedItem = nPos;
4989 0 : EndExecute();
4990 : }
4991 : }
4992 : else
4993 0 : FloatingWindow::KeyInput( rKEvent );
4994 : }
4995 : }
4996 : // #105474# check if menu window was not destroyed
4997 0 : if ( !aDelData.IsDead() )
4998 : {
4999 0 : ImplRemoveDel( &aDelData );
5000 0 : bKeyInput = false;
5001 0 : }
5002 0 : }
5003 :
5004 0 : void MenuFloatingWindow::Paint( const Rectangle& )
5005 : {
5006 0 : if( ! pMenu )
5007 0 : return;
5008 :
5009 0 : if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
5010 : {
5011 0 : SetClipRegion();
5012 0 : long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0;
5013 0 : Size aPxSize( GetOutputSizePixel() );
5014 0 : aPxSize.Width() -= nX;
5015 0 : ImplControlValue aVal( pMenu->nTextPos-GUTTERBORDER );
5016 : DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
5017 : Rectangle( Point( nX, 0 ), aPxSize ),
5018 : CTRL_STATE_ENABLED,
5019 : aVal,
5020 0 : OUString() );
5021 0 : ImplInitClipRegion();
5022 : }
5023 0 : if ( IsScrollMenu() )
5024 : {
5025 0 : ImplDrawScroller( true );
5026 0 : ImplDrawScroller( false );
5027 : }
5028 0 : SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
5029 0 : pMenu->ImplPaint( this, nScrollerHeight, ImplGetStartY() );
5030 0 : if ( nHighlightedItem != ITEMPOS_INVALID )
5031 0 : HighlightItem( nHighlightedItem, true );
5032 : }
5033 :
5034 0 : void MenuFloatingWindow::ImplDrawScroller( bool bUp )
5035 : {
5036 0 : if( ! pMenu )
5037 0 : return;
5038 :
5039 0 : SetClipRegion();
5040 :
5041 0 : Size aOutSz = GetOutputSizePixel();
5042 0 : long nY = bUp ? 0 : ( aOutSz.Height() - nScrollerHeight );
5043 0 : long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0;
5044 0 : Rectangle aRect( Point( nX, nY ), Size( aOutSz.Width()-nX, nScrollerHeight ) );
5045 :
5046 0 : DecorationView aDecoView( this );
5047 0 : SymbolType eSymbol = bUp ? SYMBOL_SPIN_UP : SYMBOL_SPIN_DOWN;
5048 :
5049 0 : sal_uInt16 nStyle = 0;
5050 0 : if ( ( bUp && !bScrollUp ) || ( !bUp && !bScrollDown ) )
5051 0 : nStyle |= SYMBOL_DRAW_DISABLE;
5052 :
5053 0 : aDecoView.DrawSymbol( aRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
5054 :
5055 0 : ImplInitClipRegion();
5056 : }
5057 :
5058 0 : void MenuFloatingWindow::RequestHelp( const HelpEvent& rHEvt )
5059 : {
5060 0 : sal_uInt16 nId = nHighlightedItem;
5061 0 : Menu* pM = pMenu;
5062 0 : Window* pW = this;
5063 :
5064 : // #102618# Get item rect before destroying the window in EndExecute() call
5065 0 : Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) );
5066 :
5067 0 : if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
5068 : {
5069 0 : nHighlightedItem = ITEMPOS_INVALID;
5070 0 : EndExecute();
5071 0 : pW = NULL;
5072 : }
5073 :
5074 0 : if( !ImplHandleHelpEvent( pW, pM, nId, rHEvt, aHighlightRect ) )
5075 0 : Window::RequestHelp( rHEvt );
5076 0 : }
5077 :
5078 0 : void MenuFloatingWindow::StateChanged( StateChangedType nType )
5079 : {
5080 0 : FloatingWindow::StateChanged( nType );
5081 :
5082 0 : if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
5083 : {
5084 0 : ImplInitMenuWindow( this, false, false );
5085 0 : Invalidate();
5086 : }
5087 0 : }
5088 :
5089 0 : void MenuFloatingWindow::DataChanged( const DataChangedEvent& rDCEvt )
5090 : {
5091 0 : FloatingWindow::DataChanged( rDCEvt );
5092 :
5093 0 : if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
5094 0 : (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
5095 0 : ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
5096 0 : (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
5097 : {
5098 0 : ImplInitMenuWindow( this, false, false );
5099 0 : Invalidate();
5100 : }
5101 0 : }
5102 :
5103 0 : void MenuFloatingWindow::Command( const CommandEvent& rCEvt )
5104 : {
5105 0 : if ( rCEvt.GetCommand() == COMMAND_WHEEL )
5106 : {
5107 0 : const CommandWheelData* pData = rCEvt.GetWheelData();
5108 0 : if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
5109 : {
5110 : // ImplCursorUpDown( pData->GetDelta() > 0L );
5111 0 : ImplScroll( pData->GetDelta() > 0L );
5112 0 : MouseMove( MouseEvent( GetPointerPosPixel(), 0 ) );
5113 : }
5114 : }
5115 0 : }
5116 :
5117 0 : ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuFloatingWindow::CreateAccessible()
5118 : {
5119 0 : ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc;
5120 :
5121 0 : if ( pMenu && !pMenu->pStartedFrom )
5122 0 : xAcc = pMenu->GetAccessible();
5123 :
5124 0 : return xAcc;
5125 : }
5126 :
5127 0 : MenuBarWindow::MenuBarWindow( Window* pParent ) :
5128 : Window( pParent, 0 ),
5129 : aCloser( this ),
5130 : aFloatBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE ),
5131 0 : aHideBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE )
5132 : {
5133 0 : SetType( WINDOW_MENUBARWINDOW );
5134 0 : pMenu = NULL;
5135 0 : pActivePopup = NULL;
5136 0 : nSaveFocusId = 0;
5137 0 : nHighlightedItem = ITEMPOS_INVALID;
5138 0 : nRolloveredItem = ITEMPOS_INVALID;
5139 0 : mbAutoPopup = true;
5140 0 : nSaveFocusId = 0;
5141 0 : bIgnoreFirstMove = true;
5142 0 : bStayActive = false;
5143 :
5144 0 : ResMgr* pResMgr = ImplGetResMgr();
5145 :
5146 0 : if( pResMgr )
5147 : {
5148 0 : BitmapEx aBitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) );
5149 0 : aCloser.maImage = Image( aBitmap );
5150 :
5151 0 : aCloser.SetOutStyle( TOOLBOX_STYLE_FLAT );
5152 0 : aCloser.SetBackground();
5153 0 : aCloser.SetPaintTransparent( true );
5154 0 : aCloser.SetParentClipMode( PARENTCLIPMODE_NOCLIP );
5155 :
5156 0 : aCloser.InsertItem( IID_DOCUMENTCLOSE, aCloser.maImage, 0 );
5157 0 : aCloser.SetSelectHdl( LINK( this, MenuBarWindow, CloserHdl ) );
5158 0 : aCloser.AddEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) );
5159 0 : aCloser.SetQuickHelpText( IID_DOCUMENTCLOSE, ResId(SV_HELPTEXT_CLOSEDOCUMENT, *pResMgr).toString() );
5160 :
5161 0 : aFloatBtn.SetClickHdl( LINK( this, MenuBarWindow, FloatHdl ) );
5162 0 : aFloatBtn.SetSymbol( SYMBOL_FLOAT );
5163 0 : aFloatBtn.SetQuickHelpText( ResId(SV_HELPTEXT_RESTORE, *pResMgr).toString() );
5164 :
5165 0 : aHideBtn.SetClickHdl( LINK( this, MenuBarWindow, HideHdl ) );
5166 0 : aHideBtn.SetSymbol( SYMBOL_HIDE );
5167 0 : aHideBtn.SetQuickHelpText( ResId(SV_HELPTEXT_MINIMIZE, *pResMgr).toString() );
5168 : }
5169 :
5170 0 : ImplInitStyleSettings();
5171 :
5172 0 : AddEventListener( LINK( this, MenuBarWindow, ShowHideListener ) );
5173 0 : }
5174 :
5175 0 : MenuBarWindow::~MenuBarWindow()
5176 : {
5177 0 : aCloser.RemoveEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) );
5178 0 : RemoveEventListener( LINK( this, MenuBarWindow, ShowHideListener ) );
5179 0 : }
5180 :
5181 0 : void MenuBarWindow::SetMenu( MenuBar* pMen )
5182 : {
5183 0 : pMenu = pMen;
5184 0 : KillActivePopup();
5185 0 : nHighlightedItem = ITEMPOS_INVALID;
5186 0 : ImplInitMenuWindow( this, true, true );
5187 0 : if ( pMen )
5188 : {
5189 0 : aCloser.ShowItem( IID_DOCUMENTCLOSE, pMen->HasCloser() );
5190 0 : aCloser.Show( pMen->HasCloser() || !m_aAddButtons.empty() );
5191 0 : aFloatBtn.Show( pMen->HasFloatButton() );
5192 0 : aHideBtn.Show( pMen->HasHideButton() );
5193 : }
5194 0 : Invalidate();
5195 :
5196 : // show and connect native menubar
5197 0 : if( pMenu && pMenu->ImplGetSalMenu() )
5198 : {
5199 0 : if( pMenu->ImplGetSalMenu()->VisibleMenuBar() )
5200 0 : ImplGetFrame()->SetMenu( pMenu->ImplGetSalMenu() );
5201 :
5202 0 : pMenu->ImplGetSalMenu()->SetFrame( ImplGetFrame() );
5203 : }
5204 0 : }
5205 :
5206 0 : void MenuBarWindow::ShowButtons( bool bClose, bool bFloat, bool bHide )
5207 : {
5208 0 : aCloser.ShowItem( IID_DOCUMENTCLOSE, bClose );
5209 0 : aCloser.Show( bClose || ! m_aAddButtons.empty() );
5210 0 : aFloatBtn.Show( bFloat );
5211 0 : aHideBtn.Show( bHide );
5212 0 : Resize();
5213 0 : }
5214 :
5215 0 : Size MenuBarWindow::MinCloseButtonSize()
5216 : {
5217 0 : return aCloser.getMinSize();
5218 : }
5219 :
5220 0 : IMPL_LINK_NOARG(MenuBarWindow, CloserHdl)
5221 : {
5222 0 : if( ! pMenu )
5223 0 : return 0;
5224 :
5225 0 : if( aCloser.GetCurItemId() == IID_DOCUMENTCLOSE )
5226 : {
5227 : // #i106052# call close hdl asynchronously to ease handler implementation
5228 : // this avoids still being in the handler while the DecoToolBox already
5229 : // gets destroyed
5230 0 : Application::PostUserEvent( ((MenuBar*)pMenu)->GetCloserHdl(), pMenu );
5231 : }
5232 : else
5233 : {
5234 0 : std::map<sal_uInt16,AddButtonEntry>::iterator it = m_aAddButtons.find( aCloser.GetCurItemId() );
5235 0 : if( it != m_aAddButtons.end() )
5236 : {
5237 : MenuBar::MenuBarButtonCallbackArg aArg;
5238 0 : aArg.nId = it->first;
5239 0 : aArg.bHighlight = (aCloser.GetHighlightItemId() == it->first);
5240 0 : aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
5241 0 : return it->second.m_aSelectLink.Call( &aArg );
5242 : }
5243 : }
5244 0 : return 0;
5245 : }
5246 :
5247 0 : IMPL_LINK( MenuBarWindow, ToolboxEventHdl, VclWindowEvent*, pEvent )
5248 : {
5249 0 : if( ! pMenu )
5250 0 : return 0;
5251 :
5252 : MenuBar::MenuBarButtonCallbackArg aArg;
5253 0 : aArg.nId = 0xffff;
5254 0 : aArg.bHighlight = (pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT);
5255 0 : aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
5256 0 : if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT )
5257 0 : aArg.nId = aCloser.GetHighlightItemId();
5258 0 : else if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHTOFF )
5259 : {
5260 0 : sal_uInt16 nPos = static_cast< sal_uInt16 >(reinterpret_cast<sal_IntPtr>(pEvent->GetData()));
5261 0 : aArg.nId = aCloser.GetItemId( nPos );
5262 : }
5263 0 : std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( aArg.nId );
5264 0 : if( it != m_aAddButtons.end() )
5265 : {
5266 0 : it->second.m_aHighlightLink.Call( &aArg );
5267 : }
5268 0 : return 0;
5269 : }
5270 :
5271 0 : IMPL_LINK( MenuBarWindow, ShowHideListener, VclWindowEvent*, pEvent )
5272 : {
5273 0 : if( ! pMenu )
5274 0 : return 0;
5275 :
5276 0 : if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW )
5277 0 : pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID );
5278 0 : else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
5279 0 : pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID );
5280 0 : return 0;
5281 : }
5282 :
5283 0 : IMPL_LINK_NOARG(MenuBarWindow, FloatHdl)
5284 : {
5285 0 : return pMenu ? ((MenuBar*)pMenu)->GetFloatButtonClickHdl().Call( pMenu ) : 0;
5286 : }
5287 :
5288 0 : IMPL_LINK_NOARG(MenuBarWindow, HideHdl)
5289 : {
5290 0 : return pMenu ? ((MenuBar*)pMenu)->GetHideButtonClickHdl().Call( pMenu ) : 0;
5291 : }
5292 :
5293 0 : void MenuBarWindow::ImplCreatePopup( bool bPreSelectFirst )
5294 : {
5295 0 : MenuItemData* pItemData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL;
5296 0 : if ( pItemData )
5297 : {
5298 0 : bIgnoreFirstMove = true;
5299 0 : if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) )
5300 : {
5301 0 : KillActivePopup();
5302 : }
5303 0 : if ( pItemData->bEnabled && pItemData->pSubMenu && ( nHighlightedItem != ITEMPOS_INVALID ) && ( pItemData->pSubMenu != pActivePopup ) )
5304 : {
5305 0 : pActivePopup = (PopupMenu*)pItemData->pSubMenu;
5306 0 : long nX = 0;
5307 0 : MenuItemData* pData = 0;
5308 0 : for ( sal_uLong n = 0; n < nHighlightedItem; n++ )
5309 : {
5310 0 : pData = pMenu->GetItemList()->GetDataFromPos( n );
5311 0 : nX += pData->aSz.Width();
5312 : }
5313 0 : pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
5314 0 : Point aItemTopLeft( nX, 0 );
5315 0 : Point aItemBottomRight( aItemTopLeft );
5316 0 : aItemBottomRight.X() += pData->aSz.Width();
5317 :
5318 : // the menu bar could have height 0 in fullscreen mode:
5319 : // so do not use always WindowHeight, as ItemHeight < WindowHeight.
5320 0 : if ( GetSizePixel().Height() )
5321 : {
5322 : // #107747# give menuitems the height of the menubar
5323 0 : aItemBottomRight.Y() += GetOutputSizePixel().Height()-1;
5324 : }
5325 :
5326 : // ImplExecute is not modal...
5327 : // #99071# do not grab the focus, otherwise it will be restored to the menubar
5328 : // when the frame is reactivated later
5329 : //GrabFocus();
5330 0 : pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_DOWN | FLOATWIN_POPUPMODE_NOHORZPLACEMENT, pMenu, bPreSelectFirst );
5331 0 : if ( pActivePopup )
5332 : {
5333 : // does not have a window, if aborted before or if there are no entries
5334 0 : if ( pActivePopup->ImplGetFloatingWindow() )
5335 0 : pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this );
5336 : else
5337 0 : pActivePopup = NULL;
5338 : }
5339 : }
5340 : }
5341 0 : }
5342 :
5343 0 : void MenuBarWindow::KillActivePopup()
5344 : {
5345 0 : if ( pActivePopup )
5346 : {
5347 0 : if( pActivePopup->pWindow != NULL )
5348 0 : if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() )
5349 0 : return; // kill it later
5350 :
5351 0 : if ( pActivePopup->bInCallback )
5352 0 : pActivePopup->bCanceled = true;
5353 :
5354 0 : pActivePopup->bInCallback = true;
5355 0 : pActivePopup->Deactivate();
5356 0 : pActivePopup->bInCallback = false;
5357 : // check for pActivePopup, if stopped by deactivate...
5358 0 : if ( pActivePopup->ImplGetWindow() )
5359 : {
5360 0 : pActivePopup->ImplGetFloatingWindow()->StopExecute();
5361 0 : pActivePopup->ImplGetFloatingWindow()->doShutdown();
5362 0 : pActivePopup->pWindow->doLazyDelete();
5363 0 : pActivePopup->pWindow = NULL;
5364 : }
5365 0 : pActivePopup = 0;
5366 : }
5367 : }
5368 :
5369 0 : void MenuBarWindow::PopupClosed( Menu* pPopup )
5370 : {
5371 0 : if ( pPopup == pActivePopup )
5372 : {
5373 0 : KillActivePopup();
5374 0 : ChangeHighlightItem( ITEMPOS_INVALID, false, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus, false );
5375 : }
5376 0 : }
5377 :
5378 0 : void MenuBarWindow::MouseButtonDown( const MouseEvent& rMEvt )
5379 : {
5380 0 : mbAutoPopup = true;
5381 0 : sal_uInt16 nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
5382 0 : if ( ( nEntry != ITEMPOS_INVALID ) && !pActivePopup )
5383 : {
5384 0 : ChangeHighlightItem( nEntry, false );
5385 : }
5386 : else
5387 : {
5388 0 : KillActivePopup();
5389 0 : ChangeHighlightItem( ITEMPOS_INVALID, false );
5390 : }
5391 0 : }
5392 :
5393 0 : void MenuBarWindow::MouseButtonUp( const MouseEvent& )
5394 : {
5395 0 : }
5396 :
5397 0 : void MenuBarWindow::MouseMove( const MouseEvent& rMEvt )
5398 : {
5399 0 : if ( rMEvt.IsSynthetic() || rMEvt.IsEnterWindow() )
5400 0 : return;
5401 :
5402 0 : if ( rMEvt.IsLeaveWindow() )
5403 : {
5404 0 : if ( nRolloveredItem != ITEMPOS_INVALID && nRolloveredItem != nHighlightedItem )
5405 0 : HighlightItem( nRolloveredItem, false );
5406 :
5407 0 : nRolloveredItem = ITEMPOS_INVALID;
5408 0 : return;
5409 : }
5410 :
5411 0 : sal_uInt16 nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
5412 0 : if ( nHighlightedItem == ITEMPOS_INVALID )
5413 : {
5414 0 : if ( nRolloveredItem != nEntry )
5415 : {
5416 0 : if ( nRolloveredItem != ITEMPOS_INVALID )
5417 0 : HighlightItem( nRolloveredItem, false );
5418 :
5419 0 : nRolloveredItem = nEntry;
5420 0 : HighlightItem( nRolloveredItem, true );
5421 : }
5422 0 : return;
5423 : }
5424 0 : nRolloveredItem = nEntry;
5425 :
5426 0 : if( bIgnoreFirstMove )
5427 : {
5428 0 : bIgnoreFirstMove = false;
5429 0 : return;
5430 : }
5431 :
5432 0 : if ( ( nEntry != ITEMPOS_INVALID )
5433 0 : && ( nEntry != nHighlightedItem ) )
5434 0 : ChangeHighlightItem( nEntry, false );
5435 : }
5436 :
5437 0 : void MenuBarWindow::ChangeHighlightItem( sal_uInt16 n, bool bSelectEntry, bool bAllowRestoreFocus, bool bDefaultToDocument)
5438 : {
5439 0 : if( ! pMenu )
5440 0 : return;
5441 :
5442 : // #57934# close active popup if applicable, as TH's background storage works.
5443 0 : MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n );
5444 0 : if ( pActivePopup && pActivePopup->ImplGetWindow() && ( !pNextData || ( pActivePopup != pNextData->pSubMenu ) ) )
5445 0 : KillActivePopup(); // pActivePopup when applicable without pWin, if Rescheduled in Activate()
5446 :
5447 : // activate menubar only ones per cycle...
5448 0 : bool bJustActivated = false;
5449 0 : if ( ( nHighlightedItem == ITEMPOS_INVALID ) && ( n != ITEMPOS_INVALID ) )
5450 : {
5451 0 : ImplGetSVData()->maWinData.mbNoDeactivate = true;
5452 0 : if( !bStayActive )
5453 : {
5454 : // #105406# avoid saving the focus when we already have the focus
5455 0 : bool bNoSaveFocus = (this == ImplGetSVData()->maWinData.mpFocusWin );
5456 :
5457 0 : if( nSaveFocusId )
5458 : {
5459 0 : if( !ImplGetSVData()->maWinData.mbNoSaveFocus )
5460 : {
5461 : // we didn't clean up last time
5462 0 : Window::EndSaveFocus( nSaveFocusId, false ); // clean up
5463 0 : nSaveFocusId = 0;
5464 0 : if( !bNoSaveFocus )
5465 0 : nSaveFocusId = Window::SaveFocus(); // only save focus when initially activated
5466 : }
5467 : else {
5468 : ; // do nothing: we 're activated again from taskpanelist, focus was already saved
5469 : }
5470 : }
5471 : else
5472 : {
5473 0 : if( !bNoSaveFocus )
5474 0 : nSaveFocusId = Window::SaveFocus(); // only save focus when initially activated
5475 : }
5476 : }
5477 : else
5478 0 : bStayActive = false;
5479 0 : pMenu->bInCallback = true; // set here if Activate overloaded
5480 0 : pMenu->Activate();
5481 0 : pMenu->bInCallback = false;
5482 0 : bJustActivated = true;
5483 : }
5484 0 : else if ( ( nHighlightedItem != ITEMPOS_INVALID ) && ( n == ITEMPOS_INVALID ) )
5485 : {
5486 0 : pMenu->bInCallback = true;
5487 0 : pMenu->Deactivate();
5488 0 : pMenu->bInCallback = false;
5489 0 : ImplGetSVData()->maWinData.mbNoDeactivate = false;
5490 0 : if( !ImplGetSVData()->maWinData.mbNoSaveFocus )
5491 : {
5492 0 : sal_uLong nTempFocusId = nSaveFocusId;
5493 0 : nSaveFocusId = 0;
5494 0 : Window::EndSaveFocus( nTempFocusId, bAllowRestoreFocus );
5495 : // #105406# restore focus to document if we could not save focus before
5496 0 : if( bDefaultToDocument && !nTempFocusId && bAllowRestoreFocus )
5497 0 : GrabFocusToDocument();
5498 : }
5499 : }
5500 :
5501 0 : if ( nHighlightedItem != ITEMPOS_INVALID )
5502 : {
5503 0 : if ( nHighlightedItem != nRolloveredItem )
5504 0 : HighlightItem( nHighlightedItem, false );
5505 :
5506 0 : pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
5507 : }
5508 :
5509 0 : nHighlightedItem = (sal_uInt16)n;
5510 : DBG_ASSERT( ( nHighlightedItem == ITEMPOS_INVALID ) || pMenu->ImplIsVisible( nHighlightedItem ), "ChangeHighlightItem: Not visible!" );
5511 0 : if ( nHighlightedItem != ITEMPOS_INVALID )
5512 0 : HighlightItem( nHighlightedItem, true );
5513 0 : else if ( nRolloveredItem != ITEMPOS_INVALID )
5514 0 : HighlightItem( nRolloveredItem, true );
5515 0 : pMenu->SetHighlightItem(nHighlightedItem);
5516 0 : pMenu->ImplCallHighlight(nHighlightedItem);
5517 :
5518 0 : if( mbAutoPopup )
5519 0 : ImplCreatePopup( bSelectEntry );
5520 :
5521 : // #58935# #73659# Focus, if no popup underneath...
5522 0 : if ( bJustActivated && !pActivePopup )
5523 0 : GrabFocus();
5524 : }
5525 :
5526 0 : void MenuBarWindow::HighlightItem( sal_uInt16 nPos, bool bHighlight )
5527 : {
5528 0 : if( ! pMenu )
5529 0 : return;
5530 :
5531 0 : long nX = 0;
5532 0 : size_t nCount = pMenu->pItemList->size();
5533 0 : for ( size_t n = 0; n < nCount; n++ )
5534 : {
5535 0 : MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
5536 0 : if ( n == nPos )
5537 : {
5538 0 : if ( pData->eType != MENUITEM_SEPARATOR )
5539 : {
5540 : // #107747# give menuitems the height of the menubar
5541 0 : Rectangle aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) );
5542 0 : Push( PUSH_CLIPREGION );
5543 0 : IntersectClipRegion( aRect );
5544 0 : bool bRollover = bHighlight && nPos != nHighlightedItem;
5545 0 : if ( bHighlight )
5546 : {
5547 0 : if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) &&
5548 0 : IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
5549 : {
5550 : // draw background (transparency)
5551 0 : MenubarValue aControlValue;
5552 0 : aControlValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
5553 :
5554 0 : if ( !Application::GetSettings().GetStyleSettings().GetPersonaHeader().IsEmpty() )
5555 0 : Erase();
5556 : else
5557 : {
5558 0 : Point tmp(0,0);
5559 0 : Rectangle aBgRegion( tmp, GetOutputSizePixel() );
5560 : DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL,
5561 : aBgRegion,
5562 : CTRL_STATE_ENABLED,
5563 : aControlValue,
5564 0 : OUString() );
5565 : }
5566 :
5567 0 : ImplAddNWFSeparator( this, aControlValue );
5568 :
5569 : // draw selected item
5570 0 : ControlState nState = CTRL_STATE_ENABLED;
5571 0 : if ( bRollover )
5572 0 : nState |= CTRL_STATE_ROLLOVER;
5573 : else
5574 0 : nState |= CTRL_STATE_SELECTED;
5575 : DrawNativeControl( CTRL_MENUBAR, PART_MENU_ITEM,
5576 : aRect,
5577 : nState,
5578 : aControlValue,
5579 0 : OUString() );
5580 : }
5581 : else
5582 : {
5583 0 : if ( bRollover )
5584 0 : SetFillColor( GetSettings().GetStyleSettings().GetMenuBarRolloverColor() );
5585 : else
5586 0 : SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
5587 0 : SetLineColor();
5588 0 : DrawRect( aRect );
5589 : }
5590 : }
5591 : else
5592 : {
5593 0 : if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) )
5594 : {
5595 0 : MenubarValue aMenubarValue;
5596 0 : aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
5597 :
5598 0 : if ( !Application::GetSettings().GetStyleSettings().GetPersonaHeader().IsEmpty() )
5599 0 : Erase( aRect );
5600 : else
5601 : {
5602 : // use full window size to get proper gradient
5603 : // but clip accordingly
5604 0 : Point aPt;
5605 0 : Rectangle aCtrlRect( aPt, GetOutputSizePixel() );
5606 :
5607 0 : DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED, aMenubarValue, OUString() );
5608 : }
5609 :
5610 0 : ImplAddNWFSeparator( this, aMenubarValue );
5611 : }
5612 : else
5613 0 : Erase( aRect );
5614 : }
5615 0 : Pop();
5616 0 : pMenu->ImplPaint( this, 0, 0, pData, bHighlight, false, bRollover );
5617 : }
5618 0 : return;
5619 : }
5620 :
5621 0 : nX += pData->aSz.Width();
5622 : }
5623 : }
5624 :
5625 0 : Rectangle MenuBarWindow::ImplGetItemRect( sal_uInt16 nPos )
5626 : {
5627 0 : Rectangle aRect;
5628 0 : if( pMenu )
5629 : {
5630 0 : long nX = 0;
5631 0 : size_t nCount = pMenu->pItemList->size();
5632 0 : for ( size_t n = 0; n < nCount; n++ )
5633 : {
5634 0 : MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
5635 0 : if ( n == nPos )
5636 : {
5637 0 : if ( pData->eType != MENUITEM_SEPARATOR )
5638 : // #107747# give menuitems the height of the menubar
5639 0 : aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) );
5640 0 : break;
5641 : }
5642 :
5643 0 : nX += pData->aSz.Width();
5644 : }
5645 : }
5646 0 : return aRect;
5647 : }
5648 :
5649 0 : void MenuBarWindow::KeyInput( const KeyEvent& rKEvent )
5650 : {
5651 0 : if ( !ImplHandleKeyEvent( rKEvent ) )
5652 0 : Window::KeyInput( rKEvent );
5653 0 : }
5654 :
5655 0 : bool MenuBarWindow::ImplHandleKeyEvent( const KeyEvent& rKEvent, bool bFromMenu )
5656 : {
5657 0 : if( ! pMenu )
5658 0 : return false;
5659 :
5660 0 : if ( pMenu->bInCallback )
5661 0 : return true; // swallow
5662 :
5663 0 : bool bDone = false;
5664 0 : sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode();
5665 :
5666 0 : if( GetParent() )
5667 : {
5668 0 : if( GetParent()->GetWindow( WINDOW_CLIENT )->IsSystemWindow() )
5669 : {
5670 0 : SystemWindow *pSysWin = (SystemWindow*)GetParent()->GetWindow( WINDOW_CLIENT );
5671 0 : if( pSysWin->GetTaskPaneList() )
5672 0 : if( pSysWin->GetTaskPaneList()->HandleKeyEvent( rKEvent ) )
5673 0 : return true;
5674 : }
5675 : }
5676 :
5677 0 : if ( nCode == KEY_MENU && !rKEvent.GetKeyCode().IsShift() ) // only F10, not Shift-F10
5678 : {
5679 0 : mbAutoPopup = ImplGetSVData()->maNWFData.mbOpenMenuOnF10;
5680 0 : if ( nHighlightedItem == ITEMPOS_INVALID )
5681 : {
5682 0 : ChangeHighlightItem( 0, false );
5683 0 : GrabFocus();
5684 : }
5685 : else
5686 : {
5687 0 : ChangeHighlightItem( ITEMPOS_INVALID, false );
5688 0 : nSaveFocusId = 0;
5689 : }
5690 0 : bDone = true;
5691 : }
5692 0 : else if ( bFromMenu )
5693 : {
5694 0 : if ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ||
5695 0 : ( nCode == KEY_HOME ) || ( nCode == KEY_END ) )
5696 : {
5697 0 : sal_uInt16 n = nHighlightedItem;
5698 0 : if ( n == ITEMPOS_INVALID )
5699 : {
5700 0 : if ( nCode == KEY_LEFT)
5701 0 : n = 0;
5702 : else
5703 0 : n = pMenu->GetItemCount()-1;
5704 : }
5705 :
5706 : // handling gtk like (aka mbOpenMenuOnF10)
5707 : // do not highlight an item when opening a sub menu
5708 : // unless there already was a higlighted sub menu item
5709 0 : bool bWasHighlight = false;
5710 0 : if( pActivePopup )
5711 : {
5712 0 : MenuFloatingWindow* pSubWindow = dynamic_cast<MenuFloatingWindow*>(pActivePopup->ImplGetWindow());
5713 0 : if( pSubWindow )
5714 0 : bWasHighlight = (pSubWindow->GetHighlightedItem() != ITEMPOS_INVALID);
5715 : }
5716 :
5717 0 : sal_uInt16 nLoop = n;
5718 :
5719 0 : if( nCode == KEY_HOME )
5720 0 : { n = (sal_uInt16)-1; nLoop = n+1; }
5721 0 : if( nCode == KEY_END )
5722 0 : { n = pMenu->GetItemCount(); nLoop = n-1; }
5723 :
5724 0 : do
5725 : {
5726 0 : if ( nCode == KEY_LEFT || nCode == KEY_END )
5727 : {
5728 0 : if ( n )
5729 0 : n--;
5730 : else
5731 0 : n = pMenu->GetItemCount()-1;
5732 : }
5733 0 : if ( nCode == KEY_RIGHT || nCode == KEY_HOME )
5734 : {
5735 0 : n++;
5736 0 : if ( n >= pMenu->GetItemCount() )
5737 0 : n = 0;
5738 : }
5739 :
5740 0 : MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n );
5741 0 : if ( ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) )
5742 : {
5743 0 : bool bDoSelect = true;
5744 0 : if( ImplGetSVData()->maNWFData.mbOpenMenuOnF10 )
5745 0 : bDoSelect = bWasHighlight;
5746 0 : ChangeHighlightItem( n, bDoSelect );
5747 0 : break;
5748 : }
5749 : } while ( n != nLoop );
5750 0 : bDone = true;
5751 : }
5752 0 : else if ( nCode == KEY_RETURN )
5753 : {
5754 0 : if( pActivePopup ) KillActivePopup();
5755 : else
5756 0 : if ( !mbAutoPopup )
5757 : {
5758 0 : ImplCreatePopup( true );
5759 0 : mbAutoPopup = true;
5760 : }
5761 0 : bDone = true;
5762 : }
5763 0 : else if ( ( nCode == KEY_UP ) || ( nCode == KEY_DOWN ) )
5764 : {
5765 0 : if ( !mbAutoPopup )
5766 : {
5767 0 : ImplCreatePopup( true );
5768 0 : mbAutoPopup = true;
5769 : }
5770 0 : bDone = true;
5771 : }
5772 0 : else if ( nCode == KEY_ESCAPE || ( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() ) )
5773 : {
5774 0 : if( pActivePopup )
5775 : {
5776 : // bring focus to menu bar without any open popup
5777 0 : mbAutoPopup = false;
5778 0 : sal_uInt16 n = nHighlightedItem;
5779 0 : nHighlightedItem = ITEMPOS_INVALID;
5780 0 : bStayActive = true;
5781 0 : ChangeHighlightItem( n, false );
5782 0 : bStayActive = false;
5783 0 : KillActivePopup();
5784 0 : GrabFocus();
5785 : }
5786 : else
5787 0 : ChangeHighlightItem( ITEMPOS_INVALID, false );
5788 :
5789 0 : if( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() )
5790 : {
5791 : // put focus into document
5792 0 : GrabFocusToDocument();
5793 : }
5794 :
5795 0 : bDone = true;
5796 : }
5797 : }
5798 :
5799 0 : if ( !bDone && ( bFromMenu || rKEvent.GetKeyCode().IsMod2() ) )
5800 : {
5801 0 : sal_Unicode nCharCode = rKEvent.GetCharCode();
5802 0 : if ( nCharCode )
5803 : {
5804 : sal_uInt16 nEntry, nDuplicates;
5805 0 : MenuItemData* pData = pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nEntry, nDuplicates, nHighlightedItem );
5806 0 : if ( pData && (nEntry != ITEMPOS_INVALID) )
5807 : {
5808 0 : mbAutoPopup = true;
5809 0 : ChangeHighlightItem( nEntry, true );
5810 0 : bDone = true;
5811 : }
5812 : }
5813 : }
5814 0 : return bDone;
5815 : }
5816 :
5817 0 : void MenuBarWindow::Paint( const Rectangle& )
5818 : {
5819 0 : if( ! pMenu )
5820 0 : return;
5821 :
5822 : // no VCL paint if native menus
5823 0 : if( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() )
5824 : {
5825 0 : ImplGetFrame()->DrawMenuBar();
5826 0 : return;
5827 : }
5828 :
5829 0 : if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) )
5830 : {
5831 0 : MenubarValue aMenubarValue;
5832 0 : aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
5833 :
5834 0 : if ( !Application::GetSettings().GetStyleSettings().GetPersonaHeader().IsEmpty() )
5835 0 : Erase();
5836 : else
5837 : {
5838 0 : Point aPt;
5839 0 : Rectangle aCtrlRegion( aPt, GetOutputSizePixel() );
5840 :
5841 0 : DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRegion, CTRL_STATE_ENABLED, aMenubarValue, OUString() );
5842 : }
5843 :
5844 0 : ImplAddNWFSeparator( this, aMenubarValue );
5845 : }
5846 0 : SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
5847 0 : pMenu->ImplPaint( this, 0 );
5848 0 : if ( nHighlightedItem != ITEMPOS_INVALID )
5849 0 : HighlightItem( nHighlightedItem, true );
5850 :
5851 : // in high contrast mode draw a separating line on the lower edge
5852 0 : if( ! IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) &&
5853 0 : GetSettings().GetStyleSettings().GetHighContrastMode() )
5854 : {
5855 0 : Push( PUSH_LINECOLOR | PUSH_MAPMODE );
5856 0 : SetLineColor( Color( COL_WHITE ) );
5857 0 : SetMapMode( MapMode( MAP_PIXEL ) );
5858 0 : Size aSize = GetSizePixel();
5859 0 : DrawLine( Point( 0, aSize.Height()-1 ), Point( aSize.Width()-1, aSize.Height()-1 ) );
5860 0 : Pop();
5861 : }
5862 :
5863 : }
5864 :
5865 0 : void MenuBarWindow::Resize()
5866 : {
5867 0 : Size aOutSz = GetOutputSizePixel();
5868 0 : long n = aOutSz.Height()-4;
5869 0 : long nX = aOutSz.Width()-3;
5870 0 : long nY = 2;
5871 :
5872 0 : if ( aCloser.IsVisible() )
5873 : {
5874 0 : aCloser.Hide();
5875 0 : aCloser.SetImages( n );
5876 0 : Size aTbxSize( aCloser.CalcWindowSizePixel() );
5877 0 : nX -= aTbxSize.Width();
5878 0 : long nTbxY = (aOutSz.Height() - aTbxSize.Height())/2;
5879 0 : aCloser.setPosSizePixel( nX, nTbxY, aTbxSize.Width(), aTbxSize.Height() );
5880 0 : nX -= 3;
5881 0 : aCloser.Show();
5882 : }
5883 0 : if ( aFloatBtn.IsVisible() )
5884 : {
5885 0 : nX -= n;
5886 0 : aFloatBtn.setPosSizePixel( nX, nY, n, n );
5887 : }
5888 0 : if ( aHideBtn.IsVisible() )
5889 : {
5890 0 : nX -= n;
5891 0 : aHideBtn.setPosSizePixel( nX, nY, n, n );
5892 : }
5893 :
5894 0 : aFloatBtn.SetSymbol( SYMBOL_FLOAT );
5895 0 : aHideBtn.SetSymbol( SYMBOL_HIDE );
5896 : //aCloser.SetSymbol( SYMBOL_CLOSE ); //is a toolbox now
5897 :
5898 0 : Invalidate();
5899 0 : }
5900 :
5901 0 : sal_uInt16 MenuBarWindow::ImplFindEntry( const Point& rMousePos ) const
5902 : {
5903 0 : if( pMenu )
5904 : {
5905 0 : long nX = 0;
5906 0 : size_t nCount = pMenu->pItemList->size();
5907 0 : for ( size_t n = 0; n < nCount; n++ )
5908 : {
5909 0 : MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
5910 0 : if ( pMenu->ImplIsVisible( n ) )
5911 : {
5912 0 : nX += pData->aSz.Width();
5913 0 : if ( nX > rMousePos.X() )
5914 0 : return (sal_uInt16)n;
5915 : }
5916 : }
5917 : }
5918 0 : return ITEMPOS_INVALID;
5919 : }
5920 :
5921 0 : void MenuBarWindow::RequestHelp( const HelpEvent& rHEvt )
5922 : {
5923 0 : sal_uInt16 nId = nHighlightedItem;
5924 0 : if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
5925 0 : ChangeHighlightItem( ITEMPOS_INVALID, true );
5926 :
5927 0 : Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) );
5928 0 : if( !ImplHandleHelpEvent( this, pMenu, nId, rHEvt, aHighlightRect ) )
5929 0 : Window::RequestHelp( rHEvt );
5930 0 : }
5931 :
5932 0 : void MenuBarWindow::StateChanged( StateChangedType nType )
5933 : {
5934 0 : Window::StateChanged( nType );
5935 :
5936 0 : if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) ||
5937 : ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
5938 : {
5939 0 : ImplInitMenuWindow( this, false, true );
5940 0 : Invalidate();
5941 : }
5942 0 : else if( pMenu )
5943 0 : pMenu->ImplKillLayoutData();
5944 :
5945 0 : }
5946 :
5947 0 : void MenuBarWindow::ImplLayoutChanged()
5948 : {
5949 0 : if( pMenu )
5950 : {
5951 0 : ImplInitMenuWindow( this, true, true );
5952 : // if the font was changed.
5953 0 : long nHeight = pMenu->ImplCalcSize( this ).Height();
5954 :
5955 : // depending on the native implementation or the displayable flag
5956 : // the menubar windows is supressed (ie, height=0)
5957 0 : if( !((MenuBar*) pMenu)->IsDisplayable() ||
5958 0 : ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) )
5959 0 : nHeight = 0;
5960 :
5961 0 : setPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT );
5962 0 : GetParent()->Resize();
5963 0 : Invalidate();
5964 0 : Resize();
5965 0 : if( pMenu )
5966 0 : pMenu->ImplKillLayoutData();
5967 : }
5968 0 : }
5969 :
5970 0 : void MenuBarWindow::ImplInitStyleSettings()
5971 : {
5972 0 : if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) &&
5973 0 : IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
5974 : {
5975 0 : AllSettings aSettings( GetSettings() );
5976 0 : ImplGetFrame()->UpdateSettings( aSettings ); // to update persona
5977 0 : StyleSettings aStyle( aSettings.GetStyleSettings() );
5978 0 : Color aHighlightTextColor = ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor;
5979 0 : if( aHighlightTextColor != Color( COL_TRANSPARENT ) )
5980 : {
5981 0 : aStyle.SetMenuHighlightTextColor( aHighlightTextColor );
5982 : }
5983 0 : aSettings.SetStyleSettings( aStyle );
5984 0 : OutputDevice::SetSettings( aSettings );
5985 : }
5986 0 : }
5987 :
5988 0 : void MenuBarWindow::DataChanged( const DataChangedEvent& rDCEvt )
5989 : {
5990 0 : Window::DataChanged( rDCEvt );
5991 :
5992 0 : if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
5993 0 : (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
5994 0 : ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
5995 0 : (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
5996 : {
5997 0 : ImplInitStyleSettings();
5998 0 : ImplLayoutChanged();
5999 : }
6000 0 : }
6001 :
6002 0 : void MenuBarWindow::LoseFocus()
6003 : {
6004 0 : if ( !HasChildPathFocus( true ) )
6005 0 : ChangeHighlightItem( ITEMPOS_INVALID, false, false );
6006 0 : }
6007 :
6008 0 : void MenuBarWindow::GetFocus()
6009 : {
6010 0 : if ( nHighlightedItem == ITEMPOS_INVALID )
6011 : {
6012 0 : mbAutoPopup = false; // do not open menu when activated by focus handling like taskpane cycling
6013 0 : ChangeHighlightItem( 0, false );
6014 : }
6015 0 : }
6016 :
6017 0 : ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuBarWindow::CreateAccessible()
6018 : {
6019 0 : ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc;
6020 :
6021 0 : if ( pMenu )
6022 0 : xAcc = pMenu->GetAccessible();
6023 :
6024 0 : return xAcc;
6025 : }
6026 :
6027 0 : sal_uInt16 MenuBarWindow::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const OUString& i_rToolTip, sal_uInt16 i_nPos )
6028 : {
6029 : // find first free button id
6030 0 : sal_uInt16 nId = IID_DOCUMENTCLOSE;
6031 0 : std::map< sal_uInt16, AddButtonEntry >::const_iterator it;
6032 0 : if( i_nPos > m_aAddButtons.size() )
6033 0 : i_nPos = static_cast<sal_uInt16>(m_aAddButtons.size());
6034 0 : do
6035 : {
6036 0 : nId++;
6037 0 : it = m_aAddButtons.find( nId );
6038 0 : } while( it != m_aAddButtons.end() && nId < 128 );
6039 : DBG_ASSERT( nId < 128, "too many addbuttons in menubar" );
6040 0 : AddButtonEntry& rNewEntry = m_aAddButtons[nId];
6041 0 : rNewEntry.m_nId = nId;
6042 0 : rNewEntry.m_aSelectLink = i_rLink;
6043 0 : aCloser.InsertItem( nId, i_rImage, 0, 0 );
6044 0 : aCloser.calcMinSize();
6045 0 : ShowButtons( aCloser.IsItemVisible( IID_DOCUMENTCLOSE ),
6046 0 : aFloatBtn.IsVisible(),
6047 0 : aHideBtn.IsVisible() );
6048 0 : ImplLayoutChanged();
6049 :
6050 0 : if( pMenu->mpSalMenu )
6051 0 : pMenu->mpSalMenu->AddMenuBarButton( SalMenuButtonItem( nId, i_rImage, i_rToolTip ) );
6052 :
6053 0 : return nId;
6054 : }
6055 :
6056 0 : void MenuBarWindow::SetMenuBarButtonHighlightHdl( sal_uInt16 nId, const Link& rLink )
6057 : {
6058 0 : std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( nId );
6059 0 : if( it != m_aAddButtons.end() )
6060 0 : it->second.m_aHighlightLink = rLink;
6061 0 : }
6062 :
6063 0 : Rectangle MenuBarWindow::GetMenuBarButtonRectPixel( sal_uInt16 nId )
6064 : {
6065 0 : Rectangle aRect;
6066 0 : if( m_aAddButtons.find( nId ) != m_aAddButtons.end() )
6067 : {
6068 0 : if( pMenu->mpSalMenu )
6069 : {
6070 0 : aRect = pMenu->mpSalMenu->GetMenuBarButtonRectPixel( nId, ImplGetWindowImpl()->mpFrame );
6071 0 : if( aRect == Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) )
6072 : {
6073 : // system menu button is somewhere but location cannot be determined
6074 0 : return Rectangle();
6075 : }
6076 : }
6077 :
6078 0 : if( aRect.IsEmpty() )
6079 : {
6080 0 : aRect = aCloser.GetItemRect( nId );
6081 0 : Point aOffset = aCloser.OutputToScreenPixel( Point() );
6082 0 : aRect.Move( aOffset.X(), aOffset.Y() );
6083 : }
6084 : }
6085 0 : return aRect;
6086 : }
6087 :
6088 0 : void MenuBarWindow::RemoveMenuBarButton( sal_uInt16 nId )
6089 : {
6090 0 : sal_uInt16 nPos = aCloser.GetItemPos( nId );
6091 0 : aCloser.RemoveItem( nPos );
6092 0 : m_aAddButtons.erase( nId );
6093 0 : aCloser.calcMinSize();
6094 0 : ImplLayoutChanged();
6095 :
6096 0 : if( pMenu->mpSalMenu )
6097 0 : pMenu->mpSalMenu->RemoveMenuBarButton( nId );
6098 0 : }
6099 :
6100 0 : bool MenuBarWindow::HandleMenuButtonEvent( sal_uInt16 i_nButtonId )
6101 : {
6102 0 : std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( i_nButtonId );
6103 0 : if( it != m_aAddButtons.end() )
6104 : {
6105 : MenuBar::MenuBarButtonCallbackArg aArg;
6106 0 : aArg.nId = it->first;
6107 0 : aArg.bHighlight = true;
6108 0 : aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
6109 0 : return it->second.m_aSelectLink.Call( &aArg );
6110 : }
6111 0 : return false;
6112 : }
6113 :
6114 0 : ImplMenuDelData::ImplMenuDelData( const Menu* pMenu )
6115 : : mpNext( 0 )
6116 0 : , mpMenu( 0 )
6117 : {
6118 0 : if( pMenu )
6119 0 : const_cast< Menu* >( pMenu )->ImplAddDel( *this );
6120 0 : }
6121 :
6122 0 : ImplMenuDelData::~ImplMenuDelData()
6123 : {
6124 0 : if( mpMenu )
6125 0 : const_cast< Menu* >( mpMenu )->ImplRemoveDel( *this );
6126 0 : }
6127 :
6128 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|