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