xref: /aoo42x/main/vcl/source/window/menu.cxx (revision 79aad27f)
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/xwphook.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 
1577 void Menu::SetItemBits( sal_uInt16 nItemId, MenuItemBits nBits )
1578 {
1579     MenuItemData* pData = pItemList->GetData( nItemId );
1580     if ( pData )
1581         pData->nBits = nBits;
1582 }
1583 
1584 MenuItemBits Menu::GetItemBits( sal_uInt16 nItemId ) const
1585 {
1586     MenuItemBits nBits = 0;
1587     MenuItemData* pData = pItemList->GetData( nItemId );
1588     if ( pData )
1589         nBits = pData->nBits;
1590     return nBits;
1591 }
1592 
1593 void Menu::SetUserValue( sal_uInt16 nItemId, sal_uLong nValue )
1594 {
1595     MenuItemData* pData = pItemList->GetData( nItemId );
1596     if ( pData )
1597         pData->nUserValue = nValue;
1598 }
1599 
1600 sal_uLong Menu::GetUserValue( sal_uInt16 nItemId ) const
1601 {
1602     MenuItemData* pData = pItemList->GetData( nItemId );
1603     return pData ? pData->nUserValue : 0;
1604 }
1605 
1606 void Menu::SetPopupMenu( sal_uInt16 nItemId, PopupMenu* pMenu )
1607 {
1608     sal_uInt16          nPos;
1609     MenuItemData*   pData = pItemList->GetData( nItemId, nPos );
1610 
1611     // Item does not exist -> return NULL
1612     if ( !pData )
1613         return;
1614 
1615     // same menu, nothing to do
1616     if ( (PopupMenu*)pData->pSubMenu == pMenu )
1617         return;
1618 
1619     // data exchange
1620     pData->pSubMenu = pMenu;
1621 
1622     // #112023# Make sure pStartedFrom does not point to invalid (old) data
1623     if ( pData->pSubMenu )
1624         pData->pSubMenu->pStartedFrom = 0;
1625 
1626     // set native submenu
1627     if( ImplGetSalMenu() && pData->pSalMenuItem )
1628     {
1629         if( pMenu )
1630             ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, pMenu->ImplGetSalMenu(), nPos );
1631         else
1632             ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, NULL, nPos );
1633     }
1634 
1635     ImplCallEventListeners( VCLEVENT_MENU_SUBMENUCHANGED, nPos );
1636 }
1637 
1638 PopupMenu* Menu::GetPopupMenu( sal_uInt16 nItemId ) const
1639 {
1640     MenuItemData* pData = pItemList->GetData( nItemId );
1641 
1642     if ( pData )
1643         return (PopupMenu*)(pData->pSubMenu);
1644     else
1645         return NULL;
1646 }
1647 
1648 void Menu::SetAccelKey( sal_uInt16 nItemId, const KeyCode& rKeyCode )
1649 {
1650     sal_uInt16          nPos;
1651     MenuItemData*   pData = pItemList->GetData( nItemId, nPos );
1652 
1653     if ( !pData )
1654         return;
1655 
1656     if ( pData->aAccelKey == rKeyCode )
1657         return;
1658 
1659     pData->aAccelKey = rKeyCode;
1660 
1661     // update native menu
1662     if( ImplGetSalMenu() && pData->pSalMenuItem )
1663         ImplGetSalMenu()->SetAccelerator( nPos, pData->pSalMenuItem, rKeyCode, rKeyCode.GetName() );
1664 }
1665 
1666 KeyCode Menu::GetAccelKey( sal_uInt16 nItemId ) const
1667 {
1668     MenuItemData* pData = pItemList->GetData( nItemId );
1669 
1670     if ( pData )
1671         return pData->aAccelKey;
1672     else
1673         return KeyCode();
1674 }
1675 
1676 KeyEvent Menu::GetActivationKey( sal_uInt16 nItemId ) const
1677 {
1678     KeyEvent aRet;
1679     MenuItemData* pData = pItemList->GetData( nItemId );
1680     if( pData )
1681     {
1682         sal_uInt16 nPos = pData->aText.Search( '~' );
1683         if( nPos != STRING_NOTFOUND && nPos < pData->aText.Len()-1 )
1684         {
1685             sal_uInt16 nCode = 0;
1686             sal_Unicode cAccel = pData->aText.GetChar( nPos+1 );
1687             if( cAccel >= 'a' && cAccel <= 'z' )
1688                 nCode = KEY_A + (cAccel-'a');
1689             else if( cAccel >= 'A' && cAccel <= 'Z' )
1690                 nCode = KEY_A + (cAccel-'A');
1691             else if( cAccel >= '0' && cAccel <= '9' )
1692                 nCode = KEY_0 + (cAccel-'0');
1693             if(nCode )
1694                 aRet = KeyEvent( cAccel, KeyCode( nCode, KEY_MOD2 ) );
1695         }
1696 
1697     }
1698     return aRet;
1699 }
1700 
1701 void Menu::CheckItem( sal_uInt16 nItemId, sal_Bool bCheck )
1702 {
1703     sal_uInt16 nPos;
1704     MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1705 
1706     if ( !pData || pData->bChecked == bCheck )
1707         return;
1708 
1709     // Wenn RadioCheck, dann vorherigen unchecken
1710     if ( bCheck && (pData->nBits & MIB_AUTOCHECK) &&
1711          (pData->nBits & MIB_RADIOCHECK) )
1712     {
1713         MenuItemData*   pGroupData;
1714         sal_uInt16          nGroupPos;
1715         sal_uInt16          nItemCount = GetItemCount();
1716         sal_Bool            bFound = sal_False;
1717 
1718         nGroupPos = nPos;
1719         while ( nGroupPos )
1720         {
1721             pGroupData = pItemList->GetDataFromPos( nGroupPos-1 );
1722             if ( pGroupData->nBits & MIB_RADIOCHECK )
1723             {
1724                 if ( IsItemChecked( pGroupData->nId ) )
1725                 {
1726                     CheckItem( pGroupData->nId, sal_False );
1727                     bFound = sal_True;
1728                     break;
1729                 }
1730             }
1731             else
1732                 break;
1733             nGroupPos--;
1734         }
1735 
1736         if ( !bFound )
1737         {
1738             nGroupPos = nPos+1;
1739             while ( nGroupPos < nItemCount )
1740             {
1741                 pGroupData = pItemList->GetDataFromPos( nGroupPos );
1742                 if ( pGroupData->nBits & MIB_RADIOCHECK )
1743                 {
1744                     if ( IsItemChecked( pGroupData->nId ) )
1745                     {
1746                         CheckItem( pGroupData->nId, sal_False );
1747                         break;
1748                     }
1749                 }
1750                 else
1751                     break;
1752                 nGroupPos++;
1753             }
1754         }
1755     }
1756 
1757     pData->bChecked = bCheck;
1758 
1759     // update native menu
1760     if( ImplGetSalMenu() )
1761         ImplGetSalMenu()->CheckItem( nPos, bCheck );
1762 
1763 	ImplCallEventListeners( bCheck ? VCLEVENT_MENU_ITEMCHECKED : VCLEVENT_MENU_ITEMUNCHECKED, nPos );
1764 }
1765 
1766 sal_Bool Menu::IsItemChecked( sal_uInt16 nItemId ) const
1767 {
1768     sal_uInt16          nPos;
1769     MenuItemData*   pData = pItemList->GetData( nItemId, nPos );
1770 
1771     if ( !pData )
1772         return sal_False;
1773 
1774     return pData->bChecked;
1775 }
1776 
1777 void Menu::EnableItem( sal_uInt16 nItemId, sal_Bool bEnable )
1778 {
1779     sal_uInt16          nPos;
1780     MenuItemData*   pItemData = pItemList->GetData( nItemId, nPos );
1781 
1782     if ( pItemData && ( pItemData->bEnabled != bEnable ) )
1783     {
1784         pItemData->bEnabled = bEnable;
1785 
1786         Window* pWin = ImplGetWindow();
1787         if ( pWin && pWin->IsVisible() )
1788         {
1789             DBG_ASSERT( bIsMenuBar, "Menu::EnableItem - Popup visible!" );
1790             long nX = 0;
1791             sal_uLong nCount = pItemList->Count();
1792             for ( sal_uLong n = 0; n < nCount; n++ )
1793             {
1794                 MenuItemData* pData = pItemList->GetDataFromPos( n );
1795                 if ( n == nPos )
1796                 {
1797                     pWin->Invalidate( Rectangle( Point( nX, 0 ), Size( pData->aSz.Width(), pData->aSz.Height() ) ) );
1798                     break;
1799                 }
1800                 nX += pData->aSz.Width();
1801             }
1802         }
1803         // update native menu
1804         if( ImplGetSalMenu() )
1805             ImplGetSalMenu()->EnableItem( nPos, bEnable );
1806 
1807         ImplCallEventListeners( bEnable ? VCLEVENT_MENU_ENABLE : VCLEVENT_MENU_DISABLE, nPos );
1808     }
1809 }
1810 
1811 sal_Bool Menu::IsItemEnabled( sal_uInt16 nItemId ) const
1812 {
1813     sal_uInt16          nPos;
1814     MenuItemData*   pData = pItemList->GetData( nItemId, nPos );
1815 
1816     if ( !pData )
1817         return sal_False;
1818 
1819     return pData->bEnabled;
1820 }
1821 
1822 void Menu::ShowItem( sal_uInt16 nItemId, sal_Bool bVisible )
1823 {
1824     sal_uInt16          nPos;
1825     MenuItemData*   pData = pItemList->GetData( nItemId, nPos );
1826 
1827     DBG_ASSERT( !bIsMenuBar, "Menu::ShowItem - ignored for menu bar entries!" );
1828     if ( !bIsMenuBar && pData && ( pData->bVisible != bVisible ) )
1829     {
1830         Window* pWin = ImplGetWindow();
1831         if ( pWin && pWin->IsVisible() )
1832         {
1833             DBG_ASSERT( 0, "Menu::ShowItem - ignored for visible popups!" );
1834             return;
1835         }
1836         pData->bVisible = bVisible;
1837 
1838         // update native menu
1839         // as long as there is no support to hide native menu entries, we just disable them
1840         // TODO: add support to show/hide native menu entries
1841         if( ImplGetSalMenu() )
1842             ImplGetSalMenu()->EnableItem( nPos, bVisible );
1843     }
1844 }
1845 
1846 void Menu::SetItemText( sal_uInt16 nItemId, const XubString& rStr )
1847 {
1848     sal_uInt16          nPos;
1849     MenuItemData*   pData = pItemList->GetData( nItemId, nPos );
1850 
1851     if ( !pData )
1852         return;
1853 
1854 	if ( !rStr.Equals( pData->aText ) )
1855 	{
1856 		pData->aText = rStr;
1857 		ImplSetMenuItemData( pData );
1858         // update native menu
1859         if( ImplGetSalMenu() && pData->pSalMenuItem )
1860             ImplGetSalMenu()->SetItemText( nPos, pData->pSalMenuItem, rStr );
1861 
1862         Window* pWin = ImplGetWindow();
1863         delete mpLayoutData, mpLayoutData = NULL;
1864         if ( pWin && IsMenuBar() )
1865         {
1866             ImplCalcSize( pWin );
1867             if ( pWin->IsVisible() )
1868                 pWin->Invalidate();
1869         }
1870 
1871         ImplCallEventListeners( VCLEVENT_MENU_ITEMTEXTCHANGED, nPos );
1872 	}
1873 }
1874 
1875 XubString Menu::GetItemText( sal_uInt16 nItemId ) const
1876 {
1877     sal_uInt16          nPos;
1878     MenuItemData*   pData = pItemList->GetData( nItemId, nPos );
1879 
1880     if ( pData )
1881         return pData->aText;
1882     else
1883         return ImplGetSVEmptyStr();
1884 }
1885 
1886 void Menu::SetItemImage( sal_uInt16 nItemId, const Image& rImage )
1887 {
1888     sal_uInt16          nPos;
1889     MenuItemData*   pData = pItemList->GetData( nItemId, nPos );
1890 
1891     if ( !pData )
1892         return;
1893 
1894     pData->aImage = rImage;
1895     ImplSetMenuItemData( pData );
1896 
1897     // update native menu
1898     if( ImplGetSalMenu() && pData->pSalMenuItem )
1899         ImplGetSalMenu()->SetItemImage( nPos, pData->pSalMenuItem, rImage );
1900 }
1901 
1902 static inline Image ImplRotImage( const Image& rImage, long nAngle10 )
1903 {
1904     Image 		aRet;
1905 	BitmapEx	aBmpEx( rImage.GetBitmapEx() );
1906 
1907 	aBmpEx.Rotate( nAngle10, COL_WHITE );
1908 
1909     return Image( aBmpEx );
1910 }
1911 
1912 void Menu::SetItemImageAngle( sal_uInt16 nItemId, long nAngle10 )
1913 {
1914     sal_uInt16          nPos;
1915     MenuItemData*   pData = pItemList->GetData( nItemId, nPos );
1916 
1917 	if ( pData )
1918 	{
1919         long nDeltaAngle = (nAngle10 - pData->nItemImageAngle) % 3600;
1920         while( nDeltaAngle < 0 )
1921             nDeltaAngle += 3600;
1922 
1923         pData->nItemImageAngle = nAngle10;
1924         if( nDeltaAngle && !!pData->aImage )
1925             pData->aImage = ImplRotImage( pData->aImage, nDeltaAngle );
1926 	}
1927 }
1928 
1929 static inline Image ImplMirrorImage( const Image& rImage )
1930 {
1931     Image 		aRet;
1932 	BitmapEx	aBmpEx( rImage.GetBitmapEx() );
1933 
1934 	aBmpEx.Mirror( BMP_MIRROR_HORZ );
1935 
1936     return Image( aBmpEx );
1937 }
1938 
1939 void Menu::SetItemImageMirrorMode( sal_uInt16 nItemId, sal_Bool bMirror )
1940 {
1941     sal_uInt16          nPos;
1942     MenuItemData*   pData = pItemList->GetData( nItemId, nPos );
1943 
1944 	if ( pData )
1945 	{
1946         if( ( pData->bMirrorMode && ! bMirror ) ||
1947             ( ! pData->bMirrorMode && bMirror )
1948             )
1949         {
1950             pData->bMirrorMode = bMirror ? true : false;
1951             if( !!pData->aImage )
1952                 pData->aImage = ImplMirrorImage( pData->aImage );
1953         }
1954     }
1955 }
1956 
1957 Image Menu::GetItemImage( sal_uInt16 nItemId ) const
1958 {
1959     MenuItemData* pData = pItemList->GetData( nItemId );
1960 
1961     if ( pData )
1962         return pData->aImage;
1963     else
1964         return Image();
1965 }
1966 
1967 long Menu::GetItemImageAngle( sal_uInt16 nItemId ) const
1968 {
1969     MenuItemData* pData = pItemList->GetData( nItemId );
1970 
1971 	if ( pData )
1972 		return pData->nItemImageAngle;
1973 	else
1974 		return 0;
1975 }
1976 
1977 sal_Bool Menu::GetItemImageMirrorMode( sal_uInt16 nItemId ) const
1978 {
1979     MenuItemData* pData = pItemList->GetData( nItemId );
1980 
1981 	if ( pData )
1982 		return pData->bMirrorMode;
1983 	else
1984 		return sal_False;
1985 }
1986 
1987 void Menu::SetItemCommand( sal_uInt16 nItemId, const String& rCommand )
1988 {
1989     MenuItemData* pData = pItemList->GetData( nItemId );
1990 
1991     if ( pData )
1992         pData->aCommandStr = rCommand;
1993 }
1994 
1995 const XubString& Menu::GetItemCommand( sal_uInt16 nItemId ) const
1996 {
1997     MenuItemData* pData = pItemList->GetData( nItemId );
1998 
1999     if ( pData )
2000         return pData->aCommandStr;
2001     else
2002         return ImplGetSVEmptyStr();
2003 }
2004 
2005 void Menu::SetHelpCommand( sal_uInt16 nItemId, const XubString& rStr )
2006 {
2007     MenuItemData* pData = pItemList->GetData( nItemId );
2008 
2009     if ( pData )
2010         pData->aHelpCommandStr = rStr;
2011 }
2012 
2013 const XubString& Menu::GetHelpCommand( sal_uInt16 nItemId ) const
2014 {
2015     MenuItemData* pData = pItemList->GetData( nItemId );
2016 
2017     if ( pData )
2018         return pData->aHelpCommandStr;
2019     else
2020         return ImplGetSVEmptyStr();
2021 }
2022 
2023 void Menu::SetHelpText( sal_uInt16 nItemId, const XubString& rStr )
2024 {
2025     MenuItemData* pData = pItemList->GetData( nItemId );
2026 
2027     if ( pData )
2028         pData->aHelpText = rStr;
2029 }
2030 
2031 const XubString& Menu::ImplGetHelpText( sal_uInt16 nItemId ) const
2032 {
2033     MenuItemData* pData = pItemList->GetData( nItemId );
2034 
2035     if ( pData )
2036     {
2037         if ( !pData->aHelpText.Len() &&
2038              (( pData->aHelpId.getLength()  ) || ( pData->aCommandStr.Len() )))
2039         {
2040             Help* pHelp = Application::GetHelp();
2041             if ( pHelp )
2042             {
2043                 if ( pData->aCommandStr.Len() )
2044                     pData->aHelpText = pHelp->GetHelpText( pData->aCommandStr, NULL );
2045 
2046                 if( !pData->aHelpText.Len() && pData->aHelpId.getLength() )
2047                     pData->aHelpText = pHelp->GetHelpText( rtl::OStringToOUString( pData->aHelpId, RTL_TEXTENCODING_UTF8 ), NULL );
2048             }
2049         }
2050 
2051         return pData->aHelpText;
2052     }
2053     else
2054         return ImplGetSVEmptyStr();
2055 }
2056 
2057 const XubString& Menu::GetHelpText( sal_uInt16 nItemId ) const
2058 {
2059     return ImplGetHelpText( nItemId );
2060 }
2061 
2062 void Menu::SetTipHelpText( sal_uInt16 nItemId, const XubString& rStr )
2063 {
2064     MenuItemData* pData = pItemList->GetData( nItemId );
2065 
2066     if ( pData )
2067         pData->aTipHelpText = rStr;
2068 }
2069 
2070 const XubString& Menu::GetTipHelpText( sal_uInt16 nItemId ) const
2071 {
2072     MenuItemData* pData = pItemList->GetData( nItemId );
2073 
2074     if ( pData )
2075         return pData->aTipHelpText;
2076     else
2077         return ImplGetSVEmptyStr();
2078 }
2079 
2080 void Menu::SetHelpId( sal_uInt16 nItemId, const rtl::OString& rHelpId )
2081 {
2082     MenuItemData* pData = pItemList->GetData( nItemId );
2083 
2084     if ( pData )
2085         pData->aHelpId = rHelpId;
2086 }
2087 
2088 rtl::OString Menu::GetHelpId( sal_uInt16 nItemId ) const
2089 {
2090     rtl::OString aRet;
2091 
2092     MenuItemData* pData = pItemList->GetData( nItemId );
2093 
2094     if ( pData )
2095     {
2096         if ( pData->aHelpId.getLength() )
2097             aRet = pData->aHelpId;
2098         else
2099             aRet = ::rtl::OUStringToOString( pData->aCommandStr, RTL_TEXTENCODING_UTF8 );
2100     }
2101 
2102     return aRet;
2103 }
2104 
2105 Menu& Menu::operator=( const Menu& rMenu )
2106 {
2107     // Aufraeumen
2108     Clear();
2109 
2110     // Items kopieren
2111     sal_uInt16 nCount = rMenu.GetItemCount();
2112     for ( sal_uInt16 i = 0; i < nCount; i++ )
2113         ImplCopyItem( this, rMenu, i, MENU_APPEND, 1 );
2114 
2115     nDefaultItem = rMenu.nDefaultItem;
2116     aActivateHdl = rMenu.aActivateHdl;
2117     aDeactivateHdl = rMenu.aDeactivateHdl;
2118     aHighlightHdl = rMenu.aHighlightHdl;
2119     aSelectHdl = rMenu.aSelectHdl;
2120     aTitleText = rMenu.aTitleText;
2121     bIsMenuBar = rMenu.bIsMenuBar;
2122 
2123     return *this;
2124 }
2125 
2126 sal_Bool Menu::ImplIsVisible( sal_uInt16 nPos ) const
2127 {
2128     sal_Bool bVisible = sal_True;
2129 
2130     MenuItemData* pData = pItemList->GetDataFromPos( nPos );
2131     // check general visibility first
2132     if( pData && !pData->bVisible )
2133         bVisible = sal_False;
2134 
2135     if ( bVisible && pData && pData->eType == MENUITEM_SEPARATOR )
2136     {
2137         if( nPos == 0 ) // no separator should be shown at the very beginning
2138             bVisible = sal_False;
2139         else
2140         {
2141             // always avoid adjacent separators
2142             sal_uInt16 nCount = (sal_uInt16) pItemList->Count();
2143             sal_uInt16 n;
2144             MenuItemData* pNextData = NULL;
2145             // search next visible item
2146             for( n = nPos + 1; n < nCount; n++ )
2147             {
2148                 pNextData = pItemList->GetDataFromPos( n );
2149                 if( pNextData && pNextData->bVisible )
2150                 {
2151                     if( pNextData->eType == MENUITEM_SEPARATOR || ImplIsVisible(n) )
2152                         break;
2153                 }
2154             }
2155             if( n == nCount ) // no next visible item
2156                 bVisible = sal_False;
2157             // check for separator
2158             if( pNextData && pNextData->bVisible && pNextData->eType == MENUITEM_SEPARATOR )
2159                 bVisible = sal_False;
2160 
2161             if( bVisible )
2162             {
2163                 for( n = nPos; n > 0; n-- )
2164                 {
2165                     pNextData = pItemList->GetDataFromPos( n-1 );
2166                     if( pNextData && pNextData->bVisible )
2167                     {
2168                         if( pNextData->eType != MENUITEM_SEPARATOR && ImplIsVisible(n-1) )
2169                             break;
2170                     }
2171                 }
2172                 if( n == 0 ) // no previous visible item
2173                     bVisible = sal_False;
2174             }
2175         }
2176     }
2177 
2178     // Fuer den Menubar nicht erlaubt, weil ich nicht mitbekomme
2179     // ob dadurch ein Eintrag verschwindet oder wieder da ist.
2180     if ( bVisible && !bIsMenuBar && ( nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES ) &&
2181         !( nMenuFlags & MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES ) )
2182     {
2183 		if( !pData ) // e.g. nPos == ITEMPOS_INVALID
2184 			bVisible = sal_False;
2185         else if ( pData->eType != MENUITEM_SEPARATOR ) // separators handled above
2186         {
2187             // bVisible = pData->bEnabled && ( !pData->pSubMenu || pData->pSubMenu->HasValidEntries( sal_True ) );
2188             bVisible = pData->bEnabled; // SubMenus nicht pruefen, weil sie ggf. erst im Activate() gefuellt werden.
2189         }
2190     }
2191 
2192     return bVisible;
2193 }
2194 
2195 sal_Bool Menu::IsItemVisible( sal_uInt16 nItemId ) const
2196 {
2197     return IsMenuVisible() && ImplIsVisible( GetItemPos( nItemId ) );
2198 }
2199 
2200 sal_Bool Menu::IsItemPosVisible( sal_uInt16 nItemPos ) const
2201 {
2202     return IsMenuVisible() && ImplIsVisible( nItemPos );
2203 }
2204 
2205 sal_Bool Menu::IsMenuVisible() const
2206 {
2207     return pWindow && pWindow->IsReallyVisible();
2208 }
2209 
2210 sal_Bool Menu::ImplIsSelectable( sal_uInt16 nPos ) const
2211 {
2212     sal_Bool bSelectable = sal_True;
2213 
2214     MenuItemData* pData = pItemList->GetDataFromPos( nPos );
2215     // check general visibility first
2216     if ( pData && ( pData->nBits & MIB_NOSELECT ) )
2217         bSelectable = sal_False;
2218 
2219     return bSelectable;
2220 }
2221 
2222 void Menu::SelectItem( sal_uInt16 nItemId )
2223 {
2224     if( bIsMenuBar )
2225         static_cast<MenuBar*>(this)->SelectEntry( nItemId );
2226     else
2227         static_cast<PopupMenu*>(this)->SelectEntry( nItemId );
2228 }
2229 
2230 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > Menu::GetAccessible()
2231 {
2232 	// Since PopupMenu are sometimes shared by different instances of MenuBar, the mxAccessible member gets
2233 	// overwritten and may contain a disposed object when the initial menubar gets set again. So use the
2234 	// mxAccessible member only for sub menus.
2235 	if ( pStartedFrom )
2236 	{
2237 		for ( sal_uInt16 i = 0, nCount = pStartedFrom->GetItemCount(); i < nCount; ++i )
2238 		{
2239 			sal_uInt16 nItemId = pStartedFrom->GetItemId( i );
2240 			if ( static_cast< Menu* >( pStartedFrom->GetPopupMenu( nItemId ) ) == this )
2241 			{
2242 				::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xParent = pStartedFrom->GetAccessible();
2243 				if ( xParent.is() )
2244 				{
2245 					::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
2246 					if ( xParentContext.is() )
2247 						return xParentContext->getAccessibleChild( i );
2248 				}
2249 			}
2250 		}
2251 	}
2252 	else if ( !mxAccessible.is() )
2253 	{
2254 		UnoWrapperBase* pWrapper = Application::GetUnoWrapper();
2255 		if ( pWrapper )
2256 			mxAccessible = pWrapper->CreateAccessible( this, bIsMenuBar );
2257 	}
2258 
2259 	return mxAccessible;
2260 }
2261 
2262 void Menu::SetAccessible( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible )
2263 {
2264 	mxAccessible = rxAccessible;
2265 }
2266 
2267 long Menu::ImplGetNativeCheckAndRadioSize( Window* pWin, long& rCheckHeight, long& rRadioHeight, long &rMaxWidth ) const
2268 {
2269     rMaxWidth = rCheckHeight = rRadioHeight = 0;
2270 
2271     if( ! bIsMenuBar )
2272     {
2273         ImplControlValue aVal;
2274         Rectangle aNativeBounds;
2275         Rectangle aNativeContent;
2276         Point tmp( 0, 0 );
2277         Rectangle aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) );
2278         if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_CHECK_MARK ) )
2279         {
2280             if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
2281                                               ControlPart(PART_MENU_ITEM_CHECK_MARK),
2282                                               aCtrlRegion,
2283                                               ControlState(CTRL_STATE_ENABLED),
2284                                               aVal,
2285                                               OUString(),
2286                                               aNativeBounds,
2287                                               aNativeContent )
2288             )
2289             {
2290                 rCheckHeight = aNativeBounds.GetHeight();
2291 				rMaxWidth = aNativeContent.GetWidth();
2292             }
2293         }
2294         if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_RADIO_MARK ) )
2295         {
2296             if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
2297                                               ControlPart(PART_MENU_ITEM_RADIO_MARK),
2298                                               aCtrlRegion,
2299                                               ControlState(CTRL_STATE_ENABLED),
2300                                               aVal,
2301                                               OUString(),
2302                                               aNativeBounds,
2303                                               aNativeContent )
2304             )
2305             {
2306                 rRadioHeight = aNativeBounds.GetHeight();
2307 				rMaxWidth = Max (rMaxWidth, aNativeContent.GetWidth());
2308             }
2309         }
2310     }
2311     return (rCheckHeight > rRadioHeight) ? rCheckHeight : rRadioHeight;
2312 }
2313 
2314 // -----------------------------------------------------------------------
2315 
2316 void Menu::ImplAddDel( ImplMenuDelData& rDel )
2317 {
2318     DBG_ASSERT( !rDel.mpMenu, "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !" );
2319     if( !rDel.mpMenu )
2320     {
2321         rDel.mpMenu = this;
2322         rDel.mpNext = mpFirstDel;
2323         mpFirstDel = &rDel;
2324     }
2325 }
2326 
2327 // -----------------------------------------------------------------------
2328 
2329 void Menu::ImplRemoveDel( ImplMenuDelData& rDel )
2330 {
2331     rDel.mpMenu = NULL;
2332     if ( mpFirstDel == &rDel )
2333 	{
2334         mpFirstDel = rDel.mpNext;
2335 	}
2336     else
2337     {
2338         ImplMenuDelData* pData = mpFirstDel;
2339         while ( pData && (pData->mpNext != &rDel) )
2340             pData = pData->mpNext;
2341 
2342 		DBG_ASSERT( pData, "Menu::ImplRemoveDel(): ImplMenuDelData not registered !" );
2343 		if( pData )
2344 			pData->mpNext = rDel.mpNext;
2345     }
2346 }
2347 
2348 // -----------------------------------------------------------------------
2349 
2350 Size Menu::ImplCalcSize( Window* pWin )
2351 {
2352     // | Checked| Image| Text| Accel/Popup|
2353 
2354     // Fuer Symbole: nFontHeight x nFontHeight
2355     long nFontHeight = pWin->GetTextHeight();
2356     long nExtra = nFontHeight/4;
2357 
2358 
2359     Size aSz;
2360     Size aMaxImgSz;
2361     long nMaxWidth = 0;
2362     long nMinMenuItemHeight = nFontHeight;
2363     long nCheckHeight = 0, nRadioHeight = 0;
2364 	long nCheckWidth = 0, nMaxCheckWidth = 0;
2365     long nMax = ImplGetNativeCheckAndRadioSize( pWin, nCheckHeight, nRadioHeight, nMaxCheckWidth );
2366     if( nMax > nMinMenuItemHeight )
2367         nMinMenuItemHeight = nMax;
2368 
2369 	const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
2370 	if ( rSettings.GetUseImagesInMenus() )
2371 	{
2372 		nMinMenuItemHeight = 16;
2373 		for ( sal_uInt16 i = (sal_uInt16)pItemList->Count(); i; )
2374 		{
2375 			MenuItemData* pData = pItemList->GetDataFromPos( --i );
2376 			if ( ImplIsVisible( i ) && (( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE )))
2377 			{
2378 				Size aImgSz = pData->aImage.GetSizePixel();
2379 				if ( aImgSz.Height() > aMaxImgSz.Height() )
2380 					aMaxImgSz.Height() = aImgSz.Height();
2381 				if ( aImgSz.Height() > nMinMenuItemHeight )
2382 					nMinMenuItemHeight = aImgSz.Height();
2383 				break;
2384 			}
2385 		}
2386 	}
2387 
2388     for ( sal_uInt16 n = (sal_uInt16)pItemList->Count(); n; )
2389     {
2390         MenuItemData* pData = pItemList->GetDataFromPos( --n );
2391 
2392         pData->aSz.Height() = 0;
2393         pData->aSz.Width() = 0;
2394 
2395         if ( ImplIsVisible( n ) )
2396         {
2397             long nWidth = 0;
2398 
2399             // Separator
2400             if ( !bIsMenuBar && ( pData->eType == MENUITEM_SEPARATOR ) )
2401             {
2402                 DBG_ASSERT( !bIsMenuBar, "Separator in MenuBar ?! " );
2403                 pData->aSz.Height() = 4;
2404             }
2405 
2406             // Image:
2407             if ( !bIsMenuBar && ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
2408             {
2409                 Size aImgSz = pData->aImage.GetSizePixel();
2410                 aImgSz.Height() += 4; // add a border for native marks
2411                 aImgSz.Width() += 4; // add a border for native marks
2412                 if ( aImgSz.Width() > aMaxImgSz.Width() )
2413                     aMaxImgSz.Width() = aImgSz.Width();
2414                 if ( aImgSz.Height() > aMaxImgSz.Height() )
2415                     aMaxImgSz.Height() = aImgSz.Height();
2416                 if ( aImgSz.Height() > pData->aSz.Height() )
2417                     pData->aSz.Height() = aImgSz.Height();
2418             }
2419 
2420 			// Check Buttons:
2421 			if ( !bIsMenuBar && pData->HasCheck() )
2422 			{
2423 				nCheckWidth = nMaxCheckWidth;
2424 				if (nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES)
2425                 {
2426                     // checks / images take the same place
2427                     if( ! ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
2428                         nWidth += nCheckWidth + nExtra * 2;
2429                 }
2430 			}
2431 
2432             // Text:
2433             if ( (pData->eType == MENUITEM_STRING) || (pData->eType == MENUITEM_STRINGIMAGE) )
2434             {
2435                 long nTextWidth = pWin->GetCtrlTextWidth( pData->aText );
2436                 long nTextHeight = pWin->GetTextHeight();
2437 
2438 //                if ( nTextHeight > pData->aSz.Height() )
2439 //                    pData->aSz.Height() = nTextHeight;
2440 
2441                 if ( bIsMenuBar )
2442                 {
2443 					if ( nTextHeight > pData->aSz.Height() )
2444 						pData->aSz.Height() = nTextHeight;
2445 
2446                     pData->aSz.Width() = nTextWidth + 4*nExtra;
2447                     aSz.Width() += pData->aSz.Width();
2448                 }
2449 				else
2450 					pData->aSz.Height() = Max( Max( nTextHeight, pData->aSz.Height() ), nMinMenuItemHeight );
2451 
2452                 nWidth += nTextWidth;
2453             }
2454 
2455             // Accel
2456             if ( !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
2457             {
2458                 String aName = pData->aAccelKey.GetName();
2459                 long nAccWidth = pWin->GetTextWidth( aName );
2460                 nAccWidth += nExtra;
2461                 nWidth += nAccWidth;
2462             }
2463 
2464             // SubMenu?
2465             if ( !bIsMenuBar && pData->pSubMenu )
2466             {
2467                     if ( nFontHeight > nWidth )
2468                         nWidth += nFontHeight;
2469 
2470 				pData->aSz.Height() = Max( Max( nFontHeight, pData->aSz.Height() ), nMinMenuItemHeight );
2471             }
2472 
2473             pData->aSz.Height() += EXTRAITEMHEIGHT; // Etwas mehr Abstand:
2474 
2475             if ( !bIsMenuBar )
2476                 aSz.Height() += (long)pData->aSz.Height();
2477 
2478             if ( nWidth > nMaxWidth )
2479                 nMaxWidth = nWidth;
2480 
2481         }
2482     }
2483 
2484     if ( !bIsMenuBar )
2485     {
2486         // popup menus should not be wider than half the screen
2487         // except on rather small screens
2488         // TODO: move GetScreenNumber from SystemWindow to Window ?
2489         // currently we rely on internal privileges
2490         unsigned int nScreenNumber = pWin->ImplGetWindowImpl()->mpFrame->maGeometry.nScreenNumber;
2491         Rectangle aDispRect( Application::GetScreenPosSizePixel( nScreenNumber ) );
2492         long nScreenWidth = aDispRect.GetWidth() >= 800 ? aDispRect.GetWidth() : 800;
2493         if( nMaxWidth > nScreenWidth/2 )
2494             nMaxWidth = nScreenWidth/2;
2495 
2496         sal_uInt16 gfxExtra = (sal_uInt16) Max( nExtra, 7L ); // #107710# increase space between checkmarks/images/text
2497         nCheckPos = (sal_uInt16)nExtra;
2498 		if (nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES)
2499 		{
2500             long nImgOrChkWidth = 0;
2501             nImagePos = nCheckPos;
2502             if( nMax > 0 ) // NWF case
2503                 nImgOrChkWidth = nMax + nExtra;
2504             else // non NWF case
2505                 nImgOrChkWidth = nFontHeight/2 + gfxExtra;
2506             nImgOrChkWidth = Max( nImgOrChkWidth, aMaxImgSz.Width() + gfxExtra );
2507             nTextPos = (sal_uInt16)(nImagePos + nImgOrChkWidth);
2508 		}
2509 		else
2510 		{
2511 			nImagePos = nCheckPos;
2512 			nTextPos = (sal_uInt16)(nImagePos + Max( aMaxImgSz.Width(), nCheckWidth ));
2513 		}
2514 		nTextPos = nTextPos + gfxExtra;
2515 
2516         aSz.Width() = nTextPos + nMaxWidth + nExtra;
2517         aSz.Width() += 4*nExtra;   // a _little_ more ...
2518 
2519         int nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
2520         aSz.Width() += 2*nOuterSpace;
2521         aSz.Height() += 2*nOuterSpace;
2522     }
2523     else
2524     {
2525         nTextPos = (sal_uInt16)(2*nExtra);
2526         aSz.Height() = nFontHeight+6;
2527 
2528         // get menubar height from native methods if supported
2529         if( pWindow->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
2530         {
2531             ImplControlValue aVal;
2532             Rectangle aNativeBounds;
2533             Rectangle aNativeContent;
2534             Point tmp( 0, 0 );
2535             Rectangle aCtrlRegion( tmp, Size( 100, 15 ) );
2536             if( pWindow->GetNativeControlRegion( ControlType(CTRL_MENUBAR),
2537                                                  ControlPart(PART_ENTIRE_CONTROL),
2538                                                  aCtrlRegion,
2539                                                  ControlState(CTRL_STATE_ENABLED),
2540                                                  aVal,
2541                                                  OUString(),
2542                                                  aNativeBounds,
2543                                                  aNativeContent )
2544             )
2545             {
2546                 int nNativeHeight = aNativeBounds.GetHeight();
2547                 if( nNativeHeight > aSz.Height() )
2548                     aSz.Height() = nNativeHeight;
2549             }
2550         }
2551 
2552         // account for the size of the close button, which actually is a toolbox
2553         // due to NWF this is variable
2554         long nCloserHeight = ((MenuBarWindow*) pWindow)->MinCloseButtonSize().Height();
2555         if( aSz.Height() < nCloserHeight )
2556             aSz.Height() = nCloserHeight;
2557     }
2558 
2559     if ( pLogo )
2560         aSz.Width() += pLogo->aBitmap.GetSizePixel().Width();
2561 
2562     return aSz;
2563 }
2564 
2565 static void ImplPaintCheckBackground( Window* i_pWindow, const Rectangle& i_rRect, bool i_bHighlight )
2566 {
2567     sal_Bool bNativeOk = sal_False;
2568     if( i_pWindow->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) )
2569     {
2570         ImplControlValue    aControlValue;
2571         Rectangle           aCtrlRegion( i_rRect );
2572         ControlState        nState = CTRL_STATE_PRESSED | CTRL_STATE_ENABLED;
2573 
2574         aControlValue.setTristateVal( BUTTONVALUE_ON );
2575 
2576         bNativeOk = i_pWindow->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON,
2577                                                   aCtrlRegion, nState, aControlValue,
2578                                                   rtl::OUString() );
2579     }
2580 
2581     if( ! bNativeOk )
2582     {
2583         const StyleSettings& rSettings = i_pWindow->GetSettings().GetStyleSettings();
2584         Color aColor( i_bHighlight ? rSettings.GetMenuHighlightTextColor() : rSettings.GetHighlightColor() );
2585         i_pWindow->DrawSelectionBackground( i_rRect, 0, i_bHighlight, sal_True, sal_False, 2, NULL, &aColor );
2586     }
2587 }
2588 
2589 static String getShortenedString( const String& i_rLong, Window* i_pWin, long i_nMaxWidth )
2590 {
2591     xub_StrLen nPos = STRING_NOTFOUND;
2592     String aNonMnem( OutputDevice::GetNonMnemonicString( i_rLong, nPos ) );
2593     aNonMnem = i_pWin->GetEllipsisString( aNonMnem, i_nMaxWidth, TEXT_DRAW_CENTERELLIPSIS );
2594     // re-insert mnemonic
2595     if( nPos != STRING_NOTFOUND )
2596     {
2597         if( nPos < aNonMnem.Len() && i_rLong.GetChar(nPos+1) == aNonMnem.GetChar(nPos) )
2598         {
2599             rtl::OUStringBuffer aBuf( i_rLong.Len() );
2600             aBuf.append( aNonMnem.GetBuffer(), nPos );
2601             aBuf.append( sal_Unicode('~') );
2602             aBuf.append( aNonMnem.GetBuffer()+nPos );
2603             aNonMnem = aBuf.makeStringAndClear();
2604         }
2605     }
2606     return aNonMnem;
2607 }
2608 
2609 void Menu::ImplPaint( Window* pWin, sal_uInt16 nBorder, long nStartY, MenuItemData* pThisItemOnly, sal_Bool bHighlighted, bool bLayout ) const
2610 {
2611     // Fuer Symbole: nFontHeight x nFontHeight
2612     long nFontHeight = pWin->GetTextHeight();
2613     long nExtra = nFontHeight/4;
2614 
2615     long nCheckHeight = 0, nRadioHeight = 0, nMaxCheckWidth = 0;
2616     ImplGetNativeCheckAndRadioSize( pWin, nCheckHeight, nRadioHeight, nMaxCheckWidth );
2617 
2618     DecorationView aDecoView( pWin );
2619     const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
2620 
2621     Point aTopLeft, aTmpPos;
2622 
2623     if ( pLogo )
2624         aTopLeft.X() = pLogo->aBitmap.GetSizePixel().Width();
2625 
2626     int nOuterSpace = 0;
2627     if( !bIsMenuBar )
2628     {
2629         nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
2630         aTopLeft.X() += nOuterSpace;
2631         aTopLeft.Y() += nOuterSpace;
2632     }
2633 
2634     Size aOutSz = pWin->GetOutputSizePixel();
2635     sal_uInt16 nCount = (sal_uInt16)pItemList->Count();
2636     if( bLayout )
2637         mpLayoutData->m_aVisibleItemBoundRects.clear();
2638     for ( sal_uInt16 n = 0; n < nCount; n++ )
2639     {
2640         MenuItemData* pData = pItemList->GetDataFromPos( n );
2641         if ( ImplIsVisible( n ) && ( !pThisItemOnly || ( pData == pThisItemOnly ) ) )
2642         {
2643             if ( pThisItemOnly && bHighlighted )
2644                 pWin->SetTextColor( rSettings.GetMenuHighlightTextColor() );
2645 
2646             Point aPos( aTopLeft );
2647             aPos.Y() += nBorder;
2648             aPos.Y() += nStartY;
2649 
2650             if ( aPos.Y() >= 0 )
2651             {
2652                 long    nTextOffsetY = ((pData->aSz.Height()-nFontHeight)/2);
2653                 if( bIsMenuBar )
2654                     nTextOffsetY += (aOutSz.Height()-pData->aSz.Height()) / 2;
2655                 sal_uInt16  nTextStyle   = 0;
2656                 sal_uInt16  nSymbolStyle = 0;
2657                 sal_uInt16  nImageStyle  = 0;
2658                 // SubMenus ohne Items werden nicht mehr disablte dargestellt,
2659                 // wenn keine Items enthalten sind, da die Anwendung selber
2660                 // darauf achten muss. Ansonsten gibt es Faelle, wo beim
2661                 // asyncronen laden die Eintraege disablte dargestellt werden.
2662                 if ( !pData->bEnabled )
2663                 {
2664                     nTextStyle   |= TEXT_DRAW_DISABLE;
2665                     nSymbolStyle |= SYMBOL_DRAW_DISABLE;
2666                     nImageStyle  |= IMAGE_DRAW_DISABLE;
2667                 }
2668 
2669                 // Separator
2670                 if ( !bLayout && !bIsMenuBar && ( pData->eType == MENUITEM_SEPARATOR ) )
2671                 {
2672                     bool bNativeOk = false;
2673                     if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
2674                                                         PART_MENU_SEPARATOR ) )
2675                     {
2676                         ControlState nState = 0;
2677                         if ( pData->bEnabled )
2678                             nState |= CTRL_STATE_ENABLED;
2679                         if ( bHighlighted )
2680                             nState |= CTRL_STATE_SELECTED;
2681 						Size aSz( pData->aSz );
2682 						aSz.Width() = aOutSz.Width() - 2*nOuterSpace;
2683                         Rectangle aItemRect( aPos, aSz );
2684                         MenupopupValue aVal( nTextPos-GUTTERBORDER, aItemRect );
2685                         bNativeOk = pWin->DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_SEPARATOR,
2686                                                              aItemRect,
2687                                                              nState,
2688                                                              aVal,
2689                                                              OUString() );
2690                     }
2691                     if( ! bNativeOk )
2692                     {
2693                         aTmpPos.Y() = aPos.Y() + ((pData->aSz.Height()-2)/2);
2694                         aTmpPos.X() = aPos.X() + 2 + nOuterSpace;
2695                         pWin->SetLineColor( rSettings.GetShadowColor() );
2696                         pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) );
2697                         aTmpPos.Y()++;
2698                         pWin->SetLineColor( rSettings.GetLightColor() );
2699                         pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) );
2700                         pWin->SetLineColor();
2701                     }
2702                 }
2703 
2704                 Rectangle aOuterCheckRect( Point( aPos.X()+nCheckPos, aPos.Y() ), Size( pData->aSz.Height(), pData->aSz.Height() ) );
2705                 aOuterCheckRect.Left()      += 1;
2706                 aOuterCheckRect.Right()     -= 1;
2707                 aOuterCheckRect.Top()       += 1;
2708                 aOuterCheckRect.Bottom()    -= 1;
2709 
2710                 // CheckMark
2711                 if ( !bLayout && !bIsMenuBar && pData->HasCheck() )
2712                 {
2713                     // draw selection transparent marker if checked
2714                     // onto that either a checkmark or the item image
2715                     // will be painted
2716                     // however do not do this if native checks will be painted since
2717                     // the selection color too often does not fit the theme's check and/or radio
2718 
2719                     if( ! ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
2720                     {
2721                         if ( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
2722                                                              (pData->nBits & MIB_RADIOCHECK)
2723                                                              ? PART_MENU_ITEM_CHECK_MARK
2724                                                              : PART_MENU_ITEM_RADIO_MARK ) )
2725                         {
2726                             ControlPart nPart = ((pData->nBits & MIB_RADIOCHECK)
2727                                                  ? PART_MENU_ITEM_RADIO_MARK
2728                                                  : PART_MENU_ITEM_CHECK_MARK);
2729 
2730                             ControlState nState = 0;
2731 
2732                             if ( pData->bChecked )
2733                                 nState |= CTRL_STATE_PRESSED;
2734 
2735                             if ( pData->bEnabled )
2736                                 nState |= CTRL_STATE_ENABLED;
2737 
2738                             if ( bHighlighted )
2739                                 nState |= CTRL_STATE_SELECTED;
2740 
2741                             long nCtrlHeight = (pData->nBits & MIB_RADIOCHECK) ? nCheckHeight : nRadioHeight;
2742                             aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - nCtrlHeight)/2;
2743                             aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - nCtrlHeight)/2;
2744 
2745                             Rectangle aCheckRect( aTmpPos, Size( nCtrlHeight, nCtrlHeight ) );
2746                             MenupopupValue aVal( nTextPos-GUTTERBORDER, Rectangle( aPos, pData->aSz ) );
2747                             pWin->DrawNativeControl( CTRL_MENU_POPUP, nPart,
2748                                                      aCheckRect,
2749                                                      nState,
2750                                                      aVal,
2751                                                      OUString() );
2752                         }
2753                         else if ( pData->bChecked ) // by default do nothing for unchecked items
2754                         {
2755                             ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted );
2756 
2757                             SymbolType eSymbol;
2758                             Size aSymbolSize;
2759                             if ( pData->nBits & MIB_RADIOCHECK )
2760                             {
2761                                 eSymbol = SYMBOL_RADIOCHECKMARK;
2762                                 aSymbolSize = Size( nFontHeight/2, nFontHeight/2 );
2763                             }
2764                             else
2765                             {
2766                                 eSymbol = SYMBOL_CHECKMARK;
2767                                 aSymbolSize = Size( (nFontHeight*25)/40, nFontHeight/2 );
2768                             }
2769                             aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - aSymbolSize.Width())/2;
2770                             aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - aSymbolSize.Height())/2;
2771                             Rectangle aRect( aTmpPos, aSymbolSize );
2772                             aDecoView.DrawSymbol( aRect, eSymbol, pWin->GetTextColor(), nSymbolStyle );
2773                         }
2774                     }
2775                 }
2776 
2777                 // Image:
2778                 if ( !bLayout && !bIsMenuBar && ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
2779                 {
2780 					// Don't render an image for a check thing
2781 					if ((nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES) || !pData->HasCheck() )
2782 					{
2783                         if( pData->bChecked )
2784                             ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted );
2785                         aTmpPos = aOuterCheckRect.TopLeft();
2786 	                    aTmpPos.X() += (aOuterCheckRect.GetWidth()-pData->aImage.GetSizePixel().Width())/2;
2787 	                    aTmpPos.Y() += (aOuterCheckRect.GetHeight()-pData->aImage.GetSizePixel().Height())/2;
2788 	                    pWin->DrawImage( aTmpPos, pData->aImage, nImageStyle );
2789 					}
2790                 }
2791 
2792                 // Text:
2793                 if ( ( pData->eType == MENUITEM_STRING ) || ( pData->eType == MENUITEM_STRINGIMAGE ) )
2794                 {
2795                     aTmpPos.X() = aPos.X() + nTextPos;
2796                     aTmpPos.Y() = aPos.Y();
2797                     aTmpPos.Y() += nTextOffsetY;
2798                     sal_uInt16 nStyle = nTextStyle|TEXT_DRAW_MNEMONIC;
2799                     if ( pData->bIsTemporary )
2800                         nStyle |= TEXT_DRAW_DISABLE;
2801                     MetricVector* pVector = bLayout ? &mpLayoutData->m_aUnicodeBoundRects : NULL;
2802                     String* pDisplayText = bLayout ? &mpLayoutData->m_aDisplayText : NULL;
2803                     if( bLayout )
2804                     {
2805                         mpLayoutData->m_aLineIndices.push_back( mpLayoutData->m_aDisplayText.Len() );
2806                         mpLayoutData->m_aLineItemIds.push_back( pData->nId );
2807                         mpLayoutData->m_aLineItemPositions.push_back( n );
2808                     }
2809                     // #i47946# with NWF painted menus the background is transparent
2810                     // since DrawCtrlText can depend on the background (e.g. for
2811                     // TEXT_DRAW_DISABLE), temporarily set a background which
2812                     // hopefully matches the NWF background since it is read
2813                     // from the system style settings
2814                     bool bSetTmpBackground = !pWin->IsBackground() && pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL );
2815                     if( bSetTmpBackground )
2816                     {
2817                         Color aBg = bIsMenuBar ?
2818                             pWin->GetSettings().GetStyleSettings().GetMenuBarColor() :
2819                             pWin->GetSettings().GetStyleSettings().GetMenuColor();
2820                         pWin->SetBackground( Wallpaper( aBg ) );
2821                     }
2822                     // how much space is there for the text ?
2823                     long nMaxItemTextWidth = aOutSz.Width() - aTmpPos.X() - nExtra - nOuterSpace;
2824                     if( !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
2825                     {
2826                         XubString aAccText = pData->aAccelKey.GetName();
2827                         nMaxItemTextWidth -= pWin->GetTextWidth( aAccText ) + 3*nExtra;
2828                     }
2829                     if( !bIsMenuBar && pData->pSubMenu )
2830                     {
2831                         nMaxItemTextWidth -= nFontHeight - nExtra;
2832                     }
2833                     String aItemText( getShortenedString( pData->aText, pWin, nMaxItemTextWidth ) );
2834                     pWin->DrawCtrlText( aTmpPos, aItemText, 0, aItemText.Len(), nStyle, pVector, pDisplayText );
2835                     if( bSetTmpBackground )
2836                         pWin->SetBackground();
2837                 }
2838 
2839                 // Accel
2840                 if ( !bLayout && !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
2841                 {
2842                     XubString aAccText = pData->aAccelKey.GetName();
2843                     aTmpPos.X() = aOutSz.Width() - pWin->GetTextWidth( aAccText );
2844                     aTmpPos.X() -= 4*nExtra;
2845 
2846                     aTmpPos.X() -= nOuterSpace;
2847                     aTmpPos.Y() = aPos.Y();
2848                     aTmpPos.Y() += nTextOffsetY;
2849                     pWin->DrawCtrlText( aTmpPos, aAccText, 0, aAccText.Len(), nTextStyle );
2850                 }
2851 
2852                 // SubMenu?
2853                 if ( !bLayout && !bIsMenuBar && pData->pSubMenu )
2854                 {
2855                     aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpace;
2856                     aTmpPos.Y() = aPos.Y();
2857                     aTmpPos.Y() += nExtra/2;
2858                     aTmpPos.Y() += ( pData->aSz.Height() / 2 ) - ( nFontHeight/4 );
2859                     if ( pData->nBits & MIB_POPUPSELECT )
2860                     {
2861                         pWin->SetTextColor( rSettings.GetMenuTextColor() );
2862                         Point aTmpPos2( aPos );
2863                         aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4;
2864                         aDecoView.DrawFrame(
2865                             Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pData->aSz.Height() ) ), FRAME_DRAW_GROUP );
2866                     }
2867                     aDecoView.DrawSymbol(
2868                         Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ),
2869                         SYMBOL_SPIN_RIGHT, pWin->GetTextColor(), nSymbolStyle );
2870                 }
2871 
2872                 if ( pThisItemOnly && bHighlighted )
2873                 {
2874                     // This restores the normal menu or menu bar text
2875                     // color for when it is no longer highlighted.
2876 		    if ( bIsMenuBar )
2877 		        pWin->SetTextColor( rSettings.GetMenuBarTextColor() );
2878 		    else
2879 		        pWin->SetTextColor( rSettings.GetMenuTextColor() );
2880 		 }
2881             }
2882             if( bLayout )
2883             {
2884                 if ( !bIsMenuBar )
2885                     mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, Size( aOutSz.Width(), pData->aSz.Height() ) );
2886                 else
2887                     mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, pData->aSz );
2888             }
2889         }
2890 
2891         if ( !bIsMenuBar )
2892         {
2893             aTopLeft.Y() += pData->aSz.Height();
2894         }
2895         else
2896         {
2897             aTopLeft.X() += pData->aSz.Width();
2898         }
2899     }
2900 
2901     if ( !bLayout && !pThisItemOnly && pLogo )
2902     {
2903         Size aLogoSz = pLogo->aBitmap.GetSizePixel();
2904 
2905         Rectangle aRect( Point( 0, 0 ), Point( aLogoSz.Width()-1, aOutSz.Height() ) );
2906         if ( pWin->GetColorCount() >= 256 )
2907         {
2908             Gradient aGrad( GRADIENT_LINEAR, pLogo->aStartColor, pLogo->aEndColor );
2909             aGrad.SetAngle( 1800 );
2910             aGrad.SetBorder( 15 );
2911             pWin->DrawGradient( aRect, aGrad );
2912         }
2913         else
2914         {
2915             pWin->SetFillColor( pLogo->aStartColor );
2916             pWin->DrawRect( aRect );
2917         }
2918 
2919         Point aLogoPos( 0, aOutSz.Height() - aLogoSz.Height() );
2920         pLogo->aBitmap.Draw( pWin, aLogoPos );
2921     }
2922 }
2923 
2924 Menu* Menu::ImplGetStartMenu()
2925 {
2926     Menu* pStart = this;
2927     while ( pStart && pStart->pStartedFrom && ( pStart->pStartedFrom != pStart ) )
2928         pStart = pStart->pStartedFrom;
2929     return pStart;
2930 }
2931 
2932 void Menu::ImplCallHighlight( sal_uInt16 nHighlightedItem )
2933 {
2934 	ImplMenuDelData aDelData( this );
2935 
2936     nSelectedId = 0;
2937     MenuItemData* pData = pItemList->GetDataFromPos( nHighlightedItem );
2938     if ( pData )
2939         nSelectedId = pData->nId;
2940     ImplCallEventListeners( VCLEVENT_MENU_HIGHLIGHT, GetItemPos( GetCurItemId() ) );
2941 
2942 	if( !aDelData.isDeleted() )
2943 	{
2944 	    Highlight();
2945 		nSelectedId = 0;
2946 	}
2947 }
2948 
2949 IMPL_LINK( Menu, ImplCallSelect, Menu*, EMPTYARG )
2950 {
2951     nEventId = 0;
2952     Select();
2953     return 0;
2954 }
2955 
2956 Menu* Menu::ImplFindSelectMenu()
2957 {
2958     Menu* pSelMenu = nEventId ? this : NULL;
2959 
2960     for ( sal_uLong n = GetItemList()->Count(); n && !pSelMenu; )
2961     {
2962         MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
2963 
2964         if ( pData->pSubMenu )
2965             pSelMenu = pData->pSubMenu->ImplFindSelectMenu();
2966     }
2967 
2968     return pSelMenu;
2969 }
2970 
2971 Menu* Menu::ImplFindMenu( sal_uInt16 nItemId )
2972 {
2973     Menu* pSelMenu = NULL;
2974 
2975     for ( sal_uLong n = GetItemList()->Count(); n && !pSelMenu; )
2976     {
2977         MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
2978 
2979         if( pData->nId == nItemId )
2980             pSelMenu = this;
2981         else if ( pData->pSubMenu )
2982             pSelMenu = pData->pSubMenu->ImplFindMenu( nItemId );
2983     }
2984 
2985     return pSelMenu;
2986 }
2987 
2988 void Menu::RemoveDisabledEntries( sal_Bool bCheckPopups, sal_Bool bRemoveEmptyPopups )
2989 {
2990     for ( sal_uInt16 n = 0; n < GetItemCount(); n++ )
2991     {
2992         sal_Bool bRemove = sal_False;
2993         MenuItemData* pItem = pItemList->GetDataFromPos( n );
2994         if ( pItem->eType == MENUITEM_SEPARATOR )
2995         {
2996             if ( !n || ( GetItemType( n-1 ) == MENUITEM_SEPARATOR ) )
2997                 bRemove = sal_True;
2998         }
2999         else
3000             bRemove = !pItem->bEnabled;
3001 
3002         if ( bCheckPopups && pItem->pSubMenu )
3003         {
3004             pItem->pSubMenu->RemoveDisabledEntries( sal_True );
3005             if ( bRemoveEmptyPopups && !pItem->pSubMenu->GetItemCount() )
3006                 bRemove = sal_True;
3007         }
3008 
3009         if ( bRemove )
3010             RemoveItem( n-- );
3011     }
3012 
3013     if ( GetItemCount() )
3014     {
3015         sal_uInt16 nLast = GetItemCount() - 1;
3016         MenuItemData* pItem = pItemList->GetDataFromPos( nLast );
3017         if ( pItem->eType == MENUITEM_SEPARATOR )
3018             RemoveItem( nLast );
3019     }
3020     delete mpLayoutData, mpLayoutData = NULL;
3021 }
3022 
3023 sal_Bool Menu::HasValidEntries( sal_Bool bCheckPopups )
3024 {
3025     sal_Bool bValidEntries = sal_False;
3026     sal_uInt16 nCount = GetItemCount();
3027     for ( sal_uInt16 n = 0; !bValidEntries && ( n < nCount ); n++ )
3028     {
3029         MenuItemData* pItem = pItemList->GetDataFromPos( n );
3030         if ( pItem->bEnabled && ( pItem->eType != MENUITEM_SEPARATOR ) )
3031         {
3032             if ( bCheckPopups && pItem->pSubMenu )
3033                 bValidEntries = pItem->pSubMenu->HasValidEntries( sal_True );
3034             else
3035                 bValidEntries = sal_True;
3036         }
3037     }
3038     return bValidEntries;
3039 }
3040 
3041 void Menu::SetLogo( const MenuLogo& rLogo )
3042 {
3043     delete pLogo;
3044     pLogo = new MenuLogo( rLogo );
3045 }
3046 
3047 void Menu::SetLogo()
3048 {
3049     delete pLogo;
3050     pLogo = NULL;
3051 }
3052 
3053 MenuLogo Menu::GetLogo() const
3054 {
3055     MenuLogo aLogo;
3056     if ( pLogo )
3057         aLogo = *pLogo;
3058     return aLogo;
3059 }
3060 
3061 void Menu::ImplKillLayoutData() const
3062 {
3063     delete mpLayoutData, mpLayoutData = NULL;
3064 }
3065 
3066 void Menu::ImplFillLayoutData() const
3067 {
3068     if( pWindow && pWindow->IsReallyVisible() )
3069     {
3070         mpLayoutData = new MenuLayoutData();
3071         if( bIsMenuBar )
3072         {
3073             ImplPaint( pWindow, 0, 0, 0, sal_False, true );
3074         }
3075         else
3076         {
3077             MenuFloatingWindow* pFloat = (MenuFloatingWindow*)pWindow;
3078             ImplPaint( pWindow, pFloat->nScrollerHeight, pFloat->ImplGetStartY(), 0, sal_False, true );
3079         }
3080     }
3081 }
3082 
3083 String Menu::GetDisplayText() const
3084 {
3085     if( ! mpLayoutData )
3086         ImplFillLayoutData();
3087     return mpLayoutData ? mpLayoutData->m_aDisplayText : String();
3088 }
3089 
3090 Rectangle Menu::GetCharacterBounds( sal_uInt16 nItemID, long nIndex ) const
3091 {
3092     long nItemIndex = -1;
3093     if( ! mpLayoutData )
3094         ImplFillLayoutData();
3095     if( mpLayoutData )
3096     {
3097         for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ )
3098         {
3099             if( mpLayoutData->m_aLineItemIds[i] == nItemID )
3100             {
3101                 nItemIndex = mpLayoutData->m_aLineIndices[i];
3102                 break;
3103             }
3104         }
3105     }
3106     return (mpLayoutData && nItemIndex != -1) ? mpLayoutData->GetCharacterBounds( nItemIndex+nIndex ) : Rectangle();
3107 }
3108 
3109 
3110 long Menu::GetIndexForPoint( const Point& rPoint, sal_uInt16& rItemID ) const
3111 {
3112     long nIndex = -1;
3113     rItemID = 0;
3114     if( ! mpLayoutData )
3115         ImplFillLayoutData();
3116     if( mpLayoutData )
3117     {
3118         nIndex = mpLayoutData->GetIndexForPoint( rPoint );
3119         for( size_t i = 0; i < mpLayoutData->m_aLineIndices.size(); i++ )
3120         {
3121             if( mpLayoutData->m_aLineIndices[i] <= nIndex &&
3122                 (i == mpLayoutData->m_aLineIndices.size()-1 || mpLayoutData->m_aLineIndices[i+1] > nIndex) )
3123             {
3124                 // make index relative to item
3125                 nIndex -= mpLayoutData->m_aLineIndices[i];
3126                 rItemID = mpLayoutData->m_aLineItemIds[i];
3127                 break;
3128             }
3129         }
3130     }
3131     return nIndex;
3132 }
3133 
3134 long Menu::GetLineCount() const
3135 {
3136     if( ! mpLayoutData )
3137         ImplFillLayoutData();
3138     return mpLayoutData ? mpLayoutData->GetLineCount() : 0;
3139 }
3140 
3141 Pair Menu::GetLineStartEnd( long nLine ) const
3142 {
3143     if( ! mpLayoutData )
3144         ImplFillLayoutData();
3145     return mpLayoutData ? mpLayoutData->GetLineStartEnd( nLine ) : Pair( -1, -1 );
3146 }
3147 
3148 Pair Menu::GetItemStartEnd( sal_uInt16 nItem ) const
3149 {
3150     if( ! mpLayoutData )
3151         ImplFillLayoutData();
3152 
3153     for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ )
3154         if( mpLayoutData->m_aLineItemIds[i] == nItem )
3155             return GetLineStartEnd( i );
3156 
3157     return Pair( -1, -1 );
3158 }
3159 
3160 sal_uInt16 Menu::GetDisplayItemId( long nLine ) const
3161 {
3162     sal_uInt16 nItemId = 0;
3163     if( ! mpLayoutData )
3164         ImplFillLayoutData();
3165     if( mpLayoutData && ( nLine >= 0 ) && ( nLine < (long)mpLayoutData->m_aLineItemIds.size() ) )
3166         nItemId = mpLayoutData->m_aLineItemIds[nLine];
3167     return nItemId;
3168 }
3169 
3170 sal_Bool Menu::ConvertPoint( Point& rPoint, Window* pReferenceWindow ) const
3171 {
3172     sal_Bool bRet = sal_False;
3173     if( pWindow && pReferenceWindow )
3174     {
3175         rPoint = pReferenceWindow->OutputToAbsoluteScreenPixel( rPoint );
3176         rPoint = pWindow->AbsoluteScreenToOutputPixel( rPoint );
3177         bRet = sal_True;
3178     }
3179     return bRet;
3180 }
3181 
3182 Rectangle Menu::GetBoundingRectangle( sal_uInt16 nPos ) const
3183 {
3184     Rectangle aRet;
3185 
3186     if( ! mpLayoutData )
3187         ImplFillLayoutData();
3188     if( mpLayoutData )
3189     {
3190         std::map< sal_uInt16, Rectangle >::const_iterator it = mpLayoutData->m_aVisibleItemBoundRects.find( nPos );
3191         if( it != mpLayoutData->m_aVisibleItemBoundRects.end() )
3192             aRet = it->second;
3193     }
3194     return aRet;
3195 }
3196 
3197 void Menu::SetAccessibleName( sal_uInt16 nItemId, const XubString& rStr )
3198 {
3199     sal_uInt16        nPos;
3200     MenuItemData* pData = pItemList->GetData( nItemId, nPos );
3201 
3202 	if ( pData && !rStr.Equals( pData->aAccessibleName ) )
3203 	{
3204 		pData->aAccessibleName = rStr;
3205 		ImplCallEventListeners( VCLEVENT_MENU_ACCESSIBLENAMECHANGED, nPos );
3206 	}
3207 }
3208 
3209 XubString Menu::GetAccessibleName( sal_uInt16 nItemId ) const
3210 {
3211     MenuItemData* pData = pItemList->GetData( nItemId );
3212 
3213     if ( pData )
3214         return pData->aAccessibleName;
3215     else
3216         return ImplGetSVEmptyStr();
3217 }
3218 
3219 void Menu::SetAccessibleDescription( sal_uInt16 nItemId, const XubString& rStr )
3220 {
3221     MenuItemData* pData = pItemList->GetData( nItemId );
3222 
3223 	if ( pData )
3224 		pData->aAccessibleDescription = rStr;
3225 }
3226 
3227 XubString Menu::GetAccessibleDescription( sal_uInt16 nItemId ) const
3228 {
3229     MenuItemData* pData = pItemList->GetData( nItemId );
3230 
3231     if ( pData )
3232         return pData->aAccessibleDescription;
3233     else
3234         return ImplGetSVEmptyStr();
3235 }
3236 
3237 void Menu::ImplSetSalMenu( SalMenu *pSalMenu )
3238 {
3239     if( mpSalMenu )
3240         ImplGetSVData()->mpDefInst->DestroyMenu( mpSalMenu );
3241     mpSalMenu = pSalMenu;
3242 }
3243 
3244 sal_Bool Menu::GetSystemMenuData( SystemMenuData* pData ) const
3245 {
3246     Menu* pMenu = (Menu*)this;
3247     if( pData && pMenu->ImplGetSalMenu() )
3248     {
3249         pMenu->ImplGetSalMenu()->GetSystemMenuData( pData );
3250         return sal_True;
3251     }
3252     else
3253         return sal_False;
3254 }
3255 
3256 bool Menu::IsHighlighted( sal_uInt16 nItemPos ) const
3257 {
3258     bool bRet = false;
3259 
3260     if( pWindow )
3261     {
3262         if( bIsMenuBar )
3263             bRet = ( nItemPos == static_cast< MenuBarWindow * > (pWindow)->GetHighlightedItem() );
3264         else
3265             bRet = ( nItemPos == static_cast< MenuFloatingWindow * > (pWindow)->GetHighlightedItem() );
3266     }
3267 
3268     return bRet;
3269 }
3270 
3271 void Menu::HighlightItem( sal_uInt16 nItemPos )
3272 {
3273     if ( pWindow )
3274     {
3275         if ( bIsMenuBar )
3276         {
3277             MenuBarWindow* pMenuWin = static_cast< MenuBarWindow* >( pWindow );
3278             pMenuWin->SetAutoPopup( sal_False );
3279             pMenuWin->ChangeHighlightItem( nItemPos, sal_False );
3280         }
3281         else
3282         {
3283             static_cast< MenuFloatingWindow* >( pWindow )->ChangeHighlightItem( nItemPos, sal_False );
3284         }
3285     }
3286 }
3287 
3288 // -----------
3289 // - MenuBar -
3290 // -----------
3291 
3292 MenuBar::MenuBar() : Menu( sal_True )
3293 {
3294     mbDisplayable       = sal_True;
3295     mbCloserVisible     = sal_False;
3296     mbFloatBtnVisible   = sal_False;
3297     mbHideBtnVisible    = sal_False;
3298 }
3299 
3300 MenuBar::MenuBar( const MenuBar& rMenu ) : Menu( sal_True )
3301 {
3302     mbDisplayable       = sal_True;
3303     mbCloserVisible     = sal_False;
3304     mbFloatBtnVisible   = sal_False;
3305     mbHideBtnVisible    = sal_False;
3306     *this               = rMenu;
3307     bIsMenuBar          = sal_True;
3308 }
3309 
3310 MenuBar::MenuBar( const ResId& rResId ) : Menu ( sal_True )
3311 {
3312     mbDisplayable       = sal_True;
3313     mbCloserVisible     = sal_False;
3314     mbFloatBtnVisible   = sal_False;
3315     mbHideBtnVisible    = sal_False;
3316     ImplLoadRes( rResId );
3317 }
3318 
3319 MenuBar::~MenuBar()
3320 {
3321     ImplDestroy( this, sal_True );
3322 }
3323 
3324 void MenuBar::ShowCloser( sal_Bool bShow )
3325 {
3326     ShowButtons( bShow, mbFloatBtnVisible, mbHideBtnVisible );
3327 }
3328 
3329 void MenuBar::ShowFloatButton( sal_Bool bShow )
3330 {
3331     ShowButtons( mbCloserVisible, bShow, mbHideBtnVisible );
3332 }
3333 
3334 void MenuBar::ShowHideButton( sal_Bool bShow )
3335 {
3336     ShowButtons( mbCloserVisible, mbFloatBtnVisible, bShow );
3337 }
3338 
3339 void MenuBar::ShowButtons( sal_Bool bClose, sal_Bool bFloat, sal_Bool bHide )
3340 {
3341     if ( (bClose != mbCloserVisible)    ||
3342          (bFloat != mbFloatBtnVisible)  ||
3343          (bHide  != mbHideBtnVisible) )
3344     {
3345         mbCloserVisible     = bClose;
3346         mbFloatBtnVisible   = bFloat;
3347         mbHideBtnVisible    = bHide;
3348         if ( ImplGetWindow() )
3349             ((MenuBarWindow*)ImplGetWindow())->ShowButtons( bClose, bFloat, bHide );
3350     }
3351 }
3352 
3353 void MenuBar::SetDisplayable( sal_Bool bDisplayable )
3354 {
3355     if( bDisplayable != mbDisplayable )
3356     {
3357         mbDisplayable = bDisplayable;
3358         MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow();
3359         if( pMenuWin )
3360             pMenuWin->ImplLayoutChanged();
3361     }
3362 }
3363 
3364 Window* MenuBar::ImplCreate( Window* pParent, Window* pWindow, MenuBar* pMenu )
3365 {
3366     if ( !pWindow )
3367         pWindow = new MenuBarWindow( pParent );
3368 
3369     pMenu->pStartedFrom = 0;
3370     pMenu->pWindow = pWindow;
3371     ((MenuBarWindow*)pWindow)->SetMenu( pMenu );
3372     long nHeight = pMenu->ImplCalcSize( pWindow ).Height();
3373 
3374     // depending on the native implementation or the displayable flag
3375     // the menubar windows is supressed (ie, height=0)
3376     if( !((MenuBar*) pMenu)->IsDisplayable() ||
3377         ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) )
3378         nHeight = 0;
3379 
3380     pWindow->SetPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT );
3381     return pWindow;
3382 }
3383 
3384 void MenuBar::ImplDestroy( MenuBar* pMenu, sal_Bool bDelete )
3385 {
3386     MenuBarWindow* pWindow = (MenuBarWindow*) pMenu->ImplGetWindow();
3387     if ( pWindow && bDelete )
3388     {
3389         pWindow->KillActivePopup();
3390         delete pWindow;
3391     }
3392     pMenu->pWindow = NULL;
3393 }
3394 
3395 sal_Bool MenuBar::ImplHandleKeyEvent( const KeyEvent& rKEvent, sal_Bool bFromMenu )
3396 {
3397     sal_Bool bDone = sal_False;
3398 
3399     // No keyboard processing when system handles the menu or our menubar is invisible
3400     if( !IsDisplayable() ||
3401         ( ImplGetSalMenu() && ImplGetSalMenu()->VisibleMenuBar() ) )
3402         return bDone;
3403 
3404     // Enabled-Abfragen, falls diese Methode von einem anderen Fenster gerufen wurde...
3405     Window* pWin = ImplGetWindow();
3406     if ( pWin && pWin->IsEnabled() && pWin->IsInputEnabled()  && ! pWin->IsInModalMode() )
3407         bDone = ((MenuBarWindow*)pWin)->ImplHandleKeyEvent( rKEvent, bFromMenu );
3408     return bDone;
3409 }
3410 
3411 // -----------------------------------------------------------------------
3412 
3413 void MenuBar::SelectEntry( sal_uInt16 nId )
3414 {
3415     MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow();
3416 
3417     if( pMenuWin )
3418     {
3419         pMenuWin->GrabFocus();
3420         nId = GetItemPos( nId );
3421 
3422         // #99705# popup the selected menu
3423         pMenuWin->SetAutoPopup( sal_True );
3424         if( ITEMPOS_INVALID != pMenuWin->nHighlightedItem )
3425         {
3426             pMenuWin->KillActivePopup();
3427             pMenuWin->ChangeHighlightItem( ITEMPOS_INVALID, sal_False );
3428         }
3429         if( nId != ITEMPOS_INVALID )
3430             pMenuWin->ChangeHighlightItem( nId, sal_False );
3431     }
3432 }
3433 
3434 // -----------------------------------------------------------------------
3435 
3436 // handler for native menu selection and command events
3437 
3438 sal_Bool MenuBar::HandleMenuActivateEvent( Menu *pMenu ) const
3439 {
3440     if( pMenu )
3441     {
3442 		ImplMenuDelData aDelData( this );
3443 
3444         pMenu->pStartedFrom = (Menu*)this;
3445         pMenu->bInCallback = sal_True;
3446         pMenu->Activate();
3447 
3448 		if( !aDelData.isDeleted() )
3449 	        pMenu->bInCallback = sal_False;
3450     }
3451     return sal_True;
3452 }
3453 
3454 sal_Bool MenuBar::HandleMenuDeActivateEvent( Menu *pMenu ) const
3455 {
3456     if( pMenu )
3457     {
3458 		ImplMenuDelData aDelData( this );
3459 
3460         pMenu->pStartedFrom = (Menu*)this;
3461         pMenu->bInCallback = sal_True;
3462         pMenu->Deactivate();
3463 		if( !aDelData.isDeleted() )
3464 			pMenu->bInCallback = sal_False;
3465     }
3466     return sal_True;
3467 }
3468 
3469 sal_Bool MenuBar::HandleMenuHighlightEvent( Menu *pMenu, sal_uInt16 nHighlightEventId ) const
3470 {
3471     if( !pMenu )
3472         pMenu = ((Menu*) this)->ImplFindMenu( nHighlightEventId );
3473     if( pMenu )
3474     {
3475 		ImplMenuDelData aDelData( pMenu );
3476 
3477         if( mnHighlightedItemPos != ITEMPOS_INVALID )
3478             pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, mnHighlightedItemPos );
3479 
3480 		if( !aDelData.isDeleted() )
3481 		{
3482 	        pMenu->mnHighlightedItemPos = pMenu->GetItemPos( nHighlightEventId );
3483 		    pMenu->nSelectedId = nHighlightEventId;
3484 			pMenu->pStartedFrom = (Menu*)this;
3485 			pMenu->ImplCallHighlight( pMenu->mnHighlightedItemPos );
3486 		}
3487         return sal_True;
3488     }
3489     else
3490         return sal_False;
3491 }
3492 
3493 sal_Bool MenuBar::HandleMenuCommandEvent( Menu *pMenu, sal_uInt16 nCommandEventId ) const
3494 {
3495     if( !pMenu )
3496         pMenu = ((Menu*) this)->ImplFindMenu( nCommandEventId );
3497     if( pMenu )
3498     {
3499         pMenu->nSelectedId = nCommandEventId;
3500         pMenu->pStartedFrom = (Menu*)this;
3501         pMenu->ImplSelect();
3502         return sal_True;
3503     }
3504     else
3505         return sal_False;
3506 }
3507 
3508 sal_uInt16 MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, sal_uInt16 i_nPos )
3509 {
3510     return AddMenuBarButton( i_rImage, i_rLink, String(), i_nPos );
3511 }
3512 
3513 sal_uInt16 MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const String& i_rToolTip, sal_uInt16 i_nPos )
3514 {
3515     return pWindow ? static_cast<MenuBarWindow*>(pWindow)->AddMenuBarButton( i_rImage, i_rLink, i_rToolTip, i_nPos ) : 0;
3516 }
3517 
3518 void MenuBar::SetMenuBarButtonHighlightHdl( sal_uInt16 nId, const Link& rLink )
3519 {
3520     if( pWindow )
3521         static_cast<MenuBarWindow*>(pWindow)->SetMenuBarButtonHighlightHdl( nId, rLink );
3522 }
3523 
3524 Rectangle MenuBar::GetMenuBarButtonRectPixel( sal_uInt16 nId )
3525 {
3526     return pWindow ? static_cast<MenuBarWindow*>(pWindow)->GetMenuBarButtonRectPixel( nId ) : Rectangle();
3527 }
3528 
3529 void MenuBar::RemoveMenuBarButton( sal_uInt16 nId )
3530 {
3531     if( pWindow )
3532         static_cast<MenuBarWindow*>(pWindow)->RemoveMenuBarButton( nId );
3533 }
3534 
3535 sal_Bool MenuBar::HandleMenuButtonEvent( Menu *, sal_uInt16 i_nButtonId ) const
3536 {
3537     return static_cast<MenuBarWindow*>(pWindow)->HandleMenuButtonEvent( i_nButtonId );
3538 }
3539 
3540 // -----------------------------------------------------------------------
3541 
3542 // sal_Bool PopupMenu::bAnyPopupInExecute = sal_False;
3543 
3544 PopupMenu::PopupMenu()
3545 {
3546     pRefAutoSubMenu = NULL;
3547 }
3548 
3549 PopupMenu::PopupMenu( const ResId& rResId )
3550 {
3551     pRefAutoSubMenu = NULL;
3552     ImplLoadRes( rResId );
3553 }
3554 
3555 PopupMenu::PopupMenu( const PopupMenu& rMenu ) : Menu()
3556 {
3557     pRefAutoSubMenu = NULL;
3558     *this = rMenu;
3559 }
3560 
3561 PopupMenu::~PopupMenu()
3562 {
3563     if( pRefAutoSubMenu && *pRefAutoSubMenu == this )
3564         *pRefAutoSubMenu = NULL;    // #111060# avoid second delete in ~MenuItemData
3565 }
3566 
3567 sal_Bool PopupMenu::IsInExecute()
3568 {
3569     return GetActivePopupMenu() ? sal_True : sal_False;
3570 }
3571 
3572 PopupMenu* PopupMenu::GetActivePopupMenu()
3573 {
3574     ImplSVData* pSVData = ImplGetSVData();
3575     return pSVData->maAppData.mpActivePopupMenu;
3576 }
3577 
3578 void PopupMenu::EndExecute( sal_uInt16 nSelectId )
3579 {
3580     if ( ImplGetWindow() )
3581         ImplGetFloatingWindow()->EndExecute( nSelectId );
3582 }
3583 
3584 void PopupMenu::SelectEntry( sal_uInt16 nId )
3585 {
3586     if ( ImplGetWindow() )
3587     {
3588         if( nId != ITEMPOS_INVALID )
3589         {
3590 	        sal_uInt16 nPos;
3591 		    MenuItemData* pData = GetItemList()->GetData( nId, nPos );
3592             if ( pData->pSubMenu )
3593                 ImplGetFloatingWindow()->ChangeHighlightItem( nPos, sal_True );
3594             else
3595                 ImplGetFloatingWindow()->EndExecute( nId );
3596         }
3597         else
3598         {
3599 			MenuFloatingWindow* pFloat = ImplGetFloatingWindow();
3600 	        pFloat->GrabFocus();
3601 			sal_uInt16 nPos;
3602 			for( nPos = 0; nPos < GetItemList()->Count(); nPos++ )
3603 			{
3604 				MenuItemData* pData = (MenuItemData*)GetItemList()->GetObject( nPos );
3605 				if( pData->pSubMenu )
3606 				{
3607 					pFloat->KillActivePopup();
3608 				}
3609 			}
3610             pFloat->ChangeHighlightItem( ITEMPOS_INVALID, sal_False );
3611         }
3612     }
3613 }
3614 
3615 void PopupMenu::SetSelectedEntry( sal_uInt16 nId )
3616 {
3617     nSelectedId = nId;
3618 }
3619 
3620 sal_uInt16 PopupMenu::Execute( Window* pExecWindow, const Point& rPopupPos )
3621 {
3622     return Execute( pExecWindow, Rectangle( rPopupPos, rPopupPos ), POPUPMENU_EXECUTE_DOWN );
3623 }
3624 
3625 sal_uInt16 PopupMenu::Execute( Window* pExecWindow, const Rectangle& rRect, sal_uInt16 nFlags )
3626 {
3627     ENSURE_OR_RETURN( pExecWindow, "PopupMenu::Execute: need a non-NULL window!", 0 );
3628 
3629 
3630     sal_uLong nPopupModeFlags = 0;
3631     if ( nFlags & POPUPMENU_EXECUTE_DOWN )
3632         nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
3633     else if ( nFlags & POPUPMENU_EXECUTE_UP )
3634         nPopupModeFlags = FLOATWIN_POPUPMODE_UP;
3635     else if ( nFlags & POPUPMENU_EXECUTE_LEFT )
3636         nPopupModeFlags = FLOATWIN_POPUPMODE_LEFT;
3637     else if ( nFlags & POPUPMENU_EXECUTE_RIGHT )
3638         nPopupModeFlags = FLOATWIN_POPUPMODE_RIGHT;
3639     else
3640         nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
3641 
3642     if (nFlags & POPUPMENU_NOMOUSEUPCLOSE )                      // allow popup menus to stay open on mouse button up
3643         nPopupModeFlags |= FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE;    // useful if the menu was opened on mousebutton down (eg toolbox configuration)
3644 
3645     return ImplExecute( pExecWindow, rRect, nPopupModeFlags, 0, sal_False );
3646 }
3647 
3648 sal_uInt16 PopupMenu::ImplExecute( Window* pW, const Rectangle& rRect, sal_uLong nPopupModeFlags, Menu* pSFrom, sal_Bool bPreSelectFirst )
3649 {
3650     if ( !pSFrom && ( PopupMenu::IsInExecute() || !GetItemCount() ) )
3651         return 0;
3652 
3653     delete mpLayoutData, mpLayoutData = NULL;
3654 
3655     ImplSVData* pSVData = ImplGetSVData();
3656 
3657     pStartedFrom = pSFrom;
3658     nSelectedId = 0;
3659     bCanceled = sal_False;
3660 
3661     sal_uLong nFocusId = 0;
3662     sal_Bool bRealExecute = sal_False;
3663     if ( !pStartedFrom )
3664     {
3665         pSVData->maWinData.mbNoDeactivate = sal_True;
3666         nFocusId = Window::SaveFocus();
3667         bRealExecute = sal_True;
3668     }
3669     else
3670     {
3671         // assure that only one menu is open at a time
3672         if( pStartedFrom->bIsMenuBar && pSVData->maWinData.mpFirstFloat )
3673             pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
3674     }
3675 
3676     DBG_ASSERT( !ImplGetWindow(), "Win?!" );
3677     Rectangle aRect( rRect );
3678     aRect.SetPos( pW->OutputToScreenPixel( aRect.TopLeft() ) );
3679 
3680     WinBits nStyle = WB_BORDER;
3681     if ( bRealExecute )
3682         nPopupModeFlags |= FLOATWIN_POPUPMODE_NEWLEVEL;
3683     if ( !pStartedFrom || !pStartedFrom->bIsMenuBar )
3684         nPopupModeFlags |= FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK | FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE;
3685 
3686     nPopupModeFlags |= FLOATWIN_POPUPMODE_NOKEYCLOSE;
3687 
3688     // Kann beim Debuggen hilfreich sein.
3689     // nPopupModeFlags |= FLOATWIN_POPUPMODE_NOFOCUSCLOSE;
3690 
3691     ImplDelData aDelData;
3692     pW->ImplAddDel( &aDelData );
3693 
3694     bInCallback = sal_True; // hier schon setzen, falls Activate ueberladen
3695     Activate();
3696     bInCallback = sal_False;
3697 
3698     if ( aDelData.IsDelete() )
3699         return 0;   // Error
3700 
3701     pW->ImplRemoveDel( &aDelData );
3702 
3703     if ( bCanceled || bKilled )
3704         return 0;
3705 
3706     if ( !GetItemCount() )
3707         return 0;
3708 
3709     // Das Flag MENU_FLAG_HIDEDISABLEDENTRIES wird vererbt.
3710     if ( pSFrom )
3711     {
3712         if ( pSFrom->nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES )
3713             nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES;
3714         else
3715             nMenuFlags &= ~MENU_FLAG_HIDEDISABLEDENTRIES;
3716     }
3717     else
3718         // #102790# context menues shall never show disabled entries
3719         nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES;
3720 
3721 
3722     sal_uInt16 nVisibleEntries = ImplGetVisibleItemCount();
3723     if ( !nVisibleEntries )
3724     {
3725         ResMgr* pResMgr = ImplGetResMgr();
3726         if( pResMgr )
3727         {
3728             String aTmpEntryText( ResId( SV_RESID_STRING_NOSELECTIONPOSSIBLE, *pResMgr ) );
3729             MenuItemData* pData = pItemList->Insert(
3730                 0xFFFF, MENUITEM_STRING, 0, aTmpEntryText, Image(), NULL, 0xFFFF );
3731                 pData->bIsTemporary = sal_True;
3732         }
3733     }
3734     else if ( Application::GetSettings().GetStyleSettings().GetAutoMnemonic() && !( nMenuFlags & MENU_FLAG_NOAUTOMNEMONICS ) )
3735     {
3736         CreateAutoMnemonics();
3737     }
3738 
3739     MenuFloatingWindow* pWin = new MenuFloatingWindow( this, pW, nStyle | WB_SYSTEMWINDOW );
3740     if( pSVData->maNWFData.mbFlatMenu )
3741         pWin->SetBorderStyle( WINDOW_BORDER_NOBORDER );
3742     else
3743         pWin->SetBorderStyle( pWin->GetBorderStyle() | WINDOW_BORDER_MENU );
3744     pWindow = pWin;
3745 
3746     Size aSz = ImplCalcSize( pWin );
3747 
3748     long nMaxHeight = pWin->GetDesktopRectPixel().GetHeight();
3749     if( Application::GetScreenCount() > 1 && ! Application::IsMultiDisplay() )
3750     {
3751         Window* pDeskW = pWindow->GetWindow( WINDOW_REALPARENT );
3752         if( ! pDeskW )
3753             pDeskW = pWindow;
3754         Point aDesktopTL( pDeskW->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) );
3755         nMaxHeight = Application::GetWorkAreaPosSizePixel(
3756             Application::GetBestScreen( Rectangle( aDesktopTL, aRect.GetSize() ) )
3757             ).GetHeight();
3758     }
3759     if ( pStartedFrom && pStartedFrom->bIsMenuBar )
3760         nMaxHeight -= pW->GetSizePixel().Height();
3761     sal_Int32 nLeft, nTop, nRight, nBottom;
3762     pWindow->GetBorder( nLeft, nTop, nRight, nBottom );
3763     nMaxHeight -= nTop+nBottom;
3764     if ( aSz.Height() > nMaxHeight )
3765     {
3766         pWin->EnableScrollMenu( sal_True );
3767         sal_uInt16 nStart = ImplGetFirstVisible();
3768         sal_uInt16 nEntries = ImplCalcVisEntries( nMaxHeight, nStart );
3769         aSz.Height() = ImplCalcHeight( nEntries );
3770     }
3771 
3772     pWin->SetFocusId( nFocusId );
3773     pWin->SetOutputSizePixel( aSz );
3774     // #102158# menus must never grab the focus, otherwise
3775     // they will be closed immediately
3776     // from now on focus grabbing is only prohibited automatically if
3777     // FLOATWIN_POPUPMODE_GRABFOCUS was set (which is done below), because some
3778     // floaters (like floating toolboxes) may grab the focus
3779     // pWin->GrabFocus();
3780     if ( GetItemCount() )
3781     {
3782         SalMenu* pMenu = ImplGetSalMenu();
3783         if( pMenu && bRealExecute && pMenu->ShowNativePopupMenu( pWin, aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS ) )
3784         {
3785             pWin->StopExecute(0);
3786             pWin->doShutdown();
3787             pWindow->doLazyDelete();
3788             pWindow = NULL;
3789             return nSelectedId;
3790         }
3791         else
3792         {
3793             pWin->StartPopupMode( aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS );
3794         }
3795         if( pSFrom )
3796         {
3797             sal_uInt16 aPos;
3798             if( pSFrom->bIsMenuBar )
3799                 aPos = ((MenuBarWindow *) pSFrom->pWindow)->GetHighlightedItem();
3800             else
3801                 aPos = ((MenuFloatingWindow *) pSFrom->pWindow)->GetHighlightedItem();
3802 
3803             pWin->SetPosInParent( aPos );  // store position to be sent in SUBMENUDEACTIVATE
3804             pSFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUACTIVATE, aPos );
3805         }
3806     }
3807     if ( bPreSelectFirst )
3808     {
3809         sal_uInt16 nCount = (sal_uInt16)pItemList->Count();
3810         for ( sal_uInt16 n = 0; n < nCount; n++ )
3811         {
3812             MenuItemData* pData = pItemList->GetDataFromPos( n );
3813             if (   ( pData->bEnabled || !Application::GetSettings().GetStyleSettings().GetSkipDisabledInMenus() )
3814                 && ( pData->eType != MENUITEM_SEPARATOR ) && ImplIsVisible( n ) && ImplIsSelectable( n ) )
3815             {
3816                 pWin->ChangeHighlightItem( n, sal_False );
3817                 break;
3818             }
3819         }
3820     }
3821     if ( bRealExecute )
3822     {
3823         pWin->ImplAddDel( &aDelData );
3824 
3825         ImplDelData aModalWinDel;
3826         pW->ImplAddDel( &aModalWinDel );
3827         pW->ImplIncModalCount();
3828 
3829         pWin->Execute();
3830 
3831         DBG_ASSERT( ! aModalWinDel.IsDead(), "window for popup died, modal count incorrect !" );
3832         if( ! aModalWinDel.IsDead() )
3833             pW->ImplDecModalCount();
3834 
3835         if ( !aDelData.IsDelete() )
3836             pWin->ImplRemoveDel( &aDelData );
3837         else
3838             return 0;
3839 
3840         // Focus wieder herstellen (kann schon im Select wieder
3841         // hergestellt wurden sein
3842         nFocusId = pWin->GetFocusId();
3843         if ( nFocusId )
3844         {
3845             pWin->SetFocusId( 0 );
3846             pSVData->maWinData.mbNoDeactivate = sal_False;
3847         }
3848         pWin->ImplEndPopupMode( 0, nFocusId );
3849 
3850         if ( nSelectedId )  // Dann abraeumen... ( sonst macht TH das )
3851         {
3852             PopupMenu* pSub = pWin->GetActivePopup();
3853             while ( pSub )
3854             {
3855                 pSub->ImplGetFloatingWindow()->EndPopupMode();
3856                 pSub = pSub->ImplGetFloatingWindow()->GetActivePopup();
3857             }
3858         }
3859         pWin->doShutdown();
3860         pWindow->doLazyDelete();
3861         pWindow = NULL;
3862 
3863         // Steht noch ein Select aus?
3864         Menu* pSelect = ImplFindSelectMenu();
3865         if ( pSelect )
3866         {
3867             // Beim Popup-Menu muss das Select vor dem Verlassen von Execute gerufen werden!
3868             Application::RemoveUserEvent( pSelect->nEventId );
3869             pSelect->nEventId = 0;
3870             pSelect->Select();
3871         }
3872     }
3873 
3874     return bRealExecute ? nSelectedId : 0;
3875 }
3876 
3877 sal_uInt16 PopupMenu::ImplCalcVisEntries( long nMaxHeight, sal_uInt16 nStartEntry, sal_uInt16* pLastVisible ) const
3878 {
3879     nMaxHeight -= 2 * ImplGetFloatingWindow()->GetScrollerHeight();
3880 
3881     long nHeight = 0;
3882     sal_uInt16 nEntries = (sal_uInt16) pItemList->Count();
3883     sal_uInt16 nVisEntries = 0;
3884 
3885     if ( pLastVisible )
3886         *pLastVisible = 0;
3887 
3888     for ( sal_uInt16 n = nStartEntry; n < nEntries; n++ )
3889     {
3890         if ( ImplIsVisible( n ) )
3891         {
3892             MenuItemData* pData = pItemList->GetDataFromPos( n );
3893             nHeight += pData->aSz.Height();
3894             if ( nHeight > nMaxHeight )
3895                 break;
3896 
3897             if ( pLastVisible )
3898                 *pLastVisible = n;
3899             nVisEntries++;
3900         }
3901     }
3902     return nVisEntries;
3903 }
3904 
3905 long PopupMenu::ImplCalcHeight( sal_uInt16 nEntries ) const
3906 {
3907     long nHeight = 0;
3908 
3909     sal_uInt16 nFound = 0;
3910     for ( sal_uInt16 n = 0; ( nFound < nEntries ) && ( n < pItemList->Count() ); n++ )
3911     {
3912         if ( ImplIsVisible( (sal_uInt16) n ) )
3913         {
3914             MenuItemData* pData = pItemList->GetDataFromPos( n );
3915             nHeight += pData->aSz.Height();
3916             nFound++;
3917         }
3918     }
3919 
3920     nHeight += 2*ImplGetFloatingWindow()->GetScrollerHeight();
3921 
3922     return nHeight;
3923 }
3924 
3925 
3926 static void ImplInitMenuWindow( Window* pWin, sal_Bool bFont, sal_Bool bMenuBar )
3927 {
3928     const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
3929 
3930     if ( bFont )
3931         pWin->SetPointFont( rStyleSettings.GetMenuFont() );
3932     if( bMenuBar )
3933     {
3934         if( pWin->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
3935         {
3936             pWin->SetBackground();  // background will be drawn by NWF
3937         }
3938         else
3939         {
3940             Wallpaper aWallpaper;
3941             aWallpaper.SetStyle( WALLPAPER_APPLICATIONGRADIENT );
3942             pWin->SetBackground( aWallpaper );
3943             pWin->SetPaintTransparent( sal_False );
3944             pWin->SetParentClipMode( 0 );
3945         }
3946     }
3947     else
3948     {
3949         if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
3950         {
3951             pWin->SetBackground();  // background will be drawn by NWF
3952         }
3953         else
3954             pWin->SetBackground( Wallpaper( rStyleSettings.GetMenuColor() ) );
3955     }
3956 
3957     if ( bMenuBar )
3958         pWin->SetTextColor( rStyleSettings.GetMenuBarTextColor() );
3959     else
3960         pWin->SetTextColor( rStyleSettings.GetMenuTextColor() );
3961     pWin->SetTextFillColor();
3962     pWin->SetLineColor();
3963 }
3964 
3965 MenuFloatingWindow::MenuFloatingWindow( Menu* pMen, Window* pParent, WinBits nStyle ) :
3966     FloatingWindow( pParent, nStyle )
3967 {
3968     mpWindowImpl->mbMenuFloatingWindow= sal_True;
3969     pMenu               = pMen;
3970     pActivePopup        = 0;
3971     nSaveFocusId        = 0;
3972     bInExecute          = sal_False;
3973     bScrollMenu         = sal_False;
3974     nHighlightedItem    = ITEMPOS_INVALID;
3975     nMBDownPos          = ITEMPOS_INVALID;
3976     nPosInParent        = ITEMPOS_INVALID;
3977     nScrollerHeight     = 0;
3978 //    nStartY             = 0;
3979     nBorder             = EXTRASPACEY;
3980     nFirstEntry         = 0;
3981     bScrollUp           = sal_False;
3982     bScrollDown         = sal_False;
3983     bIgnoreFirstMove    = sal_True;
3984     bKeyInput           = sal_False;
3985 
3986     EnableSaveBackground();
3987     ImplInitMenuWindow( this, sal_True, sal_False );
3988 
3989     SetPopupModeEndHdl( LINK( this, MenuFloatingWindow, PopupEnd ) );
3990 
3991     aHighlightChangedTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, HighlightChanged ) );
3992 	aHighlightChangedTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() );
3993 	aSubmenuCloseTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() );
3994     aSubmenuCloseTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, SubmenuClose ) );
3995     aScrollTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, AutoScroll ) );
3996 
3997     AddEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) );
3998 }
3999 
4000 void MenuFloatingWindow::doShutdown()
4001 {
4002     if( pMenu )
4003     {
4004         // #105373# notify toolkit that highlight was removed
4005         // otherwise the entry will not be read when the menu is opened again
4006         if( nHighlightedItem != ITEMPOS_INVALID )
4007             pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
4008 
4009         if( !bKeyInput && pMenu && pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
4010         {
4011             // #102461# remove highlight in parent
4012             MenuItemData* pData;
4013             sal_uInt16 i, nCount = (sal_uInt16)pMenu->pStartedFrom->pItemList->Count();
4014             for(i = 0; i < nCount; i++)
4015             {
4016                 pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i );
4017                 if( pData && ( pData->pSubMenu == pMenu ) )
4018                     break;
4019             }
4020             if( i < nCount )
4021             {
4022                 MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow();
4023                 if( pPWin )
4024                     pPWin->HighlightItem( i, sal_False );
4025             }
4026         }
4027 
4028         // free the reference to the accessible component
4029         SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() );
4030 
4031         aHighlightChangedTimer.Stop();
4032 
4033         // #95056# invalidate screen area covered by system window
4034         // so this can be taken into account if the commandhandler performs a scroll operation
4035         if( GetParent() )
4036         {
4037             Rectangle aInvRect( GetWindowExtentsRelative( GetParent() ) );
4038             GetParent()->Invalidate( aInvRect );
4039         }
4040         pMenu = NULL;
4041         RemoveEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) );
4042     }
4043 }
4044 
4045 MenuFloatingWindow::~MenuFloatingWindow()
4046 {
4047     doShutdown();
4048 }
4049 
4050 void MenuFloatingWindow::Resize()
4051 {
4052     ImplInitClipRegion();
4053 }
4054 
4055 long MenuFloatingWindow::ImplGetStartY() const
4056 {
4057     long nY = 0;
4058     if( pMenu )
4059     {
4060         for ( sal_uInt16 n = 0; n < nFirstEntry; n++ )
4061             nY += pMenu->GetItemList()->GetDataFromPos( n )->aSz.Height();
4062     }
4063     return -nY;
4064 }
4065 
4066 Region MenuFloatingWindow::ImplCalcClipRegion( sal_Bool bIncludeLogo ) const
4067 {
4068     Size aOutSz = GetOutputSizePixel();
4069     Point aPos;
4070     Rectangle aRect( aPos, aOutSz );
4071     aRect.Top() += nScrollerHeight;
4072     aRect.Bottom() -= nScrollerHeight;
4073 
4074     if ( pMenu && pMenu->pLogo && !bIncludeLogo )
4075         aRect.Left() += pMenu->pLogo->aBitmap.GetSizePixel().Width();
4076 
4077     Region aRegion = aRect;
4078     if ( pMenu && pMenu->pLogo && bIncludeLogo && nScrollerHeight )
4079         aRegion.Union( Rectangle( Point(), Size( pMenu->pLogo->aBitmap.GetSizePixel().Width(), aOutSz.Height() ) ) );
4080 
4081     return aRegion;
4082 }
4083 
4084 void MenuFloatingWindow::ImplInitClipRegion()
4085 {
4086     if ( IsScrollMenu() )
4087     {
4088         SetClipRegion( ImplCalcClipRegion() );
4089     }
4090     else
4091     {
4092         SetClipRegion();
4093     }
4094 }
4095 
4096 void MenuFloatingWindow::ImplHighlightItem( const MouseEvent& rMEvt, sal_Bool bMBDown )
4097 {
4098     if( ! pMenu )
4099         return;
4100 
4101     long nY = nScrollerHeight;
4102     long nMouseY = rMEvt.GetPosPixel().Y();
4103     Size aOutSz = GetOutputSizePixel();
4104     if ( ( nMouseY >= nY ) && ( nMouseY < ( aOutSz.Height() - nY ) ) )
4105     {
4106         sal_Bool bHighlighted = sal_False;
4107         sal_uInt16 nCount = (sal_uInt16)pMenu->pItemList->Count();
4108         nY += ImplGetStartY();  // ggf. gescrollt.
4109         for ( sal_uInt16 n = 0; !bHighlighted && ( n < nCount ); n++ )
4110         {
4111             if ( pMenu->ImplIsVisible( n ) )
4112             {
4113                 MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( n );
4114                 long nOldY = nY;
4115                 nY += pItemData->aSz.Height();
4116                 if ( ( nOldY <= nMouseY ) && ( nY > nMouseY ) && pMenu->ImplIsSelectable( n ) )
4117                 {
4118                     sal_Bool bPopupArea = sal_True;
4119                     if ( pItemData->nBits & MIB_POPUPSELECT )
4120                     {
4121                         // Nur wenn ueber dem Pfeil geklickt wurde...
4122                         Size aSz = GetOutputSizePixel();
4123                         long nFontHeight = GetTextHeight();
4124                         bPopupArea = ( rMEvt.GetPosPixel().X() >= ( aSz.Width() - nFontHeight - nFontHeight/4 ) );
4125                     }
4126 
4127                     if ( bMBDown )
4128                     {
4129                         if ( n != nHighlightedItem )
4130                         {
4131                             ChangeHighlightItem( (sal_uInt16)n, sal_False );
4132                         }
4133 
4134                         sal_Bool bAllowNewPopup = sal_True;
4135                         if ( pActivePopup )
4136                         {
4137                             MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
4138                             bAllowNewPopup = pData && ( pData->pSubMenu != pActivePopup );
4139                             if ( bAllowNewPopup )
4140                                 KillActivePopup();
4141                         }
4142 
4143                         if ( bPopupArea && bAllowNewPopup )
4144                         {
4145                             HighlightChanged( NULL );
4146                         }
4147                     }
4148                     else
4149                     {
4150                         if ( n != nHighlightedItem )
4151                         {
4152                             ChangeHighlightItem( (sal_uInt16)n, sal_True );
4153                         }
4154                         else if ( pItemData->nBits & MIB_POPUPSELECT )
4155                         {
4156                             if ( bPopupArea && ( pActivePopup != pItemData->pSubMenu ) )
4157                                 HighlightChanged( NULL );
4158                         }
4159                     }
4160                     bHighlighted = sal_True;
4161                 }
4162             }
4163         }
4164         if ( !bHighlighted )
4165             ChangeHighlightItem( ITEMPOS_INVALID, sal_True );
4166     }
4167     else
4168     {
4169         ImplScroll( rMEvt.GetPosPixel() );
4170         ChangeHighlightItem( ITEMPOS_INVALID, sal_True );
4171     }
4172 }
4173 
4174 IMPL_LINK( MenuFloatingWindow, PopupEnd, FloatingWindow*, EMPTYARG )
4175 {
4176     // "this" will be deleted before the end of this method!
4177     Menu* pM = pMenu;
4178     if ( bInExecute )
4179     {
4180         if ( pActivePopup )
4181         {
4182             //DBG_ASSERT( !pActivePopup->ImplGetWindow(), "PopupEnd, obwohl pActivePopup MIT Window!" );
4183             KillActivePopup(); // should be ok to just remove it
4184             //pActivePopup->bCanceled = sal_True;
4185         }
4186         bInExecute = sal_False;
4187         pMenu->bInCallback = sal_True;
4188         pMenu->Deactivate();
4189         pMenu->bInCallback = sal_False;
4190     }
4191     else
4192     {
4193         if( pMenu )
4194         {
4195             // Wenn dies Fenster von TH geschlossen wurde, hat noch ein anderes
4196             // Menu dieses Fenster als pActivePopup.
4197             if ( pMenu->pStartedFrom )
4198             {
4199                 // Das pWin am 'Parent' kann aber schon 0 sein, falls die Kette von
4200                 // vorne abgeraeumt wurde und jetzt die EndPopup-Events eintrudeln
4201                 if ( pMenu->pStartedFrom->bIsMenuBar )
4202                 {
4203                     MenuBarWindow* p = (MenuBarWindow*) pMenu->pStartedFrom->ImplGetWindow();
4204                     if ( p )
4205                         p->PopupClosed( pMenu );
4206                 }
4207                 else
4208                 {
4209                     MenuFloatingWindow* p = (MenuFloatingWindow*) pMenu->pStartedFrom->ImplGetWindow();
4210                     if ( p )
4211                         p->KillActivePopup( (PopupMenu*)pMenu );
4212                 }
4213             }
4214         }
4215     }
4216 
4217     if ( pM )
4218         pM->pStartedFrom = 0;
4219 
4220     return 0;
4221 }
4222 
4223 IMPL_LINK( MenuFloatingWindow, AutoScroll, Timer*, EMPTYARG )
4224 {
4225     ImplScroll( GetPointerPosPixel() );
4226     return 1;
4227 }
4228 
4229 IMPL_LINK( MenuFloatingWindow, HighlightChanged, Timer*, pTimer )
4230 {
4231     if( ! pMenu )
4232         return 0;
4233 
4234     MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
4235     if ( pItemData )
4236     {
4237         if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) )
4238         {
4239             sal_uLong nOldFlags = GetPopupModeFlags();
4240             SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
4241             KillActivePopup();
4242             SetPopupModeFlags( nOldFlags );
4243         }
4244         if ( pItemData->bEnabled && pItemData->pSubMenu && pItemData->pSubMenu->GetItemCount() && ( pItemData->pSubMenu != pActivePopup ) )
4245         {
4246             pActivePopup = (PopupMenu*)pItemData->pSubMenu;
4247             long nY = nScrollerHeight+ImplGetStartY();
4248             MenuItemData* pData = 0;
4249             for ( sal_uLong n = 0; n < nHighlightedItem; n++ )
4250             {
4251                 pData = pMenu->pItemList->GetDataFromPos( n );
4252                 nY += pData->aSz.Height();
4253             }
4254             pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
4255             Size MySize = GetOutputSizePixel();
4256 //          Point MyPos = GetPosPixel();
4257 //          Point aItemTopLeft( MyPos.X(), MyPos.Y()+nY );
4258             Point aItemTopLeft( 0, nY );
4259             Point aItemBottomRight( aItemTopLeft );
4260             aItemBottomRight.X() += MySize.Width();
4261             aItemBottomRight.Y() += pData->aSz.Height();
4262 
4263             // Popups leicht versetzen:
4264             aItemTopLeft.X() += 2;
4265             aItemBottomRight.X() -= 2;
4266             if ( nHighlightedItem )
4267                 aItemTopLeft.Y() -= 2;
4268             else
4269             {
4270                 sal_Int32 nL, nT, nR, nB;
4271                 GetBorder( nL, nT, nR, nB );
4272                 aItemTopLeft.Y() -= nT;
4273             }
4274 
4275             // pTest: Wegen Abstuerzen durch Reschedule() im Aufruf von Activate()
4276             // Ausserdem wird damit auch verhindert, dass SubMenus angezeigt werden,
4277             // die lange im Activate Rescheduled haben und jetzt schon nicht mehr
4278             // angezeigt werden sollen.
4279             Menu* pTest = pActivePopup;
4280             sal_uLong nOldFlags = GetPopupModeFlags();
4281             SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
4282             sal_uInt16 nRet = pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_RIGHT, pMenu, pTimer ? sal_False : sal_True  );
4283             SetPopupModeFlags( nOldFlags );
4284 
4285             // nRet != 0, wenn es waerend Activate() abgeschossen wurde...
4286             if ( !nRet && ( pActivePopup == pTest ) && pActivePopup->ImplGetWindow() )
4287                 pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this );
4288         }
4289     }
4290 
4291     return 0;
4292 }
4293 
4294 IMPL_LINK( MenuFloatingWindow, SubmenuClose, Timer*, EMPTYARG )
4295 {
4296     if( pMenu && pMenu->pStartedFrom )
4297     {
4298         MenuFloatingWindow* pWin = (MenuFloatingWindow*) pMenu->pStartedFrom->GetWindow();
4299         if( pWin )
4300             pWin->KillActivePopup();
4301     }
4302     return 0;
4303 }
4304 
4305 IMPL_LINK( MenuFloatingWindow, ShowHideListener, VclWindowEvent*, pEvent )
4306 {
4307     if( ! pMenu )
4308         return 0;
4309 
4310     if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW )
4311         pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID );
4312     else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
4313         pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID );
4314     return 0;
4315 }
4316 
4317 void MenuFloatingWindow::EnableScrollMenu( sal_Bool b )
4318 {
4319     bScrollMenu = b;
4320     nScrollerHeight = b ? (sal_uInt16) GetSettings().GetStyleSettings().GetScrollBarSize() /2 : 0;
4321     bScrollDown = sal_True;
4322     ImplInitClipRegion();
4323 }
4324 
4325 void MenuFloatingWindow::Execute()
4326 {
4327     ImplSVData* pSVData = ImplGetSVData();
4328 
4329     pSVData->maAppData.mpActivePopupMenu = (PopupMenu*)pMenu;
4330 
4331     bInExecute = sal_True;
4332 //  bCallingSelect = sal_False;
4333 
4334     while ( bInExecute )
4335         Application::Yield();
4336 
4337     pSVData->maAppData.mpActivePopupMenu = NULL;
4338 
4339 //  while ( bCallingSelect )
4340 //      Application::Yield();
4341 }
4342 
4343 void MenuFloatingWindow::StopExecute( sal_uLong nFocusId )
4344 {
4345     // Focus wieder herstellen
4346     // (kann schon im Select wieder hergestellt wurden sein)
4347     if ( nSaveFocusId )
4348     {
4349         Window::EndSaveFocus( nFocusId, sal_False );
4350         nFocusId = nSaveFocusId;
4351         if ( nFocusId )
4352         {
4353             nSaveFocusId = 0;
4354             ImplGetSVData()->maWinData.mbNoDeactivate = sal_False;
4355         }
4356     }
4357     ImplEndPopupMode( 0, nFocusId );
4358 
4359     aHighlightChangedTimer.Stop();
4360     bInExecute = sal_False;
4361     if ( pActivePopup )
4362     {
4363         KillActivePopup();
4364     }
4365     // notify parent, needed for accessibility
4366     if( pMenu && pMenu->pStartedFrom )
4367         pMenu->pStartedFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUDEACTIVATE, nPosInParent );
4368 }
4369 
4370 void MenuFloatingWindow::KillActivePopup( PopupMenu* pThisOnly )
4371 {
4372     if ( pActivePopup && ( !pThisOnly || ( pThisOnly == pActivePopup ) ) )
4373     {
4374         if( pActivePopup->pWindow != NULL )
4375             if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() )
4376                 return; // kill it later
4377         if ( pActivePopup->bInCallback )
4378             pActivePopup->bCanceled = sal_True;
4379 
4380         // Vor allen Aktionen schon pActivePopup = 0, falls z.B.
4381         // PopupModeEndHdl des zu zerstoerenden Popups mal synchron gerufen wird.
4382         PopupMenu* pPopup = pActivePopup;
4383         pActivePopup = NULL;
4384         pPopup->bInCallback = sal_True;
4385         pPopup->Deactivate();
4386         pPopup->bInCallback = sal_False;
4387         if ( pPopup->ImplGetWindow() )
4388         {
4389             pPopup->ImplGetFloatingWindow()->StopExecute();
4390             pPopup->ImplGetFloatingWindow()->doShutdown();
4391             pPopup->pWindow->doLazyDelete();
4392             pPopup->pWindow = NULL;
4393 
4394             Update();
4395         }
4396     }
4397 }
4398 
4399 void MenuFloatingWindow::EndExecute()
4400 {
4401     Menu* pStart = pMenu ? pMenu->ImplGetStartMenu() : NULL;
4402     sal_uLong nFocusId = 0;
4403     if ( pStart && pStart->bIsMenuBar )
4404     {
4405         nFocusId = ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->GetFocusId();
4406         if ( nFocusId )
4407         {
4408             ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->SetFocusId( 0 );
4409             ImplGetSVData()->maWinData.mbNoDeactivate = sal_False;
4410         }
4411     }
4412 
4413     // Wenn von woanders gestartet, dann ab dort aufraumen:
4414     MenuFloatingWindow* pCleanUpFrom = this;
4415     MenuFloatingWindow* pWin = this;
4416     while ( pWin && !pWin->bInExecute &&
4417         pWin->pMenu->pStartedFrom && !pWin->pMenu->pStartedFrom->bIsMenuBar )
4418     {
4419         pWin = ((PopupMenu*)pWin->pMenu->pStartedFrom)->ImplGetFloatingWindow();
4420     }
4421     if ( pWin )
4422         pCleanUpFrom = pWin;
4423 
4424     // Dies Fenster wird gleich zerstoert => Daten lokal merken...
4425     Menu* pM = pMenu;
4426     sal_uInt16 nItem = nHighlightedItem;
4427 
4428     pCleanUpFrom->StopExecute( nFocusId );
4429 
4430     if ( nItem != ITEMPOS_INVALID && pM )
4431     {
4432         MenuItemData* pItemData = pM->GetItemList()->GetDataFromPos( nItem );
4433         if ( pItemData && !pItemData->bIsTemporary )
4434         {
4435             pM->nSelectedId = pItemData->nId;
4436             if ( pStart )
4437                 pStart->nSelectedId = pItemData->nId;
4438 
4439             pM->ImplSelect();
4440         }
4441     }
4442 }
4443 
4444 void MenuFloatingWindow::EndExecute( sal_uInt16 nId )
4445 {
4446     sal_uInt16 nPos;
4447     if ( pMenu && pMenu->GetItemList()->GetData( nId, nPos ) )
4448         nHighlightedItem = nPos;
4449     else
4450         nHighlightedItem = ITEMPOS_INVALID;
4451 
4452     EndExecute();
4453 }
4454 
4455 void MenuFloatingWindow::MouseButtonDown( const MouseEvent& rMEvt )
4456 {
4457     // TH macht ein ToTop auf dieses Fenster, aber das aktive Popup
4458     // soll oben bleiben...
4459     // due to focus chage this would close all menues -> don't do it (#94123)
4460     //if ( pActivePopup && pActivePopup->ImplGetWindow() && !pActivePopup->ImplGetFloatingWindow()->pActivePopup )
4461     //    pActivePopup->ImplGetFloatingWindow()->ToTop( TOTOP_NOGRABFOCUS );
4462 
4463     ImplHighlightItem( rMEvt, sal_True );
4464 
4465     nMBDownPos = nHighlightedItem;
4466 }
4467 
4468 void MenuFloatingWindow::MouseButtonUp( const MouseEvent& rMEvt )
4469 {
4470     MenuItemData* pData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL;
4471     // nMBDownPos in lokaler Variable merken und gleich zuruecksetzen,
4472     // weil nach EndExecute zu spaet
4473     sal_uInt16 _nMBDownPos = nMBDownPos;
4474     nMBDownPos = ITEMPOS_INVALID;
4475     if ( pData && pData->bEnabled && ( pData->eType != MENUITEM_SEPARATOR ) )
4476     {
4477         if ( !pData->pSubMenu )
4478         {
4479             EndExecute();
4480         }
4481         else if ( ( pData->nBits & MIB_POPUPSELECT ) && ( nHighlightedItem == _nMBDownPos ) && ( rMEvt.GetClicks() == 2 ) )
4482         {
4483             // Nicht wenn ueber dem Pfeil geklickt wurde...
4484             Size aSz = GetOutputSizePixel();
4485             long nFontHeight = GetTextHeight();
4486             if ( rMEvt.GetPosPixel().X() < ( aSz.Width() - nFontHeight - nFontHeight/4 ) )
4487                 EndExecute();
4488         }
4489     }
4490 
4491 }
4492 
4493 void MenuFloatingWindow::MouseMove( const MouseEvent& rMEvt )
4494 {
4495     if ( !IsVisible() || rMEvt.IsSynthetic() || rMEvt.IsEnterWindow() )
4496         return;
4497 
4498     if ( rMEvt.IsLeaveWindow() )
4499     {
4500 #ifdef OS2
4501         if ( ImplHilite(rMEvt) )
4502         {
4503 #endif
4504         // #102461# do not remove highlight if a popup menu is open at this position
4505         MenuItemData* pData = pMenu ? pMenu->pItemList->GetDataFromPos( nHighlightedItem ) : NULL;
4506         // close popup with some delayed if we leave somewhere else
4507         if( pActivePopup && pData && pData->pSubMenu != pActivePopup )
4508             pActivePopup->ImplGetFloatingWindow()->aSubmenuCloseTimer.Start();
4509 
4510         if( !pActivePopup || (pData && pData->pSubMenu != pActivePopup ) )
4511             ChangeHighlightItem( ITEMPOS_INVALID, sal_False );
4512 #ifdef OS2
4513         }
4514 #endif
4515 
4516         if ( IsScrollMenu() )
4517             ImplScroll( rMEvt.GetPosPixel() );
4518     }
4519     else
4520 #ifdef OS2
4521         if ( ImplHilite(rMEvt) )
4522 #endif
4523     {
4524         aSubmenuCloseTimer.Stop();
4525 		if( bIgnoreFirstMove )
4526 			bIgnoreFirstMove = sal_False;
4527 		else
4528 			ImplHighlightItem( rMEvt, sal_False );
4529     }
4530 }
4531 
4532 void MenuFloatingWindow::ImplScroll( sal_Bool bUp )
4533 {
4534     KillActivePopup();
4535     Update();
4536 
4537     if( ! pMenu )
4538         return;
4539 
4540     HighlightItem( nHighlightedItem, sal_False );
4541 
4542     pMenu->ImplKillLayoutData();
4543 
4544     if ( bScrollUp && bUp )
4545     {
4546         nFirstEntry = pMenu->ImplGetPrevVisible( nFirstEntry );
4547         DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" );
4548 
4549         long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height();
4550 
4551 //        nStartY += nEntryHeight;
4552 
4553         if ( !bScrollDown )
4554         {
4555             bScrollDown = sal_True;
4556             ImplDrawScroller( sal_False );
4557         }
4558 
4559         if ( pMenu->ImplGetPrevVisible( nFirstEntry ) == ITEMPOS_INVALID )
4560         {
4561             bScrollUp = sal_False;
4562             ImplDrawScroller( sal_True );
4563         }
4564 
4565         Scroll( 0, nScrollEntryHeight, ImplCalcClipRegion( sal_False ).GetBoundRect(), SCROLL_CLIP );
4566     }
4567     else if ( bScrollDown && !bUp )
4568     {
4569         long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height();
4570 
4571         nFirstEntry = pMenu->ImplGetNextVisible( nFirstEntry );
4572         DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" );
4573 
4574 
4575         if ( !bScrollUp )
4576         {
4577             bScrollUp = sal_True;
4578             ImplDrawScroller( sal_True );
4579         }
4580 
4581         long nHeight = GetOutputSizePixel().Height();
4582         sal_uInt16 nLastVisible;
4583         ((PopupMenu*)pMenu)->ImplCalcVisEntries( nHeight, nFirstEntry, &nLastVisible );
4584         if ( pMenu->ImplGetNextVisible( nLastVisible ) == ITEMPOS_INVALID )
4585         {
4586             bScrollDown = sal_False;
4587             ImplDrawScroller( sal_False );
4588         }
4589 
4590 //        nStartY -= nEntryHeight;
4591         Scroll( 0, -nScrollEntryHeight, ImplCalcClipRegion( sal_False ).GetBoundRect(), SCROLL_CLIP );
4592     }
4593 
4594     HighlightItem( nHighlightedItem, sal_True );
4595 }
4596 
4597 void MenuFloatingWindow::ImplScroll( const Point& rMousePos )
4598 {
4599     Size aOutSz = GetOutputSizePixel();
4600 
4601     long nY = nScrollerHeight;
4602     long nMouseY = rMousePos.Y();
4603     long nDelta = 0;
4604 
4605     if ( bScrollUp && ( nMouseY < nY ) )
4606     {
4607         ImplScroll( sal_True );
4608         nDelta = nY - nMouseY;
4609     }
4610     else if ( bScrollDown && ( nMouseY > ( aOutSz.Height() - nY ) ) )
4611     {
4612         ImplScroll( sal_False );
4613         nDelta = nMouseY - ( aOutSz.Height() - nY );
4614     }
4615 
4616     if ( nDelta )
4617     {
4618         aScrollTimer.Stop();    // Falls durch MouseMove gescrollt.
4619         long nTimeout;
4620         if ( nDelta < 3 )
4621             nTimeout = 200;
4622         else if ( nDelta < 5 )
4623             nTimeout = 100;
4624         else if ( nDelta < 8 )
4625             nTimeout = 70;
4626         else if ( nDelta < 12 )
4627             nTimeout = 40;
4628         else
4629             nTimeout = 20;
4630         aScrollTimer.SetTimeout( nTimeout );
4631         aScrollTimer.Start();
4632     }
4633 }
4634 void MenuFloatingWindow::ChangeHighlightItem( sal_uInt16 n, sal_Bool bStartPopupTimer )
4635 {
4636     // #57934# ggf. das aktive Popup sofort schliessen, damit TH's Hintergrundsicherung funktioniert.
4637     // #65750# Dann verzichten wir lieber auf den schmalen Streifen Hintergrundsicherung.
4638     //         Sonst lassen sich die Menus schlecht bedienen.
4639 //  MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n );
4640 //  if ( pActivePopup && pNextData && ( pActivePopup != pNextData->pSubMenu ) )
4641 //      KillActivePopup();
4642 
4643     aSubmenuCloseTimer.Stop();
4644     if( ! pMenu )
4645         return;
4646 
4647     if ( nHighlightedItem != ITEMPOS_INVALID )
4648     {
4649         HighlightItem( nHighlightedItem, sal_False );
4650         pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
4651     }
4652 
4653     nHighlightedItem = (sal_uInt16)n;
4654     DBG_ASSERT( pMenu->ImplIsVisible( nHighlightedItem ) || nHighlightedItem == ITEMPOS_INVALID, "ChangeHighlightItem: Not visible!" );
4655     if( nHighlightedItem != ITEMPOS_INVALID )
4656     {
4657         if( pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
4658         {
4659             // #102461# make sure parent entry is highlighted as well
4660             MenuItemData* pData;
4661             sal_uInt16 i, nCount = (sal_uInt16)pMenu->pStartedFrom->pItemList->Count();
4662             for(i = 0; i < nCount; i++)
4663             {
4664                 pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i );
4665                 if( pData && ( pData->pSubMenu == pMenu ) )
4666                     break;
4667             }
4668             if( i < nCount )
4669             {
4670                 MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow();
4671                 if( pPWin && pPWin->nHighlightedItem != i )
4672                 {
4673                     pPWin->HighlightItem( i, sal_True );
4674                     pPWin->nHighlightedItem = i;
4675                 }
4676             }
4677         }
4678         HighlightItem( nHighlightedItem, sal_True );
4679         pMenu->ImplCallHighlight( nHighlightedItem );
4680     }
4681     else
4682         pMenu->nSelectedId = 0;
4683 
4684     if ( bStartPopupTimer )
4685 	{
4686 		// #102438# Menu items are not selectable
4687 		// If a menu item is selected by an AT-tool via the XAccessibleAction, XAccessibleValue
4688 		// or XAccessibleSelection interface, and the parent popup menus are not executed yet,
4689 		// the parent popup menus must be executed SYNCHRONOUSLY, before the menu item is selected.
4690 		if ( GetSettings().GetMouseSettings().GetMenuDelay() )
4691 			aHighlightChangedTimer.Start();
4692 		else
4693             HighlightChanged( &aHighlightChangedTimer );
4694 	}
4695 }
4696 
4697 void MenuFloatingWindow::HighlightItem( sal_uInt16 nPos, sal_Bool bHighlight )
4698 {
4699     if( ! pMenu )
4700         return;
4701 
4702     Size    aSz = GetOutputSizePixel();
4703     long    nStartY = ImplGetStartY();
4704     long    nY = nScrollerHeight+nStartY;
4705     long    nX = 0;
4706 
4707     if ( pMenu->pLogo )
4708         nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
4709 
4710     int nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
4711     nY += nOuterSpace;
4712 
4713     sal_uInt16 nCount = (sal_uInt16)pMenu->pItemList->Count();
4714     for ( sal_uInt16 n = 0; n < nCount; n++ )
4715     {
4716         MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
4717         if ( n == nPos )
4718         {
4719             DBG_ASSERT( pMenu->ImplIsVisible( n ), "Highlight: Item not visible!" );
4720             if ( pData->eType != MENUITEM_SEPARATOR )
4721             {
4722                 sal_Bool bRestoreLineColor = sal_False;
4723                 Color oldLineColor;
4724                 bool bDrawItemRect = true;
4725 
4726                 Rectangle aItemRect( Point( nX+nOuterSpace, nY ), Size( aSz.Width()-2*nOuterSpace, pData->aSz.Height() ) );
4727                 if ( pData->nBits & MIB_POPUPSELECT )
4728                 {
4729                     long nFontHeight = GetTextHeight();
4730                     aItemRect.Right() -= nFontHeight + nFontHeight/4;
4731                 }
4732 
4733                 if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
4734                 {
4735                     Size aPxSize( GetOutputSizePixel() );
4736                     Push( PUSH_CLIPREGION );
4737                     IntersectClipRegion( Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) ) );
4738                     Rectangle aCtrlRect( Point( nX, 0 ), Size( aPxSize.Width()-nX, aPxSize.Height() ) );
4739                     MenupopupValue aVal( pMenu->nTextPos-GUTTERBORDER, aItemRect );
4740                     DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
4741                                        aCtrlRect,
4742                                        CTRL_STATE_ENABLED,
4743                                        aVal,
4744                                        OUString() );
4745                     if( bHighlight &&
4746                         IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) )
4747                     {
4748                         bDrawItemRect = false;
4749                         if( sal_False == DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM,
4750                                                         aItemRect,
4751                                                         CTRL_STATE_SELECTED | ( pData->bEnabled? CTRL_STATE_ENABLED: 0 ),
4752                                                         aVal,
4753                                                         OUString() ) )
4754                         {
4755                             bDrawItemRect = bHighlight;
4756                         }
4757                     }
4758                     else
4759                         bDrawItemRect = bHighlight;
4760                     Pop();
4761                 }
4762                 if( bDrawItemRect )
4763                 {
4764                     if ( bHighlight )
4765                     {
4766                         if( pData->bEnabled )
4767                             SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
4768                         else
4769                         {
4770                             SetFillColor();
4771                             oldLineColor = GetLineColor();
4772                             SetLineColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
4773                             bRestoreLineColor = sal_True;
4774                         }
4775                     }
4776                     else
4777                         SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
4778 
4779                     DrawRect( aItemRect );
4780                 }
4781                 pMenu->ImplPaint( this, nScrollerHeight, nStartY, pData, bHighlight );
4782                 if( bRestoreLineColor )
4783                     SetLineColor( oldLineColor );
4784             }
4785             return;
4786         }
4787 
4788         nY += pData->aSz.Height();
4789     }
4790 }
4791 
4792 Rectangle MenuFloatingWindow::ImplGetItemRect( sal_uInt16 nPos )
4793 {
4794     if( ! pMenu )
4795         return Rectangle();
4796 
4797 	Rectangle aRect;
4798     Size    aSz = GetOutputSizePixel();
4799     long    nStartY = ImplGetStartY();
4800     long    nY = nScrollerHeight+nStartY;
4801     long    nX = 0;
4802 
4803     if ( pMenu->pLogo )
4804         nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
4805 
4806     sal_uInt16 nCount = (sal_uInt16)pMenu->pItemList->Count();
4807     for ( sal_uInt16 n = 0; n < nCount; n++ )
4808     {
4809         MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
4810         if ( n == nPos )
4811         {
4812             DBG_ASSERT( pMenu->ImplIsVisible( n ), "ImplGetItemRect: Item not visible!" );
4813             if ( pData->eType != MENUITEM_SEPARATOR )
4814             {
4815                 aRect = Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) );
4816                 if ( pData->nBits & MIB_POPUPSELECT )
4817                 {
4818                     long nFontHeight = GetTextHeight();
4819                     aRect.Right() -= nFontHeight + nFontHeight/4;
4820                 }
4821             }
4822             break;
4823         }
4824         nY += pData->aSz.Height();
4825     }
4826 	return aRect;
4827 }
4828 
4829 
4830 void MenuFloatingWindow::ImplCursorUpDown( sal_Bool bUp, sal_Bool bHomeEnd )
4831 {
4832     if( ! pMenu )
4833         return;
4834 
4835 	const StyleSettings& rSettings = GetSettings().GetStyleSettings();
4836 
4837     sal_uInt16 n = nHighlightedItem;
4838     if ( n == ITEMPOS_INVALID )
4839     {
4840         if ( bUp )
4841             n = 0;
4842         else
4843             n = pMenu->GetItemCount()-1;
4844     }
4845 
4846     sal_uInt16 nLoop = n;
4847 
4848 	if( bHomeEnd )
4849 	{
4850 		// absolute positioning
4851 		if( bUp )
4852 		{
4853             n = pMenu->GetItemCount();
4854 			nLoop = n-1;
4855 		}
4856 		else
4857 		{
4858 			n = (sal_uInt16)-1;
4859 			nLoop = n+1;
4860 		}
4861 	}
4862 
4863     do
4864     {
4865         if ( bUp )
4866         {
4867             if ( n )
4868                 n--;
4869             else
4870                 if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) )
4871                     n = pMenu->GetItemCount()-1;
4872                 else
4873                     break;
4874         }
4875         else
4876         {
4877             n++;
4878             if ( n >= pMenu->GetItemCount() )
4879             {
4880                 if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) )
4881                     n = 0;
4882                 else
4883                     break;
4884             }
4885         }
4886 
4887         MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n );
4888         if ( ( pData->bEnabled || !rSettings.GetSkipDisabledInMenus() )
4889 			  && ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) && pMenu->ImplIsSelectable( n ) )
4890         {
4891             // Selektion noch im sichtbaren Bereich?
4892             if ( IsScrollMenu() )
4893             {
4894                 ChangeHighlightItem( ITEMPOS_INVALID, sal_False );
4895 
4896                 while ( n < nFirstEntry )
4897                     ImplScroll( sal_True );
4898 
4899                 Size aOutSz = GetOutputSizePixel();
4900 				sal_uInt16 nLastVisible;
4901 				((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible );
4902                 while ( n > nLastVisible )
4903 				{
4904                     ImplScroll( sal_False );
4905 					((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible );
4906 				}
4907             }
4908             ChangeHighlightItem( n, sal_False );
4909             break;
4910         }
4911     } while ( n != nLoop );
4912 }
4913 
4914 void MenuFloatingWindow::KeyInput( const KeyEvent& rKEvent )
4915 {
4916     ImplDelData aDelData;
4917     ImplAddDel( &aDelData );
4918 
4919     sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode();
4920     bKeyInput = sal_True;
4921     switch ( nCode )
4922     {
4923         case KEY_UP:
4924         case KEY_DOWN:
4925         {
4926             ImplCursorUpDown( nCode == KEY_UP );
4927         }
4928         break;
4929         case KEY_END:
4930         case KEY_HOME:
4931 		{
4932             ImplCursorUpDown( nCode == KEY_END, sal_True );
4933 		}
4934 		break;
4935         case KEY_F6:
4936         case KEY_ESCAPE:
4937 		{
4938             // Ctrl-F6 acts like ESC here, the menu bar however will then put the focus in the document
4939             if( nCode == KEY_F6 && !rKEvent.GetKeyCode().IsMod1() )
4940                 break;
4941             if( pMenu )
4942             {
4943                 if ( !pMenu->pStartedFrom )
4944                 {
4945                     StopExecute();
4946                     KillActivePopup();
4947                 }
4948                 else if ( pMenu->pStartedFrom->bIsMenuBar )
4949                 {
4950                     // Forward...
4951                     ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent );
4952                 }
4953                 else
4954                 {
4955                     StopExecute();
4956                     PopupMenu* pPopupMenu = (PopupMenu*)pMenu->pStartedFrom;
4957                     MenuFloatingWindow* pFloat = pPopupMenu->ImplGetFloatingWindow();
4958                     pFloat->GrabFocus();
4959                     pFloat->KillActivePopup();
4960                     pPopupMenu->ImplCallHighlight(pFloat->nHighlightedItem);
4961                 }
4962             }
4963 		}
4964 		break;
4965         case KEY_LEFT:
4966         {
4967             if ( pMenu && pMenu->pStartedFrom )
4968             {
4969                 StopExecute();
4970                 if ( pMenu->pStartedFrom->bIsMenuBar )
4971                 {
4972                     // Forward...
4973                     ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent );
4974                 }
4975                 else
4976                 {
4977                     MenuFloatingWindow* pFloat = ((PopupMenu*)pMenu->pStartedFrom)->ImplGetFloatingWindow();
4978                     pFloat->GrabFocus();
4979                     pFloat->KillActivePopup();
4980                 }
4981             }
4982         }
4983         break;
4984         case KEY_RIGHT:
4985         {
4986             if( pMenu )
4987             {
4988                 sal_Bool bDone = sal_False;
4989                 if ( nHighlightedItem != ITEMPOS_INVALID )
4990                 {
4991                     MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
4992                     if ( pData && pData->pSubMenu )
4993                     {
4994                         HighlightChanged( 0 );
4995                         bDone = sal_True;
4996                     }
4997                 }
4998                 if ( !bDone )
4999                 {
5000                     Menu* pStart = pMenu->ImplGetStartMenu();
5001                     if ( pStart && pStart->bIsMenuBar )
5002                     {
5003                         // Forward...
5004                         pStart->ImplGetWindow()->KeyInput( rKEvent );
5005                     }
5006                 }
5007             }
5008         }
5009         break;
5010         case KEY_RETURN:
5011         {
5012             if( pMenu )
5013             {
5014                 MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
5015                 if ( pData && pData->bEnabled )
5016                 {
5017                     if ( pData->pSubMenu )
5018                         HighlightChanged( 0 );
5019                     else
5020                         EndExecute();
5021                 }
5022                 else
5023                     StopExecute();
5024             }
5025         }
5026         break;
5027         case KEY_MENU:
5028         {
5029             if( pMenu )
5030             {
5031                 Menu* pStart = pMenu->ImplGetStartMenu();
5032                 if ( pStart && pStart->bIsMenuBar )
5033                 {
5034                     // Forward...
5035                     pStart->ImplGetWindow()->KeyInput( rKEvent );
5036                 }
5037             }
5038         }
5039         break;
5040         default:
5041         {
5042             xub_Unicode nCharCode = rKEvent.GetCharCode();
5043             sal_uInt16 nPos = 0;
5044 			sal_uInt16 nDuplicates = 0;
5045             MenuItemData* pData = (nCharCode && pMenu) ? pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nPos, nDuplicates, nHighlightedItem ) : NULL;
5046             if ( pData )
5047             {
5048                 if ( pData->pSubMenu || nDuplicates > 1 )
5049                 {
5050                     ChangeHighlightItem( nPos, sal_False );
5051                     HighlightChanged( 0 );
5052                 }
5053                 else
5054                 {
5055                     nHighlightedItem = nPos;
5056                     EndExecute();
5057                 }
5058             }
5059             else
5060             {
5061                 // Bei ungueltigen Tasten Beepen, aber nicht bei HELP und F-Tasten
5062                 if ( !rKEvent.GetKeyCode().IsMod2() && ( nCode != KEY_HELP ) && ( rKEvent.GetKeyCode().GetGroup() != KEYGROUP_FKEYS ) )
5063                     Sound::Beep();
5064                 FloatingWindow::KeyInput( rKEvent );
5065             }
5066         }
5067     }
5068     // #105474# check if menu window was not destroyed
5069     if ( !aDelData.IsDelete() )
5070     {
5071         ImplRemoveDel( &aDelData );
5072         bKeyInput = sal_False;
5073     }
5074 }
5075 
5076 void MenuFloatingWindow::Paint( const Rectangle& )
5077 {
5078     if( ! pMenu )
5079         return;
5080 
5081     if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
5082     {
5083         SetClipRegion();
5084         long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0;
5085         Size aPxSize( GetOutputSizePixel() );
5086         aPxSize.Width() -= nX;
5087         ImplControlValue aVal( pMenu->nTextPos-GUTTERBORDER );
5088         DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
5089                            Rectangle( Point( nX, 0 ), aPxSize ),
5090                            CTRL_STATE_ENABLED,
5091                            aVal,
5092                            OUString() );
5093         ImplInitClipRegion();
5094     }
5095     if ( IsScrollMenu() )
5096     {
5097         ImplDrawScroller( sal_True );
5098         ImplDrawScroller( sal_False );
5099     }
5100     SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
5101     pMenu->ImplPaint( this, nScrollerHeight, ImplGetStartY() );
5102     if ( nHighlightedItem != ITEMPOS_INVALID )
5103         HighlightItem( nHighlightedItem, sal_True );
5104 }
5105 
5106 void MenuFloatingWindow::ImplDrawScroller( sal_Bool bUp )
5107 {
5108     if( ! pMenu )
5109         return;
5110 
5111     SetClipRegion();
5112 
5113     Size aOutSz = GetOutputSizePixel();
5114     long nY = bUp ? 0 : ( aOutSz.Height() - nScrollerHeight );
5115     long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0;
5116     Rectangle aRect( Point( nX, nY ), Size( aOutSz.Width()-nX, nScrollerHeight ) );
5117 
5118     DecorationView aDecoView( this );
5119     SymbolType eSymbol = bUp ? SYMBOL_SPIN_UP : SYMBOL_SPIN_DOWN;
5120 
5121     sal_uInt16 nStyle = 0;
5122     if ( ( bUp && !bScrollUp ) || ( !bUp && !bScrollDown ) )
5123         nStyle |= SYMBOL_DRAW_DISABLE;
5124 
5125     aDecoView.DrawSymbol( aRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
5126 
5127     ImplInitClipRegion();
5128 }
5129 
5130 void MenuFloatingWindow::RequestHelp( const HelpEvent& rHEvt )
5131 {
5132     sal_uInt16 nId = nHighlightedItem;
5133     Menu* pM = pMenu;
5134     Window* pW = this;
5135 
5136     // #102618# Get item rect before destroying the window in EndExecute() call
5137 	Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) );
5138 
5139     if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
5140     {
5141         nHighlightedItem = ITEMPOS_INVALID;
5142         EndExecute();
5143         pW = NULL;
5144     }
5145 
5146     if( !ImplHandleHelpEvent( pW, pM, nId, rHEvt, aHighlightRect ) )
5147         Window::RequestHelp( rHEvt );
5148 }
5149 
5150 void MenuFloatingWindow::StateChanged( StateChangedType nType )
5151 {
5152     FloatingWindow::StateChanged( nType );
5153 
5154     if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
5155     {
5156         ImplInitMenuWindow( this, sal_False, sal_False );
5157         Invalidate();
5158     }
5159 }
5160 
5161 void MenuFloatingWindow::DataChanged( const DataChangedEvent& rDCEvt )
5162 {
5163     FloatingWindow::DataChanged( rDCEvt );
5164 
5165     if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
5166          (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
5167          ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
5168           (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
5169     {
5170         ImplInitMenuWindow( this, sal_False, sal_False );
5171         Invalidate();
5172     }
5173 }
5174 
5175 void MenuFloatingWindow::Command( const CommandEvent& rCEvt )
5176 {
5177     if ( rCEvt.GetCommand() == COMMAND_WHEEL )
5178     {
5179         const CommandWheelData* pData = rCEvt.GetWheelData();
5180         if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
5181         {
5182 //          ImplCursorUpDown( pData->GetDelta() > 0L );
5183             ImplScroll( pData->GetDelta() > 0L );
5184             MouseMove( MouseEvent( GetPointerPosPixel(), 0 ) );
5185         }
5186     }
5187 }
5188 
5189 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuFloatingWindow::CreateAccessible()
5190 {
5191 	::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc;
5192 
5193 	if ( pMenu && !pMenu->pStartedFrom )
5194 		xAcc = pMenu->GetAccessible();
5195 
5196 	return xAcc;
5197 }
5198 
5199 MenuBarWindow::MenuBarWindow( Window* pParent ) :
5200     Window( pParent, 0 ),
5201     aCloser( this ),
5202     aFloatBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE ),
5203     aHideBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE )
5204 {
5205     SetType( WINDOW_MENUBARWINDOW );
5206     pMenu = NULL;
5207     pActivePopup = NULL;
5208     nSaveFocusId = 0;
5209     nHighlightedItem = ITEMPOS_INVALID;
5210     mbAutoPopup = sal_True;
5211     nSaveFocusId = 0;
5212 	bIgnoreFirstMove = sal_True;
5213 	bStayActive = sal_False;
5214 
5215     ResMgr* pResMgr = ImplGetResMgr();
5216 
5217     if( pResMgr )
5218     {
5219         BitmapEx aBitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) );
5220         BitmapEx aBitmapHC( ResId( SV_RESID_BITMAP_CLOSEDOCHC, *pResMgr ) );
5221 
5222         aCloser.maImage = Image( aBitmap );
5223         aCloser.maImageHC = Image( aBitmapHC );
5224 
5225         aCloser.SetOutStyle( TOOLBOX_STYLE_FLAT );
5226         aCloser.SetBackground();
5227         aCloser.SetPaintTransparent( sal_True );
5228         aCloser.SetParentClipMode( PARENTCLIPMODE_NOCLIP );
5229 
5230         aCloser.InsertItem( IID_DOCUMENTCLOSE,
5231         GetSettings().GetStyleSettings().GetHighContrastMode() ? aCloser.maImageHC : aCloser.maImage, 0 );
5232         aCloser.SetSelectHdl( LINK( this, MenuBarWindow, CloserHdl ) );
5233         aCloser.AddEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) );
5234         aCloser.SetQuickHelpText( IID_DOCUMENTCLOSE, XubString( ResId( SV_HELPTEXT_CLOSEDOCUMENT, *pResMgr ) ) );
5235 
5236         aFloatBtn.SetClickHdl( LINK( this, MenuBarWindow, FloatHdl ) );
5237         aFloatBtn.SetSymbol( SYMBOL_FLOAT );
5238         aFloatBtn.SetQuickHelpText( XubString( ResId( SV_HELPTEXT_RESTORE, *pResMgr ) ) );
5239 
5240         aHideBtn.SetClickHdl( LINK( this, MenuBarWindow, HideHdl ) );
5241         aHideBtn.SetSymbol( SYMBOL_HIDE );
5242         aHideBtn.SetQuickHelpText( XubString( ResId( SV_HELPTEXT_MINIMIZE, *pResMgr ) ) );
5243     }
5244 
5245     ImplInitStyleSettings();
5246 
5247     AddEventListener( LINK( this, MenuBarWindow, ShowHideListener ) );
5248 }
5249 
5250 MenuBarWindow::~MenuBarWindow()
5251 {
5252     aCloser.RemoveEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) );
5253     RemoveEventListener( LINK( this, MenuBarWindow, ShowHideListener ) );
5254 }
5255 
5256 void MenuBarWindow::SetMenu( MenuBar* pMen )
5257 {
5258     pMenu = pMen;
5259     KillActivePopup();
5260     nHighlightedItem = ITEMPOS_INVALID;
5261     ImplInitMenuWindow( this, sal_True, sal_True );
5262     if ( pMen )
5263     {
5264         aCloser.ShowItem( IID_DOCUMENTCLOSE, pMen->HasCloser() );
5265         aCloser.Show( pMen->HasCloser() || !m_aAddButtons.empty() );
5266         aFloatBtn.Show( pMen->HasFloatButton() );
5267         aHideBtn.Show( pMen->HasHideButton() );
5268     }
5269     Invalidate();
5270 
5271     // show and connect native menubar
5272     if( pMenu && pMenu->ImplGetSalMenu() )
5273     {
5274         if( pMenu->ImplGetSalMenu()->VisibleMenuBar() )
5275             ImplGetFrame()->SetMenu( pMenu->ImplGetSalMenu() );
5276 
5277         pMenu->ImplGetSalMenu()->SetFrame( ImplGetFrame() );
5278     }
5279 }
5280 
5281 void MenuBarWindow::ShowButtons( sal_Bool bClose, sal_Bool bFloat, sal_Bool bHide )
5282 {
5283     aCloser.ShowItem( IID_DOCUMENTCLOSE, bClose );
5284     aCloser.Show( bClose || ! m_aAddButtons.empty() );
5285     aFloatBtn.Show( bFloat );
5286     aHideBtn.Show( bHide );
5287     Resize();
5288 }
5289 
5290 Size MenuBarWindow::MinCloseButtonSize()
5291 {
5292     return aCloser.getMinSize();
5293 }
5294 
5295 IMPL_LINK( MenuBarWindow, CloserHdl, PushButton*, EMPTYARG )
5296 {
5297     if( ! pMenu )
5298         return 0;
5299 
5300     if( aCloser.GetCurItemId() == IID_DOCUMENTCLOSE )
5301     {
5302         // #i106052# call close hdl asynchronously to ease handler implementation
5303         // this avoids still being in the handler while the DecoToolBox already
5304         // gets destroyed
5305         Application::PostUserEvent( ((MenuBar*)pMenu)->GetCloserHdl(), pMenu );
5306     }
5307     else
5308     {
5309         std::map<sal_uInt16,AddButtonEntry>::iterator it = m_aAddButtons.find( aCloser.GetCurItemId() );
5310         if( it != m_aAddButtons.end() )
5311         {
5312             MenuBar::MenuBarButtonCallbackArg aArg;
5313             aArg.nId = it->first;
5314             aArg.bHighlight = (aCloser.GetHighlightItemId() == it->first);
5315             aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
5316             return it->second.m_aSelectLink.Call( &aArg );
5317         }
5318     }
5319     return 0;
5320 }
5321 
5322 IMPL_LINK( MenuBarWindow, ToolboxEventHdl, VclWindowEvent*, pEvent )
5323 {
5324     if( ! pMenu )
5325         return 0;
5326 
5327     MenuBar::MenuBarButtonCallbackArg aArg;
5328     aArg.nId = 0xffff;
5329     aArg.bHighlight = (pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT);
5330     aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
5331     if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT )
5332         aArg.nId = aCloser.GetHighlightItemId();
5333     else if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHTOFF )
5334     {
5335         sal_uInt16 nPos = static_cast< sal_uInt16 >(reinterpret_cast<sal_IntPtr>(pEvent->GetData()));
5336         aArg.nId = aCloser.GetItemId( nPos );
5337     }
5338     std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( aArg.nId );
5339     if( it != m_aAddButtons.end() )
5340     {
5341         it->second.m_aHighlightLink.Call( &aArg );
5342     }
5343     return 0;
5344 }
5345 
5346 IMPL_LINK( MenuBarWindow, ShowHideListener, VclWindowEvent*, pEvent )
5347 {
5348     if( ! pMenu )
5349         return 0;
5350 
5351     if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW )
5352         pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID );
5353     else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
5354         pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID );
5355     return 0;
5356 }
5357 
5358 IMPL_LINK( MenuBarWindow, FloatHdl, PushButton*, EMPTYARG )
5359 {
5360     return pMenu ? ((MenuBar*)pMenu)->GetFloatButtonClickHdl().Call( pMenu ) : 0;
5361 }
5362 
5363 IMPL_LINK( MenuBarWindow, HideHdl, PushButton*, EMPTYARG )
5364 {
5365     return pMenu ? ((MenuBar*)pMenu)->GetHideButtonClickHdl().Call( pMenu ) : 0;
5366 }
5367 
5368 void MenuBarWindow::ImplCreatePopup( sal_Bool bPreSelectFirst )
5369 {
5370     MenuItemData* pItemData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL;
5371     if ( pItemData )
5372     {
5373 		bIgnoreFirstMove = sal_True;
5374         if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) )
5375         {
5376             KillActivePopup();
5377         }
5378         if ( pItemData->bEnabled && pItemData->pSubMenu && ( nHighlightedItem != ITEMPOS_INVALID ) && ( pItemData->pSubMenu != pActivePopup ) )
5379         {
5380             pActivePopup = (PopupMenu*)pItemData->pSubMenu;
5381             long nX = 0;
5382             MenuItemData* pData = 0;
5383             for ( sal_uLong n = 0; n < nHighlightedItem; n++ )
5384             {
5385                 pData = pMenu->GetItemList()->GetDataFromPos( n );
5386                 nX += pData->aSz.Width();
5387             }
5388             pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
5389 //          Point MyPos = GetPosPixel();
5390 //          Point aItemTopLeft( MyPos.X()+nX, MyPos.Y() );
5391             Point aItemTopLeft( nX, 0 );
5392             Point aItemBottomRight( aItemTopLeft );
5393             aItemBottomRight.X() += pData->aSz.Width();
5394 
5395             // Im Vollbild-Modus hat die MenuBar ggf. die Hoehe 0:
5396             // Nicht immer einfach die Window-Hoehe nehmen, weil ItemHeight < WindowHeight.
5397             if ( GetSizePixel().Height() )
5398             {
5399                 // #107747# give menuitems the height of the menubar
5400                 aItemBottomRight.Y() += GetOutputSizePixel().Height()-1;
5401             }
5402 
5403             // ImplExecute ist doch nicht modal...
5404             // #99071# do not grab the focus, otherwise it will be restored to the menubar
5405             // when the frame is reactivated later
5406             //GrabFocus();
5407             pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_DOWN, pMenu, bPreSelectFirst );
5408             if ( pActivePopup )
5409             {
5410                 // Hat kein Window, wenn vorher abgebrochen oder keine Eintraege
5411                 if ( pActivePopup->ImplGetFloatingWindow() )
5412                     pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this );
5413                 else
5414                     pActivePopup = NULL;
5415             }
5416         }
5417     }
5418 }
5419 
5420 
5421 void MenuBarWindow::KillActivePopup()
5422 {
5423     if ( pActivePopup )
5424     {
5425         if( pActivePopup->pWindow != NULL )
5426             if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() )
5427                 return; // kill it later
5428 
5429         if ( pActivePopup->bInCallback )
5430             pActivePopup->bCanceled = sal_True;
5431 
5432         pActivePopup->bInCallback = sal_True;
5433         pActivePopup->Deactivate();
5434         pActivePopup->bInCallback = sal_False;
5435         // Abfrage auf pActivePopup, falls im Deactivate abgeschossen...
5436         if ( pActivePopup && pActivePopup->ImplGetWindow() )
5437         {
5438             pActivePopup->ImplGetFloatingWindow()->StopExecute();
5439             pActivePopup->ImplGetFloatingWindow()->doShutdown();
5440             pActivePopup->pWindow->doLazyDelete();
5441             pActivePopup->pWindow = NULL;
5442         }
5443         pActivePopup = 0;
5444     }
5445 }
5446 
5447 void MenuBarWindow::PopupClosed( Menu* pPopup )
5448 {
5449     if ( pPopup == pActivePopup )
5450     {
5451         KillActivePopup();
5452         ChangeHighlightItem( ITEMPOS_INVALID, sal_False, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus, sal_False );
5453     }
5454 }
5455 
5456 void MenuBarWindow::MouseButtonDown( const MouseEvent& rMEvt )
5457 {
5458     mbAutoPopup = sal_True;
5459     sal_uInt16 nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
5460     if ( ( nEntry != ITEMPOS_INVALID ) && ( nEntry != nHighlightedItem ) )
5461     {
5462         ChangeHighlightItem( nEntry, sal_False );
5463     }
5464     else
5465     {
5466         KillActivePopup();
5467         ChangeHighlightItem( ITEMPOS_INVALID, sal_False );
5468     }
5469 }
5470 
5471 void MenuBarWindow::MouseButtonUp( const MouseEvent& )
5472 {
5473 }
5474 
5475 void MenuBarWindow::MouseMove( const MouseEvent& rMEvt )
5476 {
5477     // Im Move nur Highlighten, wenn schon eins gehighlightet.
5478     if ( rMEvt.IsSynthetic() || rMEvt.IsLeaveWindow() || rMEvt.IsEnterWindow() || ( nHighlightedItem == ITEMPOS_INVALID ) )
5479         return;
5480 
5481 	if( bIgnoreFirstMove )
5482 	{
5483 		bIgnoreFirstMove = sal_False;
5484 		return;
5485 	}
5486 
5487     sal_uInt16 nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
5488     if ( ( nEntry != ITEMPOS_INVALID )
5489 #ifdef OS2
5490        && ( ImplHilite(rMEvt) )
5491 #endif
5492 	   && ( nEntry != nHighlightedItem ) )
5493         ChangeHighlightItem( nEntry, sal_False );
5494 }
5495 
5496 void MenuBarWindow::ChangeHighlightItem( sal_uInt16 n, sal_Bool bSelectEntry, sal_Bool bAllowRestoreFocus, sal_Bool bDefaultToDocument)
5497 {
5498     if( ! pMenu )
5499         return;
5500 
5501     // #57934# ggf. das aktive Popup sofort schliessen, damit TH's Hintergrundsicherung funktioniert.
5502     MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n );
5503     if ( pActivePopup && pActivePopup->ImplGetWindow() && ( !pNextData || ( pActivePopup != pNextData->pSubMenu ) ) )
5504         KillActivePopup(); // pActivePopup ggf. ohne pWin, wenn in Activate() Rescheduled wurde
5505 
5506     // Activate am MenuBar immer nur einmal pro Vorgang...
5507     sal_Bool bJustActivated = sal_False;
5508     if ( ( nHighlightedItem == ITEMPOS_INVALID ) && ( n != ITEMPOS_INVALID ) )
5509     {
5510         ImplGetSVData()->maWinData.mbNoDeactivate = sal_True;
5511         if( !bStayActive )
5512 		{
5513             // #105406# avoid saving the focus when we already have the focus
5514             sal_Bool bNoSaveFocus = (this == ImplGetSVData()->maWinData.mpFocusWin );
5515 
5516 			if( nSaveFocusId )
5517 			{
5518 				if( !ImplGetSVData()->maWinData.mbNoSaveFocus )
5519 				{
5520 					// we didn't clean up last time
5521 					Window::EndSaveFocus( nSaveFocusId, sal_False );	// clean up
5522                     nSaveFocusId = 0;
5523                     if( !bNoSaveFocus )
5524 					    nSaveFocusId = Window::SaveFocus();	// only save focus when initially activated
5525 				}
5526 				else {
5527 					; // do nothing: we 're activated again from taskpanelist, focus was already saved
5528                 }
5529 			}
5530 			else
5531 			{
5532                 if( !bNoSaveFocus )
5533 				    nSaveFocusId = Window::SaveFocus();	// only save focus when initially activated
5534 			}
5535 		}
5536 		else
5537 			bStayActive = sal_False;
5538         pMenu->bInCallback = sal_True;  // hier schon setzen, falls Activate ueberladen
5539         pMenu->Activate();
5540         pMenu->bInCallback = sal_False;
5541         bJustActivated = sal_True;
5542     }
5543     else if ( ( nHighlightedItem != ITEMPOS_INVALID ) && ( n == ITEMPOS_INVALID ) )
5544     {
5545         pMenu->bInCallback = sal_True;
5546         pMenu->Deactivate();
5547         pMenu->bInCallback = sal_False;
5548         ImplGetSVData()->maWinData.mbNoDeactivate = sal_False;
5549 		if( !ImplGetSVData()->maWinData.mbNoSaveFocus )
5550 		{
5551 			sal_uLong nTempFocusId = nSaveFocusId;
5552 			nSaveFocusId = 0;
5553 			Window::EndSaveFocus( nTempFocusId, bAllowRestoreFocus );
5554             // #105406# restore focus to document if we could not save focus before
5555             if( bDefaultToDocument && !nTempFocusId && bAllowRestoreFocus )
5556                 GrabFocusToDocument();
5557 		}
5558     }
5559 
5560     if ( nHighlightedItem != ITEMPOS_INVALID )
5561     {
5562         HighlightItem( nHighlightedItem, sal_False );
5563         pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
5564     }
5565 
5566     nHighlightedItem = (sal_uInt16)n;
5567     DBG_ASSERT( ( nHighlightedItem == ITEMPOS_INVALID ) || pMenu->ImplIsVisible( nHighlightedItem ), "ChangeHighlightItem: Not visible!" );
5568     HighlightItem( nHighlightedItem, sal_True );
5569     pMenu->ImplCallHighlight( nHighlightedItem );
5570 
5571     if( mbAutoPopup )
5572         ImplCreatePopup( bSelectEntry );
5573 
5574     // #58935# #73659# Focus, wenn kein Popup drunter haengt...
5575     if ( bJustActivated && !pActivePopup )
5576         GrabFocus();
5577 }
5578 
5579 void MenuBarWindow::HighlightItem( sal_uInt16 nPos, sal_Bool bHighlight )
5580 {
5581     if( ! pMenu )
5582         return;
5583 
5584     long nX = 0;
5585     sal_uLong nCount = pMenu->pItemList->Count();
5586     for ( sal_uLong n = 0; n < nCount; n++ )
5587     {
5588         MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
5589         if ( n == nPos )
5590         {
5591             if ( pData->eType != MENUITEM_SEPARATOR )
5592             {
5593                 // #107747# give menuitems the height of the menubar
5594                 Rectangle aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) );
5595                 Push( PUSH_CLIPREGION );
5596                 IntersectClipRegion( aRect );
5597                 if ( bHighlight )
5598                 {
5599                     if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) &&
5600                         IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
5601                     {
5602                         // draw background (transparency)
5603                         MenubarValue aControlValue;
5604                         aControlValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
5605 
5606                         Point tmp(0,0);
5607                         Rectangle aBgRegion( tmp, GetOutputSizePixel() );
5608                         DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL,
5609                                            aBgRegion,
5610                                            CTRL_STATE_ENABLED,
5611                                            aControlValue,
5612                                            OUString() );
5613                         ImplAddNWFSeparator( this, aControlValue );
5614 
5615                         // draw selected item
5616                         DrawNativeControl( CTRL_MENUBAR, PART_MENU_ITEM,
5617                                            aRect,
5618                                            CTRL_STATE_ENABLED | CTRL_STATE_SELECTED,
5619                                            aControlValue,
5620                                            OUString() );
5621                     }
5622                     else
5623                     {
5624                         SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
5625                         SetLineColor();
5626                         DrawRect( aRect );
5627                     }
5628                 }
5629                 else
5630                 {
5631                     if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) )
5632                     {
5633                         MenubarValue aMenubarValue;
5634                         aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
5635 
5636                         // use full window size to get proper gradient
5637                         // but clip accordingly
5638                         Point aPt;
5639                         Rectangle aCtrlRect( aPt, GetOutputSizePixel() );
5640 
5641                         DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED, aMenubarValue, rtl::OUString() );
5642                         ImplAddNWFSeparator( this, aMenubarValue );
5643                     }
5644                     else
5645                         Erase( aRect );
5646                 }
5647                 Pop();
5648                 pMenu->ImplPaint( this, 0, 0, pData, bHighlight );
5649             }
5650             return;
5651         }
5652 
5653         nX += pData->aSz.Width();
5654     }
5655 }
5656 
5657 Rectangle MenuBarWindow::ImplGetItemRect( sal_uInt16 nPos )
5658 {
5659 	Rectangle aRect;
5660     if( pMenu )
5661     {
5662         long nX = 0;
5663         sal_uLong nCount = pMenu->pItemList->Count();
5664         for ( sal_uLong n = 0; n < nCount; n++ )
5665         {
5666             MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
5667             if ( n == nPos )
5668             {
5669                 if ( pData->eType != MENUITEM_SEPARATOR )
5670                     // #107747# give menuitems the height of the menubar
5671                     aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) );
5672                 break;
5673             }
5674 
5675             nX += pData->aSz.Width();
5676         }
5677     }
5678 	return aRect;
5679 }
5680 
5681 void MenuBarWindow::KeyInput( const KeyEvent& rKEvent )
5682 {
5683     if ( !ImplHandleKeyEvent( rKEvent ) )
5684         Window::KeyInput( rKEvent );
5685 }
5686 
5687 sal_Bool MenuBarWindow::ImplHandleKeyEvent( const KeyEvent& rKEvent, sal_Bool bFromMenu )
5688 {
5689     if( ! pMenu )
5690         return sal_False;
5691 
5692     if ( pMenu->bInCallback )
5693         return sal_True;    // schlucken
5694 
5695     sal_Bool bDone = sal_False;
5696     sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode();
5697 
5698 	if( GetParent() )
5699 	{
5700 		if( GetParent()->GetWindow( WINDOW_CLIENT )->IsSystemWindow() )
5701         {
5702 		    SystemWindow *pSysWin = (SystemWindow*)GetParent()->GetWindow( WINDOW_CLIENT );
5703 		    if( pSysWin->GetTaskPaneList() )
5704 			    if( pSysWin->GetTaskPaneList()->HandleKeyEvent( rKEvent ) )
5705 				    return sal_True;
5706         }
5707 	}
5708 
5709     if ( nCode == KEY_MENU && !rKEvent.GetKeyCode().IsShift() ) // only F10, not Shift-F10
5710     {
5711         mbAutoPopup = ImplGetSVData()->maNWFData.mbOpenMenuOnF10;
5712         if ( nHighlightedItem == ITEMPOS_INVALID )
5713         {
5714             ChangeHighlightItem( 0, sal_False );
5715             GrabFocus();
5716         }
5717         else
5718         {
5719             ChangeHighlightItem( ITEMPOS_INVALID, sal_False );
5720             nSaveFocusId = 0;
5721         }
5722         bDone = sal_True;
5723     }
5724     else if ( bFromMenu )
5725     {
5726         if ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ||
5727 			( nCode == KEY_HOME ) || ( nCode == KEY_END ) )
5728         {
5729             sal_uInt16 n = nHighlightedItem;
5730             if ( n == ITEMPOS_INVALID )
5731             {
5732                 if ( nCode == KEY_LEFT)
5733                     n = 0;
5734                 else
5735                     n = pMenu->GetItemCount()-1;
5736             }
5737 
5738             // handling gtk like (aka mbOpenMenuOnF10)
5739             // do not highlight an item when opening a sub menu
5740             // unless there already was a higlighted sub menu item
5741             bool bWasHighlight = false;
5742             if( pActivePopup )
5743             {
5744                 MenuFloatingWindow* pSubWindow = dynamic_cast<MenuFloatingWindow*>(pActivePopup->ImplGetWindow());
5745                 if( pSubWindow )
5746                     bWasHighlight = (pSubWindow->GetHighlightedItem() != ITEMPOS_INVALID);
5747             }
5748 
5749             sal_uInt16 nLoop = n;
5750 
5751 			if( nCode == KEY_HOME )
5752 				{ n = (sal_uInt16)-1; nLoop = n+1; }
5753 			if( nCode == KEY_END )
5754 				{ n = pMenu->GetItemCount(); nLoop = n-1; }
5755 
5756             do
5757             {
5758                 if ( nCode == KEY_LEFT || nCode == KEY_END )
5759                 {
5760                     if ( n )
5761                         n--;
5762                     else
5763                         n = pMenu->GetItemCount()-1;
5764                 }
5765                 if ( nCode == KEY_RIGHT || nCode == KEY_HOME )
5766                 {
5767                     n++;
5768                     if ( n >= pMenu->GetItemCount() )
5769                         n = 0;
5770                 }
5771 
5772                 MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n );
5773                 if ( ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) )
5774                 {
5775                     sal_Bool bDoSelect = sal_True;
5776                     if( ImplGetSVData()->maNWFData.mbOpenMenuOnF10 )
5777                         bDoSelect = bWasHighlight;
5778                     ChangeHighlightItem( n, bDoSelect );
5779                     break;
5780                 }
5781             } while ( n != nLoop );
5782             bDone = sal_True;
5783         }
5784         else if ( nCode == KEY_RETURN )
5785         {
5786             if( pActivePopup ) KillActivePopup();
5787 			else
5788 				if ( !mbAutoPopup )
5789 				{
5790 					ImplCreatePopup( sal_True );
5791 					mbAutoPopup = sal_True;
5792 				}
5793             bDone = sal_True;
5794         }
5795         else if ( ( nCode == KEY_UP ) || ( nCode == KEY_DOWN ) )
5796         {
5797             if ( !mbAutoPopup )
5798             {
5799                 ImplCreatePopup( sal_True );
5800                 mbAutoPopup = sal_True;
5801             }
5802             bDone = sal_True;
5803         }
5804         else if ( nCode == KEY_ESCAPE || ( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() ) )
5805         {
5806 			if( pActivePopup )
5807 			{
5808 				// bring focus to menu bar without any open popup
5809 				mbAutoPopup = sal_False;
5810 				sal_uInt16 n = nHighlightedItem;
5811 				nHighlightedItem = ITEMPOS_INVALID;
5812 				bStayActive = sal_True;
5813 				ChangeHighlightItem( n, sal_False );
5814 				bStayActive = sal_False;
5815 				KillActivePopup();
5816 				GrabFocus();
5817 			}
5818 			else
5819 				ChangeHighlightItem( ITEMPOS_INVALID, sal_False );
5820 
5821             if( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() )
5822             {
5823                 // put focus into document
5824                 GrabFocusToDocument();
5825             }
5826 
5827             bDone = sal_True;
5828         }
5829     }
5830 
5831     if ( !bDone && ( bFromMenu || rKEvent.GetKeyCode().IsMod2() ) )
5832     {
5833         xub_Unicode nCharCode = rKEvent.GetCharCode();
5834         if ( nCharCode )
5835         {
5836             sal_uInt16 nEntry, nDuplicates;
5837             MenuItemData* pData = pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nEntry, nDuplicates, nHighlightedItem );
5838             if ( pData && (nEntry != ITEMPOS_INVALID) )
5839             {
5840                 mbAutoPopup = sal_True;
5841                 ChangeHighlightItem( nEntry, sal_True );
5842                 bDone = sal_True;
5843             }
5844             else
5845             {
5846                 // Wegen Systemmenu und anderen System-HotKeys, nur
5847                 // eigenstaendige Character-Kombinationen auswerten
5848                 sal_uInt16 nKeyCode = rKEvent.GetKeyCode().GetCode();
5849                 if ( ((nKeyCode >= KEY_A) && (nKeyCode <= KEY_Z)) )
5850                     Sound::Beep();
5851             }
5852         }
5853     }
5854     return bDone;
5855 }
5856 
5857 void MenuBarWindow::Paint( const Rectangle& )
5858 {
5859     if( ! pMenu )
5860         return;
5861 
5862     // no VCL paint if native menus
5863     if( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() )
5864     {
5865         ImplGetFrame()->DrawMenuBar();
5866         return;
5867     }
5868 
5869     if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) )
5870     {
5871         Point aPt;
5872         Rectangle aCtrlRegion( aPt, GetOutputSizePixel() );
5873 
5874         MenubarValue aMenubarValue;
5875         aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
5876 
5877         DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRegion, CTRL_STATE_ENABLED, aMenubarValue, rtl::OUString() );
5878         ImplAddNWFSeparator( this, aMenubarValue );
5879     }
5880     SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
5881     pMenu->ImplPaint( this, 0 );
5882     if ( nHighlightedItem != ITEMPOS_INVALID )
5883         HighlightItem( nHighlightedItem, sal_True );
5884 
5885 	// in high contrast mode draw a separating line on the lower edge
5886 	if( ! IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) &&
5887 		GetSettings().GetStyleSettings().GetHighContrastMode() )
5888     {
5889 		Push( PUSH_LINECOLOR | PUSH_MAPMODE );
5890 		SetLineColor( Color( COL_WHITE ) );
5891 		SetMapMode( MapMode( MAP_PIXEL ) );
5892 		Size aSize = GetSizePixel();
5893 		DrawLine( Point( 0, aSize.Height()-1 ), Point( aSize.Width()-1, aSize.Height()-1 ) );
5894 		Pop();
5895     }
5896 
5897 }
5898 
5899 void MenuBarWindow::Resize()
5900 {
5901     Size aOutSz = GetOutputSizePixel();
5902     long n      = aOutSz.Height()-4;
5903     long nX     = aOutSz.Width()-3;
5904     long nY     = 2;
5905 
5906     if ( aCloser.IsVisible() )
5907     {
5908         aCloser.Hide();
5909         aCloser.SetImages( n );
5910         Size aTbxSize( aCloser.CalcWindowSizePixel() );
5911         nX -= aTbxSize.Width();
5912         long nTbxY = (aOutSz.Height() - aTbxSize.Height())/2;
5913         aCloser.SetPosSizePixel( nX, nTbxY, aTbxSize.Width(), aTbxSize.Height() );
5914         nX -= 3;
5915         aCloser.Show();
5916     }
5917     if ( aFloatBtn.IsVisible() )
5918     {
5919         nX -= n;
5920         aFloatBtn.SetPosSizePixel( nX, nY, n, n );
5921     }
5922     if ( aHideBtn.IsVisible() )
5923     {
5924         nX -= n;
5925         aHideBtn.SetPosSizePixel( nX, nY, n, n );
5926     }
5927 
5928     aFloatBtn.SetSymbol( SYMBOL_FLOAT );
5929     aHideBtn.SetSymbol( SYMBOL_HIDE );
5930     //aCloser.SetSymbol( SYMBOL_CLOSE ); //is a toolbox now
5931 
5932     Invalidate();
5933 }
5934 
5935 sal_uInt16 MenuBarWindow::ImplFindEntry( const Point& rMousePos ) const
5936 {
5937     if( pMenu )
5938     {
5939         long nX = 0;
5940         sal_uInt16 nCount = (sal_uInt16)pMenu->pItemList->Count();
5941         for ( sal_uInt16 n = 0; n < nCount; n++ )
5942         {
5943             MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
5944             if ( pMenu->ImplIsVisible( n ) )
5945             {
5946                 nX += pData->aSz.Width();
5947                 if ( nX > rMousePos.X() )
5948                     return (sal_uInt16)n;
5949             }
5950         }
5951     }
5952     return ITEMPOS_INVALID;
5953 }
5954 
5955 void MenuBarWindow::RequestHelp( const HelpEvent& rHEvt )
5956 {
5957     sal_uInt16 nId = nHighlightedItem;
5958     if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
5959         ChangeHighlightItem( ITEMPOS_INVALID, sal_True );
5960 
5961 	Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) );
5962     if( !ImplHandleHelpEvent( this, pMenu, nId, rHEvt, aHighlightRect ) )
5963         Window::RequestHelp( rHEvt );
5964 }
5965 
5966 void MenuBarWindow::StateChanged( StateChangedType nType )
5967 {
5968     Window::StateChanged( nType );
5969 
5970     if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) ||
5971          ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
5972     {
5973         ImplInitMenuWindow( this, sal_False, sal_True );
5974         Invalidate();
5975     }
5976     else if( pMenu )
5977         pMenu->ImplKillLayoutData();
5978 
5979 }
5980 
5981 void MenuBarWindow::ImplLayoutChanged()
5982 {
5983     if( pMenu )
5984     {
5985         ImplInitMenuWindow( this, sal_True, sal_True );
5986         // Falls sich der Font geaendert hat.
5987         long nHeight = pMenu->ImplCalcSize( this ).Height();
5988 
5989         // depending on the native implementation or the displayable flag
5990         // the menubar windows is supressed (ie, height=0)
5991         if( !((MenuBar*) pMenu)->IsDisplayable() ||
5992             ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) )
5993             nHeight = 0;
5994 
5995         SetPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT );
5996         GetParent()->Resize();
5997         Invalidate();
5998         Resize();
5999         if( pMenu )
6000             pMenu->ImplKillLayoutData();
6001     }
6002 }
6003 
6004 void MenuBarWindow::ImplInitStyleSettings()
6005 {
6006     if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) &&
6007         IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
6008     {
6009         Color aHighlightTextColor = ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor;
6010         if( aHighlightTextColor != Color( COL_TRANSPARENT ) )
6011         {
6012             AllSettings aSettings( GetSettings() );
6013             StyleSettings aStyle( aSettings.GetStyleSettings() );
6014             aStyle.SetMenuHighlightTextColor( aHighlightTextColor );
6015             aSettings.SetStyleSettings( aStyle );
6016             OutputDevice::SetSettings( aSettings );
6017         }
6018     }
6019 }
6020 
6021 void MenuBarWindow::DataChanged( const DataChangedEvent& rDCEvt )
6022 {
6023     Window::DataChanged( rDCEvt );
6024 
6025     if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
6026          (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
6027          ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
6028           (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
6029     {
6030         ImplLayoutChanged();
6031         ImplInitStyleSettings();
6032     }
6033 }
6034 
6035 void MenuBarWindow::LoseFocus()
6036 {
6037     if ( !HasChildPathFocus( sal_True ) )
6038         ChangeHighlightItem( ITEMPOS_INVALID, sal_False, sal_False );
6039 }
6040 
6041 void MenuBarWindow::GetFocus()
6042 {
6043 	if ( nHighlightedItem == ITEMPOS_INVALID )
6044     {
6045         mbAutoPopup = sal_False;    // do not open menu when activated by focus handling like taskpane cycling
6046 		ChangeHighlightItem( 0, sal_False );
6047     }
6048 }
6049 
6050 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuBarWindow::CreateAccessible()
6051 {
6052 	::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc;
6053 
6054 	if ( pMenu )
6055 		xAcc = pMenu->GetAccessible();
6056 
6057 	return xAcc;
6058 }
6059 
6060 sal_uInt16 MenuBarWindow::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const String& i_rToolTip, sal_uInt16 i_nPos )
6061 {
6062     // find first free button id
6063     sal_uInt16 nId = IID_DOCUMENTCLOSE;
6064     std::map< sal_uInt16, AddButtonEntry >::const_iterator it;
6065     if( i_nPos > m_aAddButtons.size() )
6066         i_nPos = static_cast<sal_uInt16>(m_aAddButtons.size());
6067     do
6068     {
6069         nId++;
6070         it = m_aAddButtons.find( nId );
6071     } while( it != m_aAddButtons.end() && nId < 128 );
6072     DBG_ASSERT( nId < 128, "too many addbuttons in menubar" );
6073     AddButtonEntry& rNewEntry = m_aAddButtons[nId];
6074     rNewEntry.m_nId = nId;
6075     rNewEntry.m_aSelectLink = i_rLink;
6076     aCloser.InsertItem( nId, i_rImage, 0, 0 );
6077     aCloser.calcMinSize();
6078     ShowButtons( aCloser.IsItemVisible( IID_DOCUMENTCLOSE ),
6079                  aFloatBtn.IsVisible(),
6080                  aHideBtn.IsVisible() );
6081     ImplLayoutChanged();
6082 
6083     if( pMenu->mpSalMenu )
6084         pMenu->mpSalMenu->AddMenuBarButton( SalMenuButtonItem( nId, i_rImage, i_rToolTip ) );
6085 
6086     return nId;
6087 }
6088 
6089 void MenuBarWindow::SetMenuBarButtonHighlightHdl( sal_uInt16 nId, const Link& rLink )
6090 {
6091     std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( nId );
6092     if( it != m_aAddButtons.end() )
6093         it->second.m_aHighlightLink = rLink;
6094 }
6095 
6096 Rectangle MenuBarWindow::GetMenuBarButtonRectPixel( sal_uInt16 nId )
6097 {
6098     Rectangle aRect;
6099     if( m_aAddButtons.find( nId ) != m_aAddButtons.end() )
6100     {
6101         if( pMenu->mpSalMenu )
6102         {
6103             aRect = pMenu->mpSalMenu->GetMenuBarButtonRectPixel( nId, ImplGetWindowImpl()->mpFrame );
6104             if( aRect == Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) )
6105             {
6106                 // system menu button is somehwere but location cannot be determined
6107                 return Rectangle();
6108             }
6109         }
6110 
6111         if( aRect.IsEmpty() )
6112         {
6113             aRect = aCloser.GetItemRect( nId );
6114             Point aOffset = aCloser.OutputToScreenPixel( Point() );
6115             aRect.Move( aOffset.X(), aOffset.Y() );
6116         }
6117     }
6118     return aRect;
6119 }
6120 
6121 void MenuBarWindow::RemoveMenuBarButton( sal_uInt16 nId )
6122 {
6123 	sal_uInt16 nPos = aCloser.GetItemPos( nId );
6124     aCloser.RemoveItem( nPos );
6125     m_aAddButtons.erase( nId );
6126     aCloser.calcMinSize();
6127     ImplLayoutChanged();
6128 
6129     if( pMenu->mpSalMenu )
6130         pMenu->mpSalMenu->RemoveMenuBarButton( nId );
6131 }
6132 
6133 bool MenuBarWindow::HandleMenuButtonEvent( sal_uInt16 i_nButtonId )
6134 {
6135     std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( i_nButtonId );
6136     if( it != m_aAddButtons.end() )
6137     {
6138         MenuBar::MenuBarButtonCallbackArg aArg;
6139         aArg.nId = it->first;
6140         aArg.bHighlight = true;
6141         aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
6142         return it->second.m_aSelectLink.Call( &aArg );
6143     }
6144     return sal_False;
6145 }
6146 
6147 ImplMenuDelData::ImplMenuDelData( const Menu* pMenu )
6148 : mpNext( 0 )
6149 , mpMenu( 0 )
6150 {
6151 	if( pMenu )
6152 		const_cast< Menu* >( pMenu )->ImplAddDel( *this );
6153 }
6154 
6155 ImplMenuDelData::~ImplMenuDelData()
6156 {
6157 	if( mpMenu )
6158 		const_cast< Menu* >( mpMenu )->ImplRemoveDel( *this );
6159 }
6160