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