Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <tools/debug.hxx>
21 : #include <tools/diagnose_ex.h>
22 : #include <tools/rc.h>
23 : #include <tools/stream.hxx>
24 :
25 : #include <vcl/svapp.hxx>
26 : #include <vcl/mnemonic.hxx>
27 : #include <vcl/image.hxx>
28 : #include <vcl/event.hxx>
29 : #include <vcl/help.hxx>
30 : #include <vcl/floatwin.hxx>
31 : #include <vcl/wrkwin.hxx>
32 : #include <vcl/timer.hxx>
33 : #include <vcl/decoview.hxx>
34 : #include <vcl/bitmap.hxx>
35 : #include <vcl/menu.hxx>
36 : #include <vcl/button.hxx>
37 : #include <vcl/gradient.hxx>
38 : #include <vcl/i18nhelp.hxx>
39 : #include <vcl/taskpanelist.hxx>
40 : #include <vcl/controllayout.hxx>
41 : #include <vcl/toolbox.hxx>
42 : #include <vcl/dockingarea.hxx>
43 : #include <vcl/settings.hxx>
44 :
45 : #include <salinst.hxx>
46 : #include <svdata.hxx>
47 : #include <svids.hrc>
48 : #include <window.h>
49 : #include <salmenu.hxx>
50 : #include <salframe.hxx>
51 :
52 : #include "menubarwindow.hxx"
53 : #include "menufloatingwindow.hxx"
54 : #include "menuitemlist.hxx"
55 :
56 : #include <com/sun/star/uno/Reference.h>
57 : #include <com/sun/star/lang/XComponent.hpp>
58 : #include <com/sun/star/accessibility/XAccessible.hpp>
59 : #include <com/sun/star/accessibility/AccessibleRole.hpp>
60 : #include <vcl/unowrap.hxx>
61 :
62 : #include <vcl/unohelp.hxx>
63 : #include <vcl/configsettings.hxx>
64 :
65 : #include "vcl/lazydelete.hxx"
66 :
67 : #include <map>
68 : #include <vector>
69 :
70 : namespace vcl
71 : {
72 :
73 8 : struct MenuLayoutData : public ControlLayoutData
74 : {
75 : std::vector< sal_uInt16 > m_aLineItemIds;
76 : std::vector< sal_uInt16 > m_aLineItemPositions;
77 : std::map< sal_uInt16, Rectangle > m_aVisibleItemBoundRects;
78 : };
79 :
80 : }
81 :
82 : using namespace ::com::sun::star;
83 : using namespace vcl;
84 :
85 : #define EXTRAITEMHEIGHT 4
86 :
87 0 : static bool ImplAccelDisabled()
88 : {
89 : // display of accelerator strings may be suppressed via configuration
90 : static int nAccelDisabled = -1;
91 :
92 0 : if( nAccelDisabled == -1 )
93 : {
94 : OUString aStr =
95 : vcl::SettingsConfigItem::get()->
96 0 : getValue( "Menu", "SuppressAccelerators" );
97 0 : nAccelDisabled = aStr.equalsIgnoreAsciiCase("true") ? 1 : 0;
98 : }
99 0 : return nAccelDisabled == 1;
100 : }
101 :
102 67348 : static void ImplSetMenuItemData( MenuItemData* pData )
103 : {
104 : // convert data
105 67348 : if ( !pData->aImage )
106 13524 : pData->eType = MenuItemType::STRING;
107 53824 : else if ( pData->aText.isEmpty() )
108 72 : pData->eType = MenuItemType::IMAGE;
109 : else
110 53752 : pData->eType = MenuItemType::STRINGIMAGE;
111 67348 : }
112 :
113 139892 : Menu::Menu()
114 : : mpFirstDel(NULL),
115 139892 : pItemList(new MenuItemList),
116 : pLogo(NULL),
117 : pStartedFrom(NULL),
118 : pWindow(NULL),
119 : nEventId(0),
120 : mnHighlightedItemPos(ITEMPOS_INVALID),
121 : nMenuFlags(0),
122 : nDefaultItem(0),
123 : nSelectedId(0),
124 : nImgOrChkPos(0),
125 : nTextPos(0),
126 : bCanceled(false),
127 : bInCallback(false),
128 : bKilled(false),
129 : mpLayoutData(NULL),
130 279784 : mpSalMenu(NULL)
131 : {
132 139892 : }
133 :
134 279736 : Menu::~Menu()
135 : {
136 :
137 139868 : vcl::LazyDeletor<Menu>::Undelete( this );
138 :
139 139868 : ImplCallEventListeners( VCLEVENT_OBJECT_DYING, ITEMPOS_INVALID );
140 :
141 : // at the window free the reference to the accessible component
142 : // and make sure the MenuFloatingWindow knows about our destruction
143 139868 : if ( pWindow )
144 : {
145 0 : MenuFloatingWindow* pFloat = static_cast<MenuFloatingWindow*>(pWindow);
146 0 : if( pFloat->pMenu == this )
147 0 : pFloat->pMenu = NULL;
148 0 : pWindow->SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() );
149 : }
150 :
151 : // dispose accessible components
152 139868 : if ( mxAccessible.is() )
153 : {
154 576 : ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent> xComponent( mxAccessible, ::com::sun::star::uno::UNO_QUERY );
155 576 : if ( xComponent.is() )
156 576 : xComponent->dispose();
157 : }
158 :
159 139868 : if ( nEventId )
160 0 : Application::RemoveUserEvent( nEventId );
161 :
162 : // Notify deletion of this menu
163 139868 : ImplMenuDelData* pDelData = mpFirstDel;
164 279736 : while ( pDelData )
165 : {
166 0 : pDelData->mpMenu = NULL;
167 0 : pDelData = pDelData->mpNext;
168 : }
169 :
170 139868 : bKilled = true;
171 :
172 139868 : delete pItemList;
173 139868 : delete pLogo;
174 139868 : delete mpLayoutData;
175 :
176 : // Native-support: destroy SalMenu
177 139868 : ImplSetSalMenu( NULL );
178 139868 : }
179 :
180 18 : void Menu::CreateAutoMnemonics()
181 : {
182 18 : MnemonicGenerator aMnemonicGenerator;
183 : size_t n;
184 492 : for ( n = 0; n < pItemList->size(); n++ )
185 : {
186 474 : MenuItemData* pData = pItemList->GetDataFromPos( n );
187 474 : if ( ! (pData->nBits & MenuItemBits::NOSELECT ) )
188 474 : aMnemonicGenerator.RegisterMnemonic( pData->aText );
189 : }
190 492 : for ( n = 0; n < pItemList->size(); n++ )
191 : {
192 474 : MenuItemData* pData = pItemList->GetDataFromPos( n );
193 474 : if ( ! (pData->nBits & MenuItemBits::NOSELECT ) )
194 474 : pData->aText = aMnemonicGenerator.CreateMnemonic( pData->aText );
195 18 : }
196 18 : }
197 :
198 36 : void Menu::Activate()
199 : {
200 36 : bInCallback = true;
201 :
202 36 : ImplMenuDelData aDelData( this );
203 :
204 36 : ImplCallEventListeners( VCLEVENT_MENU_ACTIVATE, ITEMPOS_INVALID );
205 :
206 36 : if( !aDelData.isDeleted() )
207 : {
208 36 : if ( !aActivateHdl.Call( this ) )
209 : {
210 0 : if( !aDelData.isDeleted() )
211 : {
212 0 : Menu* pStartMenu = ImplGetStartMenu();
213 0 : if ( pStartMenu && ( pStartMenu != this ) )
214 : {
215 0 : pStartMenu->bInCallback = true;
216 : // MT 11/01: Call EventListener here? I don't know...
217 0 : pStartMenu->aActivateHdl.Call( this );
218 0 : pStartMenu->bInCallback = false;
219 : }
220 : }
221 : }
222 36 : bInCallback = false;
223 36 : }
224 36 : }
225 :
226 48 : void Menu::Deactivate()
227 : {
228 840 : for ( size_t n = pItemList->size(); n; )
229 : {
230 744 : MenuItemData* pData = pItemList->GetDataFromPos( --n );
231 744 : if ( pData->bIsTemporary )
232 0 : pItemList->Remove( n );
233 : }
234 :
235 48 : bInCallback = true;
236 :
237 48 : ImplMenuDelData aDelData( this );
238 :
239 48 : Menu* pStartMenu = ImplGetStartMenu();
240 48 : ImplCallEventListeners( VCLEVENT_MENU_DEACTIVATE, ITEMPOS_INVALID );
241 :
242 48 : if( !aDelData.isDeleted() )
243 : {
244 48 : if ( !aDeactivateHdl.Call( this ) )
245 : {
246 0 : if( !aDelData.isDeleted() )
247 : {
248 0 : if ( pStartMenu && ( pStartMenu != this ) )
249 : {
250 0 : pStartMenu->bInCallback = true;
251 0 : pStartMenu->aDeactivateHdl.Call( this );
252 0 : pStartMenu->bInCallback = false;
253 : }
254 : }
255 : }
256 : }
257 :
258 48 : if( !aDelData.isDeleted() )
259 : {
260 48 : bInCallback = false;
261 48 : }
262 48 : }
263 :
264 52 : void Menu::Highlight()
265 : {
266 52 : ImplMenuDelData aDelData( this );
267 :
268 52 : Menu* pStartMenu = ImplGetStartMenu();
269 52 : if ( !aHighlightHdl.Call( this ) && !aDelData.isDeleted() )
270 : {
271 52 : if ( pStartMenu && ( pStartMenu != this ) )
272 0 : pStartMenu->aHighlightHdl.Call( this );
273 52 : }
274 52 : }
275 :
276 0 : void Menu::ImplSelect()
277 : {
278 0 : MenuItemData* pData = GetItemList()->GetData( nSelectedId );
279 0 : if ( pData && (pData->nBits & MenuItemBits::AUTOCHECK) )
280 : {
281 0 : bool bChecked = IsItemChecked( nSelectedId );
282 0 : if ( pData->nBits & MenuItemBits::RADIOCHECK )
283 : {
284 0 : if ( !bChecked )
285 0 : CheckItem( nSelectedId, true );
286 : }
287 : else
288 0 : CheckItem( nSelectedId, !bChecked );
289 : }
290 :
291 : // call select
292 0 : ImplSVData* pSVData = ImplGetSVData();
293 0 : pSVData->maAppData.mpActivePopupMenu = NULL; // if new execute in select()
294 0 : nEventId = Application::PostUserEvent( LINK( this, Menu, ImplCallSelect ) );
295 0 : }
296 :
297 0 : void Menu::Select()
298 : {
299 0 : ImplMenuDelData aDelData( this );
300 :
301 0 : ImplCallEventListeners( VCLEVENT_MENU_SELECT, GetItemPos( GetCurItemId() ) );
302 0 : if ( !aDelData.isDeleted() && !aSelectHdl.Call( this ) )
303 : {
304 0 : if( !aDelData.isDeleted() )
305 : {
306 0 : Menu* pStartMenu = ImplGetStartMenu();
307 0 : if ( pStartMenu && ( pStartMenu != this ) )
308 : {
309 0 : pStartMenu->nSelectedId = nSelectedId;
310 0 : pStartMenu->aSelectHdl.Call( this );
311 : }
312 : }
313 0 : }
314 0 : }
315 :
316 : #if defined(MACOSX)
317 : void Menu::ImplSelectWithStart( Menu* pSMenu )
318 : {
319 : Menu* pOldStartedFrom = pStartedFrom;
320 : pStartedFrom = pSMenu;
321 : Menu* pOldStartedStarted = pOldStartedFrom ? pOldStartedFrom->pStartedFrom : NULL;
322 : Select();
323 : if( pOldStartedFrom )
324 : pOldStartedFrom->pStartedFrom = pOldStartedStarted;
325 : pStartedFrom = pOldStartedFrom;
326 : }
327 : #endif
328 :
329 0 : void Menu::RequestHelp( const HelpEvent& )
330 : {
331 0 : }
332 :
333 835961 : void Menu::ImplCallEventListeners( sal_uLong nEvent, sal_uInt16 nPos )
334 : {
335 835961 : ImplMenuDelData aDelData( this );
336 :
337 1671922 : VclMenuEvent aEvent( this, nEvent, nPos );
338 :
339 : // This is needed by atk accessibility bridge
340 835961 : if ( nEvent == VCLEVENT_MENU_HIGHLIGHT )
341 : {
342 52 : Application::ImplCallEventListeners( &aEvent );
343 : }
344 :
345 835961 : if ( !aDelData.isDeleted() )
346 835961 : maEventListeners.Call( &aEvent );
347 :
348 835961 : if( !aDelData.isDeleted() )
349 : {
350 835961 : Menu* pMenu = this;
351 2508215 : while ( pMenu )
352 : {
353 836293 : maChildEventListeners.Call( &aEvent );
354 :
355 836293 : if( aDelData.isDeleted() )
356 0 : break;
357 :
358 836293 : pMenu = ( pMenu->pStartedFrom != pMenu ) ? pMenu->pStartedFrom : NULL;
359 : }
360 835961 : }
361 835961 : }
362 :
363 15448 : void Menu::AddEventListener( const Link& rEventListener )
364 : {
365 15448 : maEventListeners.addListener( rEventListener );
366 15448 : }
367 :
368 20918 : void Menu::RemoveEventListener( const Link& rEventListener )
369 : {
370 20918 : maEventListeners.removeListener( rEventListener );
371 20918 : }
372 :
373 490660 : void Menu::InsertItem(sal_uInt16 nItemId, const OUString& rStr, MenuItemBits nItemBits,
374 : const OString &rIdent, sal_uInt16 nPos)
375 : {
376 : DBG_ASSERT( nItemId, "Menu::InsertItem(): ItemId == 0" );
377 : DBG_ASSERT( GetItemPos( nItemId ) == MENU_ITEM_NOTFOUND,
378 : "Menu::InsertItem(): ItemId already exists" );
379 :
380 : // if Position > ItemCount, append
381 490660 : if ( nPos >= pItemList->size() )
382 490658 : nPos = MENU_APPEND;
383 :
384 : // put Item in MenuItemList
385 : MenuItemData* pData = pItemList->Insert(nItemId, MenuItemType::STRING,
386 490660 : nItemBits, rStr, Image(), this, nPos, rIdent);
387 :
388 : // update native menu
389 490660 : if( ImplGetSalMenu() && pData->pSalMenuItem )
390 0 : ImplGetSalMenu()->InsertItem( pData->pSalMenuItem, nPos );
391 :
392 490660 : vcl::Window* pWin = ImplGetWindow();
393 490660 : delete mpLayoutData, mpLayoutData = NULL;
394 490660 : if ( pWin )
395 : {
396 114 : ImplCalcSize( pWin );
397 114 : if ( pWin->IsVisible() )
398 114 : pWin->Invalidate();
399 : }
400 490660 : ImplCallEventListeners( VCLEVENT_MENU_INSERTITEM, nPos );
401 490660 : }
402 :
403 0 : void Menu::InsertItem(sal_uInt16 nItemId, const Image& rImage,
404 : MenuItemBits nItemBits, const OString &rIdent, sal_uInt16 nPos)
405 : {
406 0 : InsertItem(nItemId, OUString(), nItemBits, rIdent, nPos);
407 0 : SetItemImage( nItemId, rImage );
408 0 : }
409 :
410 35784 : void Menu::InsertItem(sal_uInt16 nItemId, const OUString& rStr,
411 : const Image& rImage, MenuItemBits nItemBits,
412 : const OString &rIdent, sal_uInt16 nPos)
413 : {
414 35784 : InsertItem(nItemId, rStr, nItemBits, rIdent, nPos);
415 35784 : SetItemImage( nItemId, rImage );
416 35784 : }
417 :
418 9794 : void Menu::InsertItem( const ResId& rResId, sal_uInt16 nPos )
419 : {
420 9794 : ResMgr* pMgr = rResId.GetResMgr();
421 9794 : if( ! pMgr )
422 9794 : return;
423 :
424 : sal_uLong nObjMask;
425 :
426 9794 : GetRes( rResId.SetRT( RSC_MENUITEM ) );
427 9794 : nObjMask = ReadLongRes();
428 :
429 9794 : bool bSep = false;
430 9794 : if ( nObjMask & RSC_MENUITEM_SEPARATOR )
431 134 : bSep = ReadShortRes() != 0;
432 :
433 9794 : sal_uInt16 nItemId = 1;
434 9794 : if ( nObjMask & RSC_MENUITEM_ID )
435 8247 : nItemId = sal::static_int_cast<sal_uInt16>(ReadLongRes());
436 :
437 9794 : MenuItemBits nStatus = MenuItemBits::NONE;
438 9794 : if ( nObjMask & RSC_MENUITEM_STATUS )
439 5700 : nStatus = sal::static_int_cast<MenuItemBits>(ReadLongRes());
440 :
441 9794 : OUString aText;
442 9794 : if ( nObjMask & RSC_MENUITEM_TEXT )
443 9660 : aText = ReadStringRes();
444 :
445 : // create item
446 9794 : if ( nObjMask & RSC_MENUITEM_BITMAP )
447 : {
448 0 : if ( !bSep )
449 : {
450 0 : Bitmap aBmp( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
451 0 : Image const aImg(aBmp);
452 0 : if ( !aText.isEmpty() )
453 0 : InsertItem( nItemId, aText, aImg, nStatus, OString(), nPos );
454 : else
455 0 : InsertItem( nItemId, aImg, nStatus, OString(), nPos );
456 : }
457 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
458 : }
459 9794 : else if ( !bSep )
460 9660 : InsertItem(nItemId, aText, nStatus, OString(), nPos);
461 9794 : if ( bSep )
462 134 : InsertSeparator(OString(), nPos);
463 :
464 19588 : OUString aHelpText;
465 9794 : if ( nObjMask & RSC_MENUITEM_HELPTEXT )
466 : {
467 0 : aHelpText = ReadStringRes();
468 0 : if( !bSep )
469 0 : SetHelpText( nItemId, aHelpText );
470 : }
471 :
472 9794 : if ( nObjMask & RSC_MENUITEM_HELPID )
473 : {
474 1524 : OString aHelpId( ReadByteStringRes() );
475 1524 : if ( !bSep )
476 1524 : SetHelpId( nItemId, aHelpId );
477 : }
478 :
479 9794 : if( !bSep )
480 9660 : SetHelpText( nItemId, aHelpText );
481 :
482 9794 : if ( nObjMask & RSC_MENUITEM_KEYCODE )
483 : {
484 0 : if ( !bSep )
485 0 : SetAccelKey( nItemId, KeyCode( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) ) );
486 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
487 : }
488 9794 : if( nObjMask & RSC_MENUITEM_CHECKED )
489 : {
490 0 : if ( !bSep )
491 0 : CheckItem( nItemId, ReadShortRes() != 0 );
492 : }
493 9794 : if ( nObjMask & RSC_MENUITEM_DISABLE )
494 : {
495 0 : if ( !bSep )
496 0 : EnableItem( nItemId, ReadShortRes() == 0 );
497 : }
498 9794 : if ( nObjMask & RSC_MENUITEM_COMMAND )
499 : {
500 48 : OUString aCommandStr = ReadStringRes();
501 48 : if ( !bSep )
502 48 : SetItemCommand( nItemId, aCommandStr );
503 : }
504 9794 : if ( nObjMask & RSC_MENUITEM_MENU )
505 : {
506 8 : if ( !bSep )
507 : {
508 8 : MenuItemData* pData = GetItemList()->GetData( nItemId );
509 8 : if ( pData )
510 : {
511 8 : PopupMenu* pSubMenu = new PopupMenu( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
512 8 : pData->pAutoSubMenu = pSubMenu;
513 : // #111060# keep track of this pointer, may be it will be deleted from outside
514 8 : pSubMenu->pRefAutoSubMenu = &pData->pAutoSubMenu;
515 8 : SetPopupMenu( nItemId, pSubMenu );
516 : }
517 : }
518 8 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
519 : }
520 19588 : delete mpLayoutData, mpLayoutData = NULL;
521 : }
522 :
523 86272 : void Menu::InsertSeparator(const OString &rIdent, sal_uInt16 nPos)
524 : {
525 : // do nothing if it's a menu bar
526 86272 : if (IsMenuBar())
527 86272 : return;
528 :
529 : // if position > ItemCount, append
530 86272 : if ( nPos >= pItemList->size() )
531 86272 : nPos = MENU_APPEND;
532 :
533 : // put separator in item list
534 86272 : pItemList->InsertSeparator(rIdent, nPos);
535 :
536 : // update native menu
537 86272 : size_t itemPos = ( nPos != MENU_APPEND ) ? nPos : pItemList->size() - 1;
538 86272 : MenuItemData *pData = pItemList->GetDataFromPos( itemPos );
539 86272 : if( ImplGetSalMenu() && pData && pData->pSalMenuItem )
540 0 : ImplGetSalMenu()->InsertItem( pData->pSalMenuItem, nPos );
541 :
542 86272 : delete mpLayoutData, mpLayoutData = NULL;
543 :
544 86272 : ImplCallEventListeners( VCLEVENT_MENU_INSERTITEM, nPos );
545 : }
546 :
547 122 : void Menu::RemoveItem( sal_uInt16 nPos )
548 : {
549 122 : bool bRemove = false;
550 :
551 122 : if ( nPos < GetItemCount() )
552 : {
553 : // update native menu
554 122 : if( ImplGetSalMenu() )
555 0 : ImplGetSalMenu()->RemoveItem( nPos );
556 :
557 122 : pItemList->Remove( nPos );
558 122 : bRemove = true;
559 : }
560 :
561 122 : vcl::Window* pWin = ImplGetWindow();
562 122 : if ( pWin )
563 : {
564 114 : ImplCalcSize( pWin );
565 114 : if ( pWin->IsVisible() )
566 114 : pWin->Invalidate();
567 : }
568 122 : delete mpLayoutData, mpLayoutData = NULL;
569 :
570 122 : if ( bRemove )
571 122 : ImplCallEventListeners( VCLEVENT_MENU_REMOVEITEM, nPos );
572 122 : }
573 :
574 22410 : void ImplCopyItem( Menu* pThis, const Menu& rMenu, sal_uInt16 nPos, sal_uInt16 nNewPos,
575 : sal_uInt16 nMode = 0 )
576 : {
577 22410 : MenuItemType eType = rMenu.GetItemType( nPos );
578 :
579 22410 : if ( eType == MenuItemType::DONTKNOW )
580 0 : return;
581 :
582 22410 : if ( eType == MenuItemType::SEPARATOR )
583 4482 : pThis->InsertSeparator( OString(), nNewPos );
584 : else
585 : {
586 17928 : sal_uInt16 nId = rMenu.GetItemId( nPos );
587 :
588 : DBG_ASSERT( pThis->GetItemPos( nId ) == MENU_ITEM_NOTFOUND,
589 : "Menu::CopyItem(): ItemId already exists" );
590 :
591 17928 : MenuItemData* pData = rMenu.GetItemList()->GetData( nId );
592 :
593 17928 : if (!pData)
594 0 : return;
595 :
596 17928 : if ( eType == MenuItemType::STRINGIMAGE )
597 17892 : pThis->InsertItem( nId, pData->aText, pData->aImage, pData->nBits, pData->sIdent, nNewPos );
598 36 : else if ( eType == MenuItemType::STRING )
599 36 : pThis->InsertItem( nId, pData->aText, pData->nBits, pData->sIdent, nNewPos );
600 : else
601 0 : pThis->InsertItem( nId, pData->aImage, pData->nBits, pData->sIdent, nNewPos );
602 :
603 17928 : if ( rMenu.IsItemChecked( nId ) )
604 0 : pThis->CheckItem( nId, true );
605 17928 : if ( !rMenu.IsItemEnabled( nId ) )
606 0 : pThis->EnableItem( nId, false );
607 17928 : pThis->SetHelpId( nId, pData->aHelpId );
608 17928 : pThis->SetHelpText( nId, pData->aHelpText );
609 17928 : pThis->SetAccelKey( nId, pData->aAccelKey );
610 17928 : pThis->SetItemCommand( nId, pData->aCommandStr );
611 17928 : pThis->SetHelpCommand( nId, pData->aHelpCommandStr );
612 :
613 17928 : PopupMenu* pSubMenu = rMenu.GetPopupMenu( nId );
614 17928 : if ( pSubMenu )
615 : {
616 : // create auto-copy
617 0 : if ( nMode == 1 )
618 : {
619 0 : PopupMenu* pNewMenu = new PopupMenu( *pSubMenu );
620 0 : pThis->SetPopupMenu( nId, pNewMenu );
621 : }
622 : else
623 0 : pThis->SetPopupMenu( nId, pSubMenu );
624 : }
625 : }
626 : }
627 :
628 0 : void Menu::CopyItem( const Menu& rMenu, sal_uInt16 nPos, sal_uInt16 nNewPos )
629 : {
630 0 : ImplCopyItem( this, rMenu, nPos, nNewPos );
631 0 : }
632 :
633 1508 : void Menu::Clear()
634 : {
635 1622 : for ( sal_uInt16 i = GetItemCount(); i; i-- )
636 114 : RemoveItem( 0 );
637 1508 : }
638 :
639 251709 : sal_uInt16 Menu::GetItemCount() const
640 : {
641 251709 : return (sal_uInt16)pItemList->size();
642 : }
643 :
644 16 : sal_uInt16 Menu::ImplGetVisibleItemCount() const
645 : {
646 16 : sal_uInt16 nItems = 0;
647 488 : for ( size_t n = pItemList->size(); n; )
648 : {
649 456 : if ( ImplIsVisible( --n ) )
650 456 : nItems++;
651 : }
652 16 : return nItems;
653 : }
654 :
655 0 : sal_uInt16 Menu::ImplGetFirstVisible() const
656 : {
657 0 : for ( size_t n = 0; n < pItemList->size(); n++ )
658 : {
659 0 : if ( ImplIsVisible( n ) )
660 0 : return n;
661 : }
662 0 : return ITEMPOS_INVALID;
663 : }
664 :
665 0 : sal_uInt16 Menu::ImplGetPrevVisible( sal_uInt16 nPos ) const
666 : {
667 0 : for ( size_t n = nPos; n; )
668 : {
669 0 : if ( n && ImplIsVisible( --n ) )
670 0 : return n;
671 : }
672 0 : return ITEMPOS_INVALID;
673 : }
674 :
675 0 : sal_uInt16 Menu::ImplGetNextVisible( sal_uInt16 nPos ) const
676 : {
677 0 : for ( size_t n = nPos+1; n < pItemList->size(); n++ )
678 : {
679 0 : if ( ImplIsVisible( n ) )
680 0 : return n;
681 : }
682 0 : return ITEMPOS_INVALID;
683 : }
684 :
685 676695 : sal_uInt16 Menu::GetItemId(sal_uInt16 nPos) const
686 : {
687 676695 : MenuItemData* pData = pItemList->GetDataFromPos( nPos );
688 :
689 676695 : if ( pData )
690 676695 : return pData->nId;
691 : else
692 0 : return 0;
693 : }
694 :
695 0 : sal_uInt16 Menu::GetItemId(const OString &rIdent) const
696 : {
697 0 : for (size_t n = 0; n < pItemList->size(); ++n)
698 : {
699 0 : MenuItemData* pData = pItemList->GetDataFromPos(n);
700 0 : if (pData && pData->sIdent == rIdent)
701 0 : return pData->nId;
702 : }
703 0 : return MENU_ITEM_NOTFOUND;
704 : }
705 :
706 2888 : sal_uInt16 Menu::GetItemPos( sal_uInt16 nItemId ) const
707 : {
708 : size_t nPos;
709 2888 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
710 :
711 2888 : if ( pData )
712 2856 : return (sal_uInt16)nPos;
713 : else
714 32 : return MENU_ITEM_NOTFOUND;
715 : }
716 :
717 534734 : MenuItemType Menu::GetItemType( sal_uInt16 nPos ) const
718 : {
719 534734 : MenuItemData* pData = pItemList->GetDataFromPos( nPos );
720 :
721 534734 : if ( pData )
722 516806 : return pData->eType;
723 : else
724 17928 : return MenuItemType::DONTKNOW;
725 : }
726 :
727 0 : OString Menu::GetCurItemIdent() const
728 : {
729 0 : const MenuItemData* pData = pItemList->GetData(nSelectedId);
730 0 : return pData ? pData->sIdent : OString();
731 : }
732 :
733 0 : OString Menu::GetItemIdent(sal_uInt16 nId) const
734 : {
735 0 : const MenuItemData* pData = pItemList->GetData(nId);
736 0 : return pData ? pData->sIdent : OString();
737 : }
738 :
739 17177 : void Menu::SetItemBits( sal_uInt16 nItemId, MenuItemBits nBits )
740 : {
741 17177 : MenuItemData* pData = pItemList->GetData( nItemId );
742 17177 : if ( pData )
743 17177 : pData->nBits = nBits;
744 17177 : }
745 :
746 20575 : MenuItemBits Menu::GetItemBits( sal_uInt16 nItemId ) const
747 : {
748 20575 : MenuItemBits nBits = MenuItemBits::NONE;
749 20575 : MenuItemData* pData = pItemList->GetData( nItemId );
750 20575 : if ( pData )
751 20575 : nBits = pData->nBits;
752 20575 : return nBits;
753 : }
754 :
755 18008 : void Menu::SetUserValue( sal_uInt16 nItemId, sal_uLong nValue )
756 : {
757 18008 : MenuItemData* pData = pItemList->GetData( nItemId );
758 18008 : if ( pData )
759 18008 : pData->nUserValue = nValue;
760 18008 : }
761 :
762 91020 : sal_uLong Menu::GetUserValue( sal_uInt16 nItemId ) const
763 : {
764 91020 : MenuItemData* pData = pItemList->GetData( nItemId );
765 91020 : return pData ? pData->nUserValue : 0;
766 : }
767 :
768 83248 : void Menu::SetPopupMenu( sal_uInt16 nItemId, PopupMenu* pMenu )
769 : {
770 : size_t nPos;
771 83248 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
772 :
773 : // Item does not exist -> return NULL
774 83248 : if ( !pData )
775 0 : return;
776 :
777 : // same menu, nothing to do
778 83248 : if ( static_cast<PopupMenu*>(pData->pSubMenu) == pMenu )
779 0 : return;
780 :
781 : // data exchange
782 83248 : pData->pSubMenu = pMenu;
783 :
784 : // #112023# Make sure pStartedFrom does not point to invalid (old) data
785 83248 : if ( pData->pSubMenu )
786 69880 : pData->pSubMenu->pStartedFrom = 0;
787 :
788 : // set native submenu
789 83248 : if( ImplGetSalMenu() && pData->pSalMenuItem )
790 : {
791 0 : if( pMenu )
792 0 : ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, pMenu->ImplGetSalMenu(), nPos );
793 : else
794 0 : ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, NULL, nPos );
795 : }
796 :
797 83248 : ImplCallEventListeners( VCLEVENT_MENU_SUBMENUCHANGED, nPos );
798 : }
799 :
800 603554 : PopupMenu* Menu::GetPopupMenu( sal_uInt16 nItemId ) const
801 : {
802 603554 : MenuItemData* pData = pItemList->GetData( nItemId );
803 :
804 603554 : if ( pData )
805 581802 : return static_cast<PopupMenu*>(pData->pSubMenu);
806 : else
807 21752 : return NULL;
808 : }
809 :
810 18258 : void Menu::SetAccelKey( sal_uInt16 nItemId, const KeyCode& rKeyCode )
811 : {
812 : size_t nPos;
813 18258 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
814 :
815 18258 : if ( !pData )
816 18258 : return;
817 :
818 18258 : if ( pData->aAccelKey == rKeyCode )
819 18258 : return;
820 :
821 0 : pData->aAccelKey = rKeyCode;
822 :
823 : // update native menu
824 0 : if( ImplGetSalMenu() && pData->pSalMenuItem )
825 0 : ImplGetSalMenu()->SetAccelerator( nPos, pData->pSalMenuItem, rKeyCode, rKeyCode.GetName() );
826 : }
827 :
828 2 : KeyCode Menu::GetAccelKey( sal_uInt16 nItemId ) const
829 : {
830 2 : MenuItemData* pData = pItemList->GetData( nItemId );
831 :
832 2 : if ( pData )
833 2 : return pData->aAccelKey;
834 : else
835 0 : return KeyCode();
836 : }
837 :
838 2 : KeyEvent Menu::GetActivationKey( sal_uInt16 nItemId ) const
839 : {
840 2 : KeyEvent aRet;
841 2 : MenuItemData* pData = pItemList->GetData( nItemId );
842 2 : if( pData )
843 : {
844 2 : sal_Int32 nPos = pData->aText.indexOf( '~' );
845 2 : if( nPos != -1 && nPos < pData->aText.getLength()-1 )
846 : {
847 2 : sal_uInt16 nCode = 0;
848 2 : sal_Unicode cAccel = pData->aText[nPos+1];
849 2 : if( cAccel >= 'a' && cAccel <= 'z' )
850 0 : nCode = KEY_A + (cAccel-'a');
851 2 : else if( cAccel >= 'A' && cAccel <= 'Z' )
852 2 : nCode = KEY_A + (cAccel-'A');
853 0 : else if( cAccel >= '0' && cAccel <= '9' )
854 0 : nCode = KEY_0 + (cAccel-'0');
855 2 : if(nCode )
856 2 : aRet = KeyEvent( cAccel, KeyCode( nCode, KEY_MOD2 ) );
857 : }
858 :
859 : }
860 2 : return aRet;
861 : }
862 :
863 1592 : void Menu::CheckItem( sal_uInt16 nItemId, bool bCheck )
864 : {
865 : size_t nPos;
866 1592 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
867 :
868 1592 : if ( !pData || pData->bChecked == bCheck )
869 1741 : return;
870 :
871 : // if radio-check, then uncheck previous
872 2898 : if ( bCheck && (pData->nBits & MenuItemBits::AUTOCHECK) &&
873 1455 : (pData->nBits & MenuItemBits::RADIOCHECK) )
874 : {
875 : MenuItemData* pGroupData;
876 : sal_uInt16 nGroupPos;
877 6 : sal_uInt16 nItemCount = GetItemCount();
878 6 : bool bFound = false;
879 :
880 6 : nGroupPos = nPos;
881 12 : while ( nGroupPos )
882 : {
883 0 : pGroupData = pItemList->GetDataFromPos( nGroupPos-1 );
884 0 : if ( pGroupData->nBits & MenuItemBits::RADIOCHECK )
885 : {
886 0 : if ( IsItemChecked( pGroupData->nId ) )
887 : {
888 0 : CheckItem( pGroupData->nId, false );
889 0 : bFound = true;
890 0 : break;
891 : }
892 : }
893 : else
894 0 : break;
895 0 : nGroupPos--;
896 : }
897 :
898 6 : if ( !bFound )
899 : {
900 6 : nGroupPos = nPos+1;
901 24 : while ( nGroupPos < nItemCount )
902 : {
903 12 : pGroupData = pItemList->GetDataFromPos( nGroupPos );
904 12 : if ( pGroupData->nBits & MenuItemBits::RADIOCHECK )
905 : {
906 12 : if ( IsItemChecked( pGroupData->nId ) )
907 : {
908 0 : CheckItem( pGroupData->nId, false );
909 0 : break;
910 : }
911 : }
912 : else
913 0 : break;
914 12 : nGroupPos++;
915 : }
916 : }
917 : }
918 :
919 1443 : pData->bChecked = bCheck;
920 :
921 : // update native menu
922 1443 : if( ImplGetSalMenu() )
923 0 : ImplGetSalMenu()->CheckItem( nPos, bCheck );
924 :
925 1443 : ImplCallEventListeners( bCheck ? VCLEVENT_MENU_ITEMCHECKED : VCLEVENT_MENU_ITEMUNCHECKED, nPos );
926 : }
927 :
928 25236 : bool Menu::IsItemChecked( sal_uInt16 nItemId ) const
929 : {
930 : size_t nPos;
931 25236 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
932 :
933 25236 : if ( !pData )
934 0 : return false;
935 :
936 25236 : return pData->bChecked;
937 : }
938 :
939 13672 : void Menu::EnableItem( sal_uInt16 nItemId, bool bEnable )
940 : {
941 : size_t nPos;
942 13672 : MenuItemData* pItemData = pItemList->GetData( nItemId, nPos );
943 :
944 13672 : if ( pItemData && ( pItemData->bEnabled != bEnable ) )
945 : {
946 13442 : pItemData->bEnabled = bEnable;
947 :
948 13442 : vcl::Window* pWin = ImplGetWindow();
949 13442 : if ( pWin && pWin->IsVisible() )
950 : {
951 : DBG_ASSERT(IsMenuBar(), "Menu::EnableItem - Popup visible!" );
952 0 : long nX = 0;
953 0 : size_t nCount = pItemList->size();
954 0 : for ( size_t n = 0; n < nCount; n++ )
955 : {
956 0 : MenuItemData* pData = pItemList->GetDataFromPos( n );
957 0 : if ( n == nPos )
958 : {
959 0 : pWin->Invalidate( Rectangle( Point( nX, 0 ), Size( pData->aSz.Width(), pData->aSz.Height() ) ) );
960 0 : break;
961 : }
962 0 : nX += pData->aSz.Width();
963 : }
964 : }
965 : // update native menu
966 13442 : if( ImplGetSalMenu() )
967 0 : ImplGetSalMenu()->EnableItem( nPos, bEnable );
968 :
969 13442 : ImplCallEventListeners( bEnable ? VCLEVENT_MENU_ENABLE : VCLEVENT_MENU_DISABLE, nPos );
970 : }
971 13672 : }
972 :
973 26992 : bool Menu::IsItemEnabled( sal_uInt16 nItemId ) const
974 : {
975 : size_t nPos;
976 26992 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
977 :
978 26992 : if ( !pData )
979 0 : return false;
980 :
981 26992 : return pData->bEnabled;
982 : }
983 :
984 568 : void Menu::ShowItem( sal_uInt16 nItemId, bool bVisible )
985 : {
986 : size_t nPos;
987 568 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
988 :
989 : DBG_ASSERT(!IsMenuBar(), "Menu::ShowItem - ignored for menu bar entries!");
990 568 : if (!IsMenuBar()&& pData && (pData->bVisible != bVisible))
991 : {
992 0 : vcl::Window* pWin = ImplGetWindow();
993 0 : if ( pWin && pWin->IsVisible() )
994 : {
995 : DBG_ASSERT( false, "Menu::ShowItem - ignored for visible popups!" );
996 0 : return;
997 : }
998 0 : pData->bVisible = bVisible;
999 :
1000 : // update native menu
1001 0 : if( ImplGetSalMenu() )
1002 0 : ImplGetSalMenu()->ShowItem( nPos, bVisible );
1003 : }
1004 : }
1005 :
1006 13526 : void Menu::SetItemText( sal_uInt16 nItemId, const OUString& rStr )
1007 : {
1008 : size_t nPos;
1009 13526 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1010 :
1011 13526 : if ( !pData )
1012 13526 : return;
1013 :
1014 13526 : if ( !rStr.equals( pData->aText ) )
1015 : {
1016 13526 : pData->aText = rStr;
1017 13526 : ImplSetMenuItemData( pData );
1018 : // update native menu
1019 13526 : if( ImplGetSalMenu() && pData->pSalMenuItem )
1020 0 : ImplGetSalMenu()->SetItemText( nPos, pData->pSalMenuItem, rStr );
1021 :
1022 13526 : vcl::Window* pWin = ImplGetWindow();
1023 13526 : delete mpLayoutData, mpLayoutData = NULL;
1024 13526 : if (pWin && IsMenuBar())
1025 : {
1026 108 : ImplCalcSize( pWin );
1027 108 : if ( pWin->IsVisible() )
1028 108 : pWin->Invalidate();
1029 : }
1030 :
1031 13526 : ImplCallEventListeners( VCLEVENT_MENU_ITEMTEXTCHANGED, nPos );
1032 : }
1033 : }
1034 :
1035 23329 : OUString Menu::GetItemText( sal_uInt16 nItemId ) const
1036 : {
1037 : size_t nPos;
1038 23329 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1039 :
1040 23329 : if ( pData )
1041 23329 : return pData->aText;
1042 :
1043 0 : return OUString();
1044 : }
1045 :
1046 53822 : void Menu::SetItemImage( sal_uInt16 nItemId, const Image& rImage )
1047 : {
1048 : size_t nPos;
1049 53822 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1050 :
1051 53822 : if ( !pData )
1052 53822 : return;
1053 :
1054 53822 : pData->aImage = rImage;
1055 53822 : ImplSetMenuItemData( pData );
1056 :
1057 : // update native menu
1058 53822 : if( ImplGetSalMenu() && pData->pSalMenuItem )
1059 0 : ImplGetSalMenu()->SetItemImage( nPos, pData->pSalMenuItem, rImage );
1060 : }
1061 :
1062 0 : static inline Image ImplRotImage( const Image& rImage, long nAngle10 )
1063 : {
1064 0 : Image aRet;
1065 0 : BitmapEx aBmpEx( rImage.GetBitmapEx() );
1066 :
1067 0 : aBmpEx.Rotate( nAngle10, COL_WHITE );
1068 :
1069 0 : return Image( aBmpEx );
1070 : }
1071 :
1072 0 : void Menu::SetItemImageAngle( sal_uInt16 nItemId, long nAngle10 )
1073 : {
1074 : size_t nPos;
1075 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1076 :
1077 0 : if ( pData )
1078 : {
1079 0 : long nDeltaAngle = (nAngle10 - pData->nItemImageAngle) % 3600;
1080 0 : while( nDeltaAngle < 0 )
1081 0 : nDeltaAngle += 3600;
1082 :
1083 0 : pData->nItemImageAngle = nAngle10;
1084 0 : if( nDeltaAngle && !!pData->aImage )
1085 0 : pData->aImage = ImplRotImage( pData->aImage, nDeltaAngle );
1086 : }
1087 0 : }
1088 :
1089 0 : static inline Image ImplMirrorImage( const Image& rImage )
1090 : {
1091 0 : Image aRet;
1092 0 : BitmapEx aBmpEx( rImage.GetBitmapEx() );
1093 :
1094 0 : aBmpEx.Mirror( BMP_MIRROR_HORZ );
1095 :
1096 0 : return Image( aBmpEx );
1097 : }
1098 :
1099 0 : void Menu::SetItemImageMirrorMode( sal_uInt16 nItemId, bool bMirror )
1100 : {
1101 : size_t nPos;
1102 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1103 :
1104 0 : if ( pData )
1105 : {
1106 0 : if( ( pData->bMirrorMode && ! bMirror ) ||
1107 0 : ( ! pData->bMirrorMode && bMirror )
1108 : )
1109 : {
1110 0 : pData->bMirrorMode = bMirror;
1111 0 : if( !!pData->aImage )
1112 0 : pData->aImage = ImplMirrorImage( pData->aImage );
1113 : }
1114 : }
1115 0 : }
1116 :
1117 1336 : Image Menu::GetItemImage( sal_uInt16 nItemId ) const
1118 : {
1119 1336 : MenuItemData* pData = pItemList->GetData( nItemId );
1120 :
1121 1336 : if ( pData )
1122 1336 : return pData->aImage;
1123 : else
1124 0 : return Image();
1125 : }
1126 :
1127 511562 : void Menu::SetItemCommand( sal_uInt16 nItemId, const OUString& rCommand )
1128 : {
1129 : size_t nPos;
1130 511562 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1131 :
1132 511562 : if ( pData )
1133 511562 : pData->aCommandStr = rCommand;
1134 511562 : }
1135 :
1136 573531 : OUString Menu::GetItemCommand( sal_uInt16 nItemId ) const
1137 : {
1138 573531 : MenuItemData* pData = pItemList->GetData( nItemId );
1139 :
1140 573531 : if (pData)
1141 573531 : return pData->aCommandStr;
1142 :
1143 0 : return OUString();
1144 : }
1145 :
1146 130936 : void Menu::SetHelpCommand( sal_uInt16 nItemId, const OUString& rStr )
1147 : {
1148 130936 : MenuItemData* pData = pItemList->GetData( nItemId );
1149 :
1150 130936 : if ( pData )
1151 130936 : pData->aHelpCommandStr = rStr;
1152 130936 : }
1153 :
1154 113008 : OUString Menu::GetHelpCommand( sal_uInt16 nItemId ) const
1155 : {
1156 113008 : MenuItemData* pData = pItemList->GetData( nItemId );
1157 :
1158 113008 : if ( pData )
1159 113008 : return pData->aHelpCommandStr;
1160 :
1161 0 : return OUString();
1162 : }
1163 :
1164 27588 : void Menu::SetHelpText( sal_uInt16 nItemId, const OUString& rStr )
1165 : {
1166 27588 : MenuItemData* pData = pItemList->GetData( nItemId );
1167 :
1168 27588 : if ( pData )
1169 27588 : pData->aHelpText = rStr;
1170 27588 : }
1171 :
1172 412 : OUString Menu::ImplGetHelpText( sal_uInt16 nItemId ) const
1173 : {
1174 412 : MenuItemData* pData = pItemList->GetData( nItemId );
1175 :
1176 1236 : if ( pData && pData->aHelpText.isEmpty() &&
1177 824 : (( !pData->aHelpId.isEmpty() ) || ( !pData->aCommandStr.isEmpty() )))
1178 : {
1179 412 : Help* pHelp = Application::GetHelp();
1180 412 : if ( pHelp )
1181 : {
1182 412 : if (!pData->aCommandStr.isEmpty())
1183 412 : pData->aHelpText = pHelp->GetHelpText( pData->aCommandStr, NULL );
1184 412 : if (pData->aHelpText.isEmpty() && !pData->aHelpId.isEmpty())
1185 0 : pData->aHelpText = pHelp->GetHelpText( OStringToOUString( pData->aHelpId, RTL_TEXTENCODING_UTF8 ), NULL );
1186 : }
1187 : }
1188 :
1189 412 : return OUString();
1190 : }
1191 :
1192 412 : OUString Menu::GetHelpText( sal_uInt16 nItemId ) const
1193 : {
1194 412 : return ImplGetHelpText( nItemId );
1195 : }
1196 :
1197 0 : void Menu::SetTipHelpText( sal_uInt16 nItemId, const OUString& rStr )
1198 : {
1199 0 : MenuItemData* pData = pItemList->GetData( nItemId );
1200 :
1201 0 : if ( pData )
1202 0 : pData->aTipHelpText = rStr;
1203 0 : }
1204 :
1205 4 : OUString Menu::GetTipHelpText( sal_uInt16 nItemId ) const
1206 : {
1207 4 : MenuItemData* pData = pItemList->GetData( nItemId );
1208 :
1209 4 : if ( pData )
1210 4 : return pData->aTipHelpText;
1211 :
1212 0 : return OUString();
1213 : }
1214 :
1215 19466 : void Menu::SetHelpId( sal_uInt16 nItemId, const OString& rHelpId )
1216 : {
1217 19466 : MenuItemData* pData = pItemList->GetData( nItemId );
1218 :
1219 19466 : if ( pData )
1220 19464 : pData->aHelpId = rHelpId;
1221 19466 : }
1222 :
1223 0 : OString Menu::GetHelpId( sal_uInt16 nItemId ) const
1224 : {
1225 0 : OString aRet;
1226 :
1227 0 : MenuItemData* pData = pItemList->GetData( nItemId );
1228 :
1229 0 : if ( pData )
1230 : {
1231 0 : if ( !pData->aHelpId.isEmpty() )
1232 0 : aRet = pData->aHelpId;
1233 : else
1234 0 : aRet = OUStringToOString( pData->aCommandStr, RTL_TEXTENCODING_UTF8 );
1235 : }
1236 :
1237 0 : return aRet;
1238 : }
1239 :
1240 1494 : Menu& Menu::operator=( const Menu& rMenu )
1241 : {
1242 : // clean up
1243 1494 : Clear();
1244 :
1245 : // copy items
1246 1494 : sal_uInt16 nCount = rMenu.GetItemCount();
1247 23904 : for ( sal_uInt16 i = 0; i < nCount; i++ )
1248 22410 : ImplCopyItem( this, rMenu, i, MENU_APPEND, 1 );
1249 :
1250 1494 : nDefaultItem = rMenu.nDefaultItem;
1251 1494 : aActivateHdl = rMenu.aActivateHdl;
1252 1494 : aDeactivateHdl = rMenu.aDeactivateHdl;
1253 1494 : aHighlightHdl = rMenu.aHighlightHdl;
1254 1494 : aSelectHdl = rMenu.aSelectHdl;
1255 1494 : aTitleText = rMenu.aTitleText;
1256 :
1257 1494 : return *this;
1258 : }
1259 :
1260 48275 : bool Menu::ImplIsVisible( sal_uInt16 nPos ) const
1261 : {
1262 48275 : bool bVisible = true;
1263 :
1264 48275 : MenuItemData* pData = pItemList->GetDataFromPos( nPos );
1265 : // check general visibility first
1266 48275 : if( pData && !pData->bVisible )
1267 0 : bVisible = false;
1268 :
1269 48275 : if ( bVisible && pData && pData->eType == MenuItemType::SEPARATOR )
1270 : {
1271 298 : if( nPos == 0 ) // no separator should be shown at the very beginning
1272 0 : bVisible = false;
1273 : else
1274 : {
1275 : // always avoid adjacent separators
1276 298 : size_t nCount = pItemList->size();
1277 : size_t n;
1278 298 : MenuItemData* pNextData = NULL;
1279 : // search next visible item
1280 298 : for( n = nPos + 1; n < nCount; n++ )
1281 : {
1282 298 : pNextData = pItemList->GetDataFromPos( n );
1283 298 : if( pNextData && pNextData->bVisible )
1284 : {
1285 298 : if( pNextData->eType == MenuItemType::SEPARATOR || ImplIsVisible(n) )
1286 298 : break;
1287 : }
1288 : }
1289 298 : if( n == nCount ) // no next visible item
1290 0 : bVisible = false;
1291 : // check for separator
1292 298 : if( pNextData && pNextData->bVisible && pNextData->eType == MenuItemType::SEPARATOR )
1293 0 : bVisible = false;
1294 :
1295 298 : if( bVisible )
1296 : {
1297 298 : for( n = nPos; n > 0; n-- )
1298 : {
1299 298 : pNextData = pItemList->GetDataFromPos( n-1 );
1300 298 : if( pNextData && pNextData->bVisible )
1301 : {
1302 298 : if( pNextData->eType != MenuItemType::SEPARATOR && ImplIsVisible(n-1) )
1303 298 : break;
1304 : }
1305 : }
1306 298 : if( n == 0 ) // no previous visible item
1307 0 : bVisible = false;
1308 : }
1309 : }
1310 : }
1311 :
1312 : // not allowed for menubar, as I do not know
1313 : // whether a menu-entry will disappear or will appear
1314 48275 : if (bVisible && !IsMenuBar() && (nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES) &&
1315 0 : !(nMenuFlags & MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES))
1316 : {
1317 0 : if( !pData ) // e.g. nPos == ITEMPOS_INVALID
1318 0 : bVisible = false;
1319 0 : else if ( pData->eType != MenuItemType::SEPARATOR ) // separators handled above
1320 : {
1321 : // bVisible = pData->bEnabled && ( !pData->pSubMenu || pData->pSubMenu->HasValidEntries( true ) );
1322 0 : bVisible = pData->bEnabled; // do not check submenus as they might be filled at Activate().
1323 : }
1324 : }
1325 :
1326 48275 : return bVisible;
1327 : }
1328 :
1329 8844 : bool Menu::IsItemPosVisible( sal_uInt16 nItemPos ) const
1330 : {
1331 8844 : return IsMenuVisible() && ImplIsVisible( nItemPos );
1332 : }
1333 :
1334 8916 : bool Menu::IsMenuVisible() const
1335 : {
1336 8916 : return pWindow && pWindow->IsReallyVisible();
1337 : }
1338 :
1339 0 : bool Menu::ImplIsSelectable( sal_uInt16 nPos ) const
1340 : {
1341 0 : bool bSelectable = true;
1342 :
1343 0 : MenuItemData* pData = pItemList->GetDataFromPos( nPos );
1344 : // check general visibility first
1345 0 : if ( pData && ( pData->nBits & MenuItemBits::NOSELECT ) )
1346 0 : bSelectable = false;
1347 :
1348 0 : return bSelectable;
1349 : }
1350 :
1351 6482 : ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > Menu::GetAccessible()
1352 : {
1353 : // Since PopupMenu are sometimes shared by different instances of MenuBar, the mxAccessible member gets
1354 : // overwritten and may contain a disposed object when the initial menubar gets set again. So use the
1355 : // mxAccessible member only for sub menus.
1356 6482 : if ( pStartedFrom )
1357 : {
1358 4552 : for ( sal_uInt16 i = 0, nCount = pStartedFrom->GetItemCount(); i < nCount; ++i )
1359 : {
1360 4552 : sal_uInt16 nItemId = pStartedFrom->GetItemId( i );
1361 4552 : if ( static_cast< Menu* >( pStartedFrom->GetPopupMenu( nItemId ) ) == this )
1362 : {
1363 1520 : ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xParent = pStartedFrom->GetAccessible();
1364 1520 : if ( xParent.is() )
1365 : {
1366 1520 : ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
1367 1520 : if ( xParentContext.is() )
1368 1520 : return xParentContext->getAccessibleChild( i );
1369 0 : }
1370 : }
1371 : }
1372 : }
1373 4962 : else if ( !mxAccessible.is() )
1374 : {
1375 50 : UnoWrapperBase* pWrapper = Application::GetUnoWrapper();
1376 50 : if ( pWrapper )
1377 50 : mxAccessible = pWrapper->CreateAccessible(this, IsMenuBar());
1378 : }
1379 :
1380 4962 : return mxAccessible;
1381 : }
1382 :
1383 526 : void Menu::SetAccessible( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible )
1384 : {
1385 526 : mxAccessible = rxAccessible;
1386 526 : }
1387 :
1388 7633 : Size Menu::ImplGetNativeCheckAndRadioSize( const vcl::Window* pWin, long& rCheckHeight, long& rRadioHeight ) const
1389 : {
1390 7633 : long nCheckWidth = 0, nRadioWidth = 0;
1391 7633 : rCheckHeight = rRadioHeight = 0;
1392 :
1393 7633 : if (!IsMenuBar())
1394 : {
1395 32 : ImplControlValue aVal;
1396 32 : Rectangle aNativeBounds;
1397 32 : Rectangle aNativeContent;
1398 32 : Point tmp( 0, 0 );
1399 32 : Rectangle aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) );
1400 32 : if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_CHECK_MARK ) )
1401 : {
1402 0 : if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
1403 : ControlPart(PART_MENU_ITEM_CHECK_MARK),
1404 : aCtrlRegion,
1405 : ControlState(CTRL_STATE_ENABLED),
1406 : aVal,
1407 : OUString(),
1408 : aNativeBounds,
1409 0 : aNativeContent )
1410 : )
1411 : {
1412 0 : rCheckHeight = aNativeBounds.GetHeight();
1413 0 : nCheckWidth = aNativeContent.GetWidth();
1414 : }
1415 : }
1416 32 : if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_RADIO_MARK ) )
1417 : {
1418 0 : if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
1419 : ControlPart(PART_MENU_ITEM_RADIO_MARK),
1420 : aCtrlRegion,
1421 : ControlState(CTRL_STATE_ENABLED),
1422 : aVal,
1423 : OUString(),
1424 : aNativeBounds,
1425 0 : aNativeContent )
1426 : )
1427 : {
1428 0 : rRadioHeight = aNativeBounds.GetHeight();
1429 0 : nRadioWidth = aNativeContent.GetWidth();
1430 : }
1431 32 : }
1432 : }
1433 7633 : return Size(std::max(nCheckWidth, nRadioWidth), std::max(rCheckHeight, rRadioHeight));
1434 : }
1435 :
1436 0 : bool Menu::ImplGetNativeSubmenuArrowSize( vcl::Window* pWin, Size& rArrowSize, long& rArrowSpacing ) const
1437 : {
1438 0 : ImplControlValue aVal;
1439 0 : Rectangle aNativeBounds;
1440 0 : Rectangle aNativeContent;
1441 0 : Point tmp( 0, 0 );
1442 0 : Rectangle aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) );
1443 0 : if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
1444 0 : PART_MENU_SUBMENU_ARROW ) )
1445 : {
1446 0 : if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
1447 : ControlPart(PART_MENU_SUBMENU_ARROW),
1448 : aCtrlRegion,
1449 : ControlState(CTRL_STATE_ENABLED),
1450 : aVal,
1451 : OUString(),
1452 : aNativeBounds,
1453 0 : aNativeContent )
1454 : )
1455 : {
1456 : Size aSize( Size ( aNativeContent.GetWidth(),
1457 0 : aNativeContent.GetHeight() ) );
1458 0 : rArrowSize = aSize;
1459 0 : rArrowSpacing = aNativeBounds.GetWidth() - aNativeContent.GetWidth();
1460 :
1461 0 : return true;
1462 : }
1463 : }
1464 0 : return false;
1465 : }
1466 :
1467 836149 : void Menu::ImplAddDel( ImplMenuDelData& rDel )
1468 : {
1469 : DBG_ASSERT( !rDel.mpMenu, "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !" );
1470 836149 : if( !rDel.mpMenu )
1471 : {
1472 836149 : rDel.mpMenu = this;
1473 836149 : rDel.mpNext = mpFirstDel;
1474 836149 : mpFirstDel = &rDel;
1475 : }
1476 836149 : }
1477 :
1478 836149 : void Menu::ImplRemoveDel( ImplMenuDelData& rDel )
1479 : {
1480 836149 : rDel.mpMenu = NULL;
1481 836149 : if ( mpFirstDel == &rDel )
1482 : {
1483 836149 : mpFirstDel = rDel.mpNext;
1484 : }
1485 : else
1486 : {
1487 0 : ImplMenuDelData* pData = mpFirstDel;
1488 0 : while ( pData && (pData->mpNext != &rDel) )
1489 0 : pData = pData->mpNext;
1490 :
1491 : DBG_ASSERT( pData, "Menu::ImplRemoveDel(): ImplMenuDelData not registered !" );
1492 0 : if( pData )
1493 0 : pData->mpNext = rDel.mpNext;
1494 : }
1495 836149 : }
1496 :
1497 5832 : Size Menu::ImplCalcSize( const vcl::Window* pWin )
1498 : {
1499 : // | Check/Radio/Image| Text| Accel/Popup|
1500 :
1501 : // for symbols: nFontHeight x nFontHeight
1502 5832 : long nFontHeight = pWin->GetTextHeight();
1503 5832 : long nExtra = nFontHeight/4;
1504 :
1505 5832 : long nMinMenuItemHeight = nFontHeight;
1506 5832 : long nCheckHeight = 0, nRadioHeight = 0;
1507 5832 : Size aMaxSize = ImplGetNativeCheckAndRadioSize(pWin, nCheckHeight, nRadioHeight);
1508 5832 : if( aMaxSize.Height() > nMinMenuItemHeight )
1509 0 : nMinMenuItemHeight = aMaxSize.Height();
1510 :
1511 5832 : Size aMaxImgSz;
1512 :
1513 5832 : const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
1514 5832 : if ( rSettings.GetUseImagesInMenus() )
1515 : {
1516 5832 : if ( 16 > nMinMenuItemHeight )
1517 5832 : nMinMenuItemHeight = 16;
1518 26926 : for ( size_t i = pItemList->size(); i; )
1519 : {
1520 15278 : MenuItemData* pData = pItemList->GetDataFromPos( --i );
1521 30556 : if ( ImplIsVisible( i )
1522 15294 : && ( ( pData->eType == MenuItemType::IMAGE )
1523 15278 : || ( pData->eType == MenuItemType::STRINGIMAGE )
1524 : )
1525 : )
1526 : {
1527 16 : Size aImgSz = pData->aImage.GetSizePixel();
1528 16 : if ( aImgSz.Height() > aMaxImgSz.Height() )
1529 16 : aMaxImgSz.Height() = aImgSz.Height();
1530 16 : if ( aImgSz.Height() > nMinMenuItemHeight )
1531 0 : nMinMenuItemHeight = aImgSz.Height();
1532 16 : break;
1533 : }
1534 : }
1535 : }
1536 :
1537 5832 : Size aSz;
1538 5832 : long nCheckWidth = 0;
1539 5832 : long nMaxWidth = 0;
1540 :
1541 27376 : for ( size_t n = pItemList->size(); n; )
1542 : {
1543 15712 : MenuItemData* pData = pItemList->GetDataFromPos( --n );
1544 :
1545 15712 : pData->aSz.Height() = 0;
1546 15712 : pData->aSz.Width() = 0;
1547 :
1548 15712 : if ( ImplIsVisible( n ) )
1549 : {
1550 15712 : long nWidth = 0;
1551 :
1552 : // Separator
1553 15712 : if (!IsMenuBar()&& (pData->eType == MenuItemType::SEPARATOR))
1554 : {
1555 : DBG_ASSERT( !IsMenuBar(), "Separator in MenuBar ?! " );
1556 84 : pData->aSz.Height() = 4;
1557 : }
1558 :
1559 : // Image:
1560 15712 : if (!IsMenuBar()&& ((pData->eType == MenuItemType::IMAGE) || (pData->eType == MenuItemType::STRINGIMAGE)))
1561 : {
1562 188 : Size aImgSz = pData->aImage.GetSizePixel();
1563 188 : aImgSz.Height() += 4; // add a border for native marks
1564 188 : aImgSz.Width() += 4; // add a border for native marks
1565 188 : if ( aImgSz.Width() > aMaxImgSz.Width() )
1566 16 : aMaxImgSz.Width() = aImgSz.Width();
1567 188 : if ( aImgSz.Height() > aMaxImgSz.Height() )
1568 16 : aMaxImgSz.Height() = aImgSz.Height();
1569 188 : if ( aImgSz.Height() > pData->aSz.Height() )
1570 188 : pData->aSz.Height() = aImgSz.Height();
1571 : }
1572 :
1573 : // Check Buttons:
1574 15712 : if (!IsMenuBar() && pData->HasCheck())
1575 : {
1576 98 : nCheckWidth = aMaxSize.Width();
1577 : // checks / images take the same place
1578 98 : if( ! ( ( pData->eType == MenuItemType::IMAGE ) || ( pData->eType == MenuItemType::STRINGIMAGE ) ) )
1579 30 : nWidth += nCheckWidth + nExtra * 2;
1580 : }
1581 :
1582 : // Text:
1583 15712 : if ( (pData->eType == MenuItemType::STRING) || (pData->eType == MenuItemType::STRINGIMAGE) )
1584 : {
1585 15628 : long nTextWidth = pWin->GetCtrlTextWidth( pData->aText );
1586 15628 : long nTextHeight = pWin->GetTextHeight();
1587 :
1588 15628 : if (IsMenuBar())
1589 : {
1590 15256 : if ( nTextHeight > pData->aSz.Height() )
1591 15256 : pData->aSz.Height() = nTextHeight;
1592 :
1593 15256 : pData->aSz.Width() = nTextWidth + 4*nExtra;
1594 15256 : aSz.Width() += pData->aSz.Width();
1595 : }
1596 : else
1597 372 : pData->aSz.Height() = std::max( std::max( nTextHeight, pData->aSz.Height() ), nMinMenuItemHeight );
1598 :
1599 15628 : nWidth += nTextWidth;
1600 : }
1601 :
1602 : // Accel
1603 15712 : if (!IsMenuBar()&& pData->aAccelKey.GetCode() && !ImplAccelDisabled())
1604 : {
1605 0 : OUString aName = pData->aAccelKey.GetName();
1606 0 : long nAccWidth = pWin->GetTextWidth( aName );
1607 0 : nAccWidth += nExtra;
1608 0 : nWidth += nAccWidth;
1609 : }
1610 :
1611 : // SubMenu?
1612 15712 : if (!IsMenuBar() && pData->pSubMenu)
1613 : {
1614 42 : if ( nFontHeight > nWidth )
1615 0 : nWidth += nFontHeight;
1616 :
1617 42 : pData->aSz.Height() = std::max( std::max( nFontHeight, pData->aSz.Height() ), nMinMenuItemHeight );
1618 : }
1619 :
1620 15712 : pData->aSz.Height() += EXTRAITEMHEIGHT; // little bit more distance
1621 :
1622 15712 : if (!IsMenuBar())
1623 456 : aSz.Height() += (long)pData->aSz.Height();
1624 :
1625 15712 : if ( nWidth > nMaxWidth )
1626 3332 : nMaxWidth = nWidth;
1627 :
1628 : }
1629 : }
1630 :
1631 5832 : if (!IsMenuBar())
1632 : {
1633 : // popup menus should not be wider than half the screen
1634 : // except on rather small screens
1635 : // TODO: move GetScreenNumber from SystemWindow to Window ?
1636 : // currently we rely on internal privileges
1637 16 : unsigned int nDisplayScreen = pWin->ImplGetWindowImpl()->mpFrame->maGeometry.nDisplayScreenNumber;
1638 16 : Rectangle aDispRect( Application::GetScreenPosSizePixel( nDisplayScreen ) );
1639 16 : long nScreenWidth = aDispRect.GetWidth() >= 800 ? aDispRect.GetWidth() : 800;
1640 16 : if( nMaxWidth > nScreenWidth/2 )
1641 0 : nMaxWidth = nScreenWidth/2;
1642 :
1643 16 : sal_uInt16 gfxExtra = (sal_uInt16) std::max( nExtra, 7L ); // #107710# increase space between checkmarks/images/text
1644 16 : nImgOrChkPos = (sal_uInt16)nExtra;
1645 16 : long nImgOrChkWidth = 0;
1646 16 : if( aMaxSize.Height() > 0 ) // NWF case
1647 0 : nImgOrChkWidth = aMaxSize.Height() + nExtra;
1648 : else // non NWF case
1649 16 : nImgOrChkWidth = nFontHeight/2 + gfxExtra;
1650 16 : nImgOrChkWidth = std::max( nImgOrChkWidth, aMaxImgSz.Width() + gfxExtra );
1651 16 : nTextPos = (sal_uInt16)(nImgOrChkPos + nImgOrChkWidth);
1652 16 : nTextPos = nTextPos + gfxExtra;
1653 :
1654 16 : aSz.Width() = nTextPos + nMaxWidth + nExtra;
1655 16 : aSz.Width() += 4*nExtra; // a _little_ more ...
1656 :
1657 16 : aSz.Width() += 2*ImplGetSVData()->maNWFData.mnMenuFormatBorderX;
1658 16 : aSz.Height() += 2*ImplGetSVData()->maNWFData.mnMenuFormatBorderY;
1659 : }
1660 : else
1661 : {
1662 5816 : nTextPos = (sal_uInt16)(2*nExtra);
1663 5816 : aSz.Height() = nFontHeight+6;
1664 :
1665 : // get menubar height from native methods if supported
1666 5816 : if( pWindow->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
1667 : {
1668 0 : ImplControlValue aVal;
1669 0 : Rectangle aNativeBounds;
1670 0 : Rectangle aNativeContent;
1671 0 : Point tmp( 0, 0 );
1672 0 : Rectangle aCtrlRegion( tmp, Size( 100, 15 ) );
1673 0 : if( pWindow->GetNativeControlRegion( ControlType(CTRL_MENUBAR),
1674 : ControlPart(PART_ENTIRE_CONTROL),
1675 : aCtrlRegion,
1676 : ControlState(CTRL_STATE_ENABLED),
1677 : aVal,
1678 : OUString(),
1679 : aNativeBounds,
1680 0 : aNativeContent )
1681 : )
1682 : {
1683 0 : int nNativeHeight = aNativeBounds.GetHeight();
1684 0 : if( nNativeHeight > aSz.Height() )
1685 0 : aSz.Height() = nNativeHeight;
1686 0 : }
1687 : }
1688 :
1689 : // account for the size of the close button, which actually is a toolbox
1690 : // due to NWF this is variable
1691 5816 : long nCloseButtonHeight = static_cast<MenuBarWindow*>(pWindow)->MinCloseButtonSize().Height();
1692 5816 : if (aSz.Height() < nCloseButtonHeight)
1693 0 : aSz.Height() = nCloseButtonHeight;
1694 : }
1695 :
1696 5832 : if ( pLogo )
1697 0 : aSz.Width() += pLogo->aBitmap.GetSizePixel().Width();
1698 :
1699 5832 : return aSz;
1700 : }
1701 :
1702 32 : static void ImplPaintCheckBackground( vcl::Window* i_pWindow, const Rectangle& i_rRect, bool i_bHighlight )
1703 : {
1704 32 : bool bNativeOk = false;
1705 32 : if( i_pWindow->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) )
1706 : {
1707 0 : ImplControlValue aControlValue;
1708 0 : Rectangle aCtrlRegion( i_rRect );
1709 0 : ControlState nState = CTRL_STATE_PRESSED | CTRL_STATE_ENABLED;
1710 :
1711 0 : aControlValue.setTristateVal( BUTTONVALUE_ON );
1712 :
1713 : bNativeOk = i_pWindow->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON,
1714 : aCtrlRegion, nState, aControlValue,
1715 0 : OUString() );
1716 : }
1717 :
1718 32 : if( ! bNativeOk )
1719 : {
1720 32 : const StyleSettings& rSettings = i_pWindow->GetSettings().GetStyleSettings();
1721 32 : Color aColor( i_bHighlight ? rSettings.GetMenuHighlightTextColor() : rSettings.GetHighlightColor() );
1722 32 : i_pWindow->DrawSelectionBackground( i_rRect, 0, i_bHighlight, true, false, 2, NULL, &aColor );
1723 : }
1724 32 : }
1725 :
1726 15305 : static OUString getShortenedString( const OUString& i_rLong, vcl::Window* i_pWin, long i_nMaxWidth )
1727 : {
1728 15305 : sal_Int32 nPos = -1;
1729 15305 : OUString aNonMnem( OutputDevice::GetNonMnemonicString( i_rLong, nPos ) );
1730 15305 : aNonMnem = i_pWin->GetEllipsisString( aNonMnem, i_nMaxWidth, TEXT_DRAW_CENTERELLIPSIS );
1731 : // re-insert mnemonic
1732 15305 : if( nPos != -1 )
1733 : {
1734 15280 : if( nPos < aNonMnem.getLength() && i_rLong[nPos+1] == aNonMnem[nPos] )
1735 : {
1736 15280 : OUStringBuffer aBuf( i_rLong.getLength() );
1737 15280 : aBuf.append( aNonMnem.copy( 0, nPos) );
1738 15280 : aBuf.append( '~' );
1739 15280 : aBuf.append( aNonMnem.copy(nPos) );
1740 15280 : aNonMnem = aBuf.makeStringAndClear();
1741 : }
1742 : }
1743 15305 : return aNonMnem;
1744 : }
1745 :
1746 1801 : void Menu::ImplPaint( vcl::Window* pWin, sal_uInt16 nBorder, long nStartY, MenuItemData* pThisItemOnly, bool bHighlighted, bool bLayout, bool bRollover ) const
1747 : {
1748 : // for symbols: nFontHeight x nFontHeight
1749 1801 : long nFontHeight = pWin->GetTextHeight();
1750 1801 : long nExtra = nFontHeight/4;
1751 :
1752 1801 : long nCheckHeight = 0, nRadioHeight = 0;
1753 1801 : ImplGetNativeCheckAndRadioSize( pWin, nCheckHeight, nRadioHeight );
1754 :
1755 1801 : DecorationView aDecoView( pWin );
1756 1801 : const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
1757 :
1758 1801 : Point aTopLeft, aTmpPos;
1759 :
1760 1801 : if ( pLogo )
1761 0 : aTopLeft.X() = pLogo->aBitmap.GetSizePixel().Width();
1762 :
1763 1801 : int nOuterSpaceX = 0;
1764 1801 : if (!IsMenuBar())
1765 : {
1766 16 : nOuterSpaceX = ImplGetSVData()->maNWFData.mnMenuFormatBorderX;
1767 16 : aTopLeft.X() += nOuterSpaceX;
1768 16 : aTopLeft.Y() += ImplGetSVData()->maNWFData.mnMenuFormatBorderY;
1769 : }
1770 :
1771 1801 : Size aOutSz = pWin->GetOutputSizePixel();
1772 1801 : size_t nCount = pItemList->size();
1773 1801 : if( bLayout )
1774 4 : mpLayoutData->m_aVisibleItemBoundRects.clear();
1775 :
1776 17558 : for ( size_t n = 0; n < nCount; n++ )
1777 : {
1778 15757 : MenuItemData* pData = pItemList->GetDataFromPos( n );
1779 15757 : if ( ImplIsVisible( n ) && ( !pThisItemOnly || ( pData == pThisItemOnly ) ) )
1780 : {
1781 15389 : if ( pThisItemOnly )
1782 : {
1783 46 : if (IsMenuBar()&& bRollover )
1784 0 : pWin->SetTextColor( rSettings.GetMenuBarRolloverTextColor() );
1785 46 : else if ( bHighlighted )
1786 30 : pWin->SetTextColor( rSettings.GetMenuHighlightTextColor() );
1787 : }
1788 :
1789 15389 : Point aPos( aTopLeft );
1790 15389 : aPos.Y() += nBorder;
1791 15389 : aPos.Y() += nStartY;
1792 :
1793 15389 : if ( aPos.Y() >= 0 )
1794 : {
1795 15389 : long nTextOffsetY = ((pData->aSz.Height()-nFontHeight)/2);
1796 15389 : if (IsMenuBar())
1797 14933 : nTextOffsetY += (aOutSz.Height()-pData->aSz.Height()) / 2;
1798 15389 : sal_uInt16 nTextStyle = 0;
1799 15389 : sal_uInt16 nSymbolStyle = 0;
1800 15389 : sal_uInt16 nImageStyle = 0;
1801 :
1802 : // submenus without items are not disabled when no items are
1803 : // contained. The application itself should check for this!
1804 : // Otherwise it could happen entries are disabled due to
1805 : // asynchronous loading
1806 15389 : if ( !pData->bEnabled )
1807 : {
1808 172 : nTextStyle |= TEXT_DRAW_DISABLE;
1809 172 : nSymbolStyle |= SYMBOL_DRAW_DISABLE;
1810 172 : nImageStyle |= IMAGE_DRAW_DISABLE;
1811 : }
1812 :
1813 : // Separator
1814 15389 : if (!bLayout && !IsMenuBar() && (pData->eType == MenuItemType::SEPARATOR))
1815 : {
1816 76 : bool bNativeOk = false;
1817 76 : if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
1818 76 : PART_MENU_SEPARATOR ) )
1819 : {
1820 0 : ControlState nState = 0;
1821 0 : if ( pData->bEnabled )
1822 0 : nState |= CTRL_STATE_ENABLED;
1823 0 : if ( bHighlighted )
1824 0 : nState |= CTRL_STATE_SELECTED;
1825 0 : Size aSz( pData->aSz );
1826 0 : aSz.Width() = aOutSz.Width() - 2*nOuterSpaceX;
1827 0 : Rectangle aItemRect( aPos, aSz );
1828 0 : MenupopupValue aVal( nTextPos-GUTTERBORDER, aItemRect );
1829 : bNativeOk = pWin->DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_SEPARATOR,
1830 : aItemRect,
1831 : nState,
1832 : aVal,
1833 0 : OUString() );
1834 : }
1835 76 : if( ! bNativeOk )
1836 : {
1837 76 : aTmpPos.Y() = aPos.Y() + ((pData->aSz.Height()-2)/2);
1838 76 : aTmpPos.X() = aPos.X() + 2 + nOuterSpaceX;
1839 76 : pWin->SetLineColor( rSettings.GetShadowColor() );
1840 76 : pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpaceX, aTmpPos.Y() ) );
1841 76 : aTmpPos.Y()++;
1842 76 : pWin->SetLineColor( rSettings.GetLightColor() );
1843 76 : pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpaceX, aTmpPos.Y() ) );
1844 76 : pWin->SetLineColor();
1845 : }
1846 : }
1847 :
1848 15389 : Rectangle aOuterCheckRect( Point( aPos.X()+nImgOrChkPos, aPos.Y() ), Size( pData->aSz.Height(), pData->aSz.Height() ) );
1849 15389 : aOuterCheckRect.Left() += 1;
1850 15389 : aOuterCheckRect.Right() -= 1;
1851 15389 : aOuterCheckRect.Top() += 1;
1852 15389 : aOuterCheckRect.Bottom() -= 1;
1853 :
1854 : // CheckMark
1855 15389 : if (!bLayout && !IsMenuBar() && pData->HasCheck())
1856 : {
1857 : // draw selection transparent marker if checked
1858 : // onto that either a checkmark or the item image
1859 : // will be painted
1860 : // however do not do this if native checks will be painted since
1861 : // the selection color too often does not fit the theme's check and/or radio
1862 :
1863 72 : if( ! ( ( pData->eType == MenuItemType::IMAGE ) || ( pData->eType == MenuItemType::STRINGIMAGE ) ) )
1864 : {
1865 40 : if ( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
1866 40 : (pData->nBits & MenuItemBits::RADIOCHECK)
1867 : ? PART_MENU_ITEM_CHECK_MARK
1868 20 : : PART_MENU_ITEM_RADIO_MARK ) )
1869 : {
1870 0 : ControlPart nPart = ((pData->nBits & MenuItemBits::RADIOCHECK)
1871 : ? PART_MENU_ITEM_RADIO_MARK
1872 0 : : PART_MENU_ITEM_CHECK_MARK);
1873 :
1874 0 : ControlState nState = 0;
1875 :
1876 0 : if ( pData->bChecked )
1877 0 : nState |= CTRL_STATE_PRESSED;
1878 :
1879 0 : if ( pData->bEnabled )
1880 0 : nState |= CTRL_STATE_ENABLED;
1881 :
1882 0 : if ( bHighlighted )
1883 0 : nState |= CTRL_STATE_SELECTED;
1884 :
1885 0 : long nCtrlHeight = (pData->nBits & MenuItemBits::RADIOCHECK) ? nCheckHeight : nRadioHeight;
1886 0 : aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - nCtrlHeight)/2;
1887 0 : aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - nCtrlHeight)/2;
1888 :
1889 0 : Rectangle aCheckRect( aTmpPos, Size( nCtrlHeight, nCtrlHeight ) );
1890 0 : Size aSz( pData->aSz );
1891 0 : aSz.Width() = aOutSz.Width() - 2*nOuterSpaceX;
1892 0 : Rectangle aItemRect( aPos, aSz );
1893 0 : MenupopupValue aVal( nTextPos-GUTTERBORDER, aItemRect );
1894 : pWin->DrawNativeControl( CTRL_MENU_POPUP, nPart,
1895 : aCheckRect,
1896 : nState,
1897 : aVal,
1898 0 : OUString() );
1899 : }
1900 20 : else if ( pData->bChecked ) // by default do nothing for unchecked items
1901 : {
1902 20 : ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted );
1903 :
1904 : SymbolType eSymbol;
1905 20 : Size aSymbolSize;
1906 20 : if ( pData->nBits & MenuItemBits::RADIOCHECK )
1907 : {
1908 0 : eSymbol = SymbolType::RADIOCHECKMARK;
1909 0 : aSymbolSize = Size( nFontHeight/2, nFontHeight/2 );
1910 : }
1911 : else
1912 : {
1913 20 : eSymbol = SymbolType::CHECKMARK;
1914 20 : aSymbolSize = Size( (nFontHeight*25)/40, nFontHeight/2 );
1915 : }
1916 20 : aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - aSymbolSize.Width())/2;
1917 20 : aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - aSymbolSize.Height())/2;
1918 20 : Rectangle aRect( aTmpPos, aSymbolSize );
1919 20 : aDecoView.DrawSymbol( aRect, eSymbol, pWin->GetTextColor(), nSymbolStyle );
1920 : }
1921 : }
1922 : }
1923 :
1924 : // Image:
1925 15389 : if (!bLayout && !IsMenuBar() && ((pData->eType == MenuItemType::IMAGE) || (pData->eType == MenuItemType::STRINGIMAGE)))
1926 : {
1927 : // Don't render an image for a check thing
1928 172 : if( pData->bChecked )
1929 12 : ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted );
1930 172 : aTmpPos = aOuterCheckRect.TopLeft();
1931 172 : aTmpPos.X() += (aOuterCheckRect.GetWidth()-pData->aImage.GetSizePixel().Width())/2;
1932 172 : aTmpPos.Y() += (aOuterCheckRect.GetHeight()-pData->aImage.GetSizePixel().Height())/2;
1933 172 : pWin->DrawImage( aTmpPos, pData->aImage, nImageStyle );
1934 : }
1935 :
1936 : // Text:
1937 15389 : if ( ( pData->eType == MenuItemType::STRING ) || ( pData->eType == MenuItemType::STRINGIMAGE ) )
1938 : {
1939 15305 : aTmpPos.X() = aPos.X() + nTextPos;
1940 15305 : aTmpPos.Y() = aPos.Y();
1941 15305 : aTmpPos.Y() += nTextOffsetY;
1942 15305 : sal_uInt16 nStyle = nTextStyle|TEXT_DRAW_MNEMONIC;
1943 15305 : if ( pData->bIsTemporary )
1944 0 : nStyle |= TEXT_DRAW_DISABLE;
1945 15305 : MetricVector* pVector = bLayout ? &mpLayoutData->m_aUnicodeBoundRects : NULL;
1946 15305 : OUString* pDisplayText = bLayout ? &mpLayoutData->m_aDisplayText : NULL;
1947 15305 : if( bLayout )
1948 : {
1949 52 : mpLayoutData->m_aLineIndices.push_back( mpLayoutData->m_aDisplayText.getLength() );
1950 52 : mpLayoutData->m_aLineItemIds.push_back( pData->nId );
1951 52 : mpLayoutData->m_aLineItemPositions.push_back( n );
1952 : }
1953 : // #i47946# with NWF painted menus the background is transparent
1954 : // since DrawCtrlText can depend on the background (e.g. for
1955 : // TEXT_DRAW_DISABLE), temporarily set a background which
1956 : // hopefully matches the NWF background since it is read
1957 : // from the system style settings
1958 15305 : bool bSetTmpBackground = !pWin->IsBackground() && pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL );
1959 15305 : if( bSetTmpBackground )
1960 : {
1961 0 : Color aBg = IsMenuBar()?
1962 0 : pWin->GetSettings().GetStyleSettings().GetMenuBarColor() :
1963 0 : pWin->GetSettings().GetStyleSettings().GetMenuColor();
1964 0 : pWin->SetBackground( Wallpaper( aBg ) );
1965 : }
1966 : // how much space is there for the text ?
1967 15305 : long nMaxItemTextWidth = aOutSz.Width() - aTmpPos.X() - nExtra - nOuterSpaceX;
1968 15305 : if (!IsMenuBar() && pData->aAccelKey.GetCode() && !ImplAccelDisabled())
1969 : {
1970 0 : OUString aAccText = pData->aAccelKey.GetName();
1971 0 : nMaxItemTextWidth -= pWin->GetTextWidth( aAccText ) + 3*nExtra;
1972 : }
1973 15305 : if (!IsMenuBar() && pData->pSubMenu)
1974 : {
1975 42 : nMaxItemTextWidth -= nFontHeight - nExtra;
1976 : }
1977 15305 : OUString aItemText( getShortenedString( pData->aText, pWin, nMaxItemTextWidth ) );
1978 15305 : pWin->DrawCtrlText( aTmpPos, aItemText, 0, aItemText.getLength(), nStyle, pVector, pDisplayText );
1979 15305 : if( bSetTmpBackground )
1980 0 : pWin->SetBackground();
1981 : }
1982 :
1983 : // Accel
1984 15389 : if (!bLayout && !IsMenuBar() && pData->aAccelKey.GetCode() && !ImplAccelDisabled())
1985 : {
1986 0 : OUString aAccText = pData->aAccelKey.GetName();
1987 0 : aTmpPos.X() = aOutSz.Width() - pWin->GetTextWidth( aAccText );
1988 0 : aTmpPos.X() -= 4*nExtra;
1989 :
1990 0 : aTmpPos.X() -= nOuterSpaceX;
1991 0 : aTmpPos.Y() = aPos.Y();
1992 0 : aTmpPos.Y() += nTextOffsetY;
1993 0 : pWin->DrawCtrlText( aTmpPos, aAccText, 0, aAccText.getLength(), nTextStyle );
1994 : }
1995 :
1996 : // SubMenu?
1997 15389 : if (!bLayout && !IsMenuBar() && pData->pSubMenu)
1998 : {
1999 38 : bool bNativeOk = false;
2000 38 : if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
2001 38 : PART_MENU_SUBMENU_ARROW ) )
2002 : {
2003 0 : ControlState nState = 0;
2004 0 : Size aTmpSz( 0, 0 );
2005 0 : long aSpacing = 0;
2006 :
2007 0 : if( !ImplGetNativeSubmenuArrowSize( pWin,
2008 0 : aTmpSz, aSpacing ) )
2009 : {
2010 0 : aTmpSz = Size( nFontHeight, nFontHeight );
2011 0 : aSpacing = nOuterSpaceX;
2012 : }
2013 :
2014 0 : if ( pData->bEnabled )
2015 0 : nState |= CTRL_STATE_ENABLED;
2016 0 : if ( bHighlighted )
2017 0 : nState |= CTRL_STATE_SELECTED;
2018 :
2019 0 : aTmpPos.X() = aOutSz.Width() - aTmpSz.Width() - aSpacing - nOuterSpaceX;
2020 0 : aTmpPos.Y() = aPos.Y() + ( pData->aSz.Height() - aTmpSz.Height() ) / 2;
2021 0 : aTmpPos.Y() += nExtra/2;
2022 :
2023 0 : Rectangle aItemRect( aTmpPos, aTmpSz );
2024 0 : MenupopupValue aVal( nTextPos-GUTTERBORDER, aItemRect );
2025 : bNativeOk = pWin->DrawNativeControl( CTRL_MENU_POPUP,
2026 : PART_MENU_SUBMENU_ARROW,
2027 : aItemRect,
2028 : nState,
2029 : aVal,
2030 0 : OUString() );
2031 : }
2032 38 : if( ! bNativeOk )
2033 : {
2034 38 : aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpaceX;
2035 38 : aTmpPos.Y() = aPos.Y();
2036 38 : aTmpPos.Y() += nExtra/2;
2037 38 : aTmpPos.Y() += ( pData->aSz.Height() / 2 ) - ( nFontHeight/4 );
2038 38 : if ( pData->nBits & MenuItemBits::POPUPSELECT )
2039 : {
2040 0 : pWin->SetTextColor( rSettings.GetMenuTextColor() );
2041 0 : Point aTmpPos2( aPos );
2042 0 : aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4;
2043 : aDecoView.DrawFrame(
2044 0 : Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pData->aSz.Height() ) ), FRAME_DRAW_GROUP );
2045 : }
2046 : aDecoView.DrawSymbol(
2047 : Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ),
2048 38 : SymbolType::SPIN_RIGHT, pWin->GetTextColor(), nSymbolStyle );
2049 : }
2050 : }
2051 :
2052 15389 : if ( pThisItemOnly && bHighlighted )
2053 : {
2054 : // This restores the normal menu or menu bar text
2055 : // color for when it is no longer highlighted.
2056 30 : if (IsMenuBar())
2057 30 : pWin->SetTextColor( rSettings.GetMenuBarTextColor() );
2058 : else
2059 0 : pWin->SetTextColor( rSettings.GetMenuTextColor() );
2060 : }
2061 : }
2062 15389 : if( bLayout )
2063 : {
2064 60 : if (!IsMenuBar())
2065 42 : mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, Size( aOutSz.Width(), pData->aSz.Height() ) );
2066 : else
2067 18 : mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, pData->aSz );
2068 : }
2069 : }
2070 :
2071 15757 : if (!IsMenuBar())
2072 : {
2073 456 : aTopLeft.Y() += pData->aSz.Height();
2074 : }
2075 : else
2076 : {
2077 15301 : aTopLeft.X() += pData->aSz.Width();
2078 : }
2079 : }
2080 :
2081 1801 : if ( !bLayout && !pThisItemOnly && pLogo )
2082 : {
2083 0 : Size aLogoSz = pLogo->aBitmap.GetSizePixel();
2084 :
2085 0 : Rectangle aRect( Point( 0, 0 ), Point( aLogoSz.Width()-1, aOutSz.Height() ) );
2086 0 : if ( pWin->GetColorCount() >= 256 )
2087 : {
2088 0 : Gradient aGrad( GradientStyle_LINEAR, pLogo->aStartColor, pLogo->aEndColor );
2089 0 : aGrad.SetAngle( 1800 );
2090 0 : aGrad.SetBorder( 15 );
2091 0 : pWin->DrawGradient( aRect, aGrad );
2092 : }
2093 : else
2094 : {
2095 0 : pWin->SetFillColor( pLogo->aStartColor );
2096 0 : pWin->DrawRect( aRect );
2097 : }
2098 :
2099 0 : Point aLogoPos( 0, aOutSz.Height() - aLogoSz.Height() );
2100 0 : pLogo->aBitmap.Draw( pWin, aLogoPos );
2101 : }
2102 1801 : }
2103 :
2104 100 : Menu* Menu::ImplGetStartMenu()
2105 : {
2106 100 : Menu* pStart = this;
2107 216 : while ( pStart && pStart->pStartedFrom && ( pStart->pStartedFrom != pStart ) )
2108 16 : pStart = pStart->pStartedFrom;
2109 100 : return pStart;
2110 : }
2111 :
2112 52 : void Menu::ImplCallHighlight(sal_uInt16 nItem)
2113 : {
2114 52 : ImplMenuDelData aDelData( this );
2115 :
2116 52 : nSelectedId = 0;
2117 52 : MenuItemData* pData = pItemList->GetDataFromPos(nItem);
2118 52 : if ( pData )
2119 20 : nSelectedId = pData->nId;
2120 52 : ImplCallEventListeners( VCLEVENT_MENU_HIGHLIGHT, GetItemPos( GetCurItemId() ) );
2121 :
2122 52 : if( !aDelData.isDeleted() )
2123 : {
2124 52 : Highlight();
2125 52 : nSelectedId = 0;
2126 52 : }
2127 52 : }
2128 :
2129 0 : IMPL_LINK_NOARG(Menu, ImplCallSelect)
2130 : {
2131 0 : nEventId = 0;
2132 0 : Select();
2133 0 : return 0;
2134 : }
2135 :
2136 0 : Menu* Menu::ImplFindSelectMenu()
2137 : {
2138 0 : Menu* pSelMenu = nEventId ? this : NULL;
2139 :
2140 0 : for ( size_t n = GetItemList()->size(); n && !pSelMenu; )
2141 : {
2142 0 : MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
2143 :
2144 0 : if ( pData->pSubMenu )
2145 0 : pSelMenu = pData->pSubMenu->ImplFindSelectMenu();
2146 : }
2147 :
2148 0 : return pSelMenu;
2149 : }
2150 :
2151 0 : Menu* Menu::ImplFindMenu( sal_uInt16 nItemId )
2152 : {
2153 0 : Menu* pSelMenu = NULL;
2154 :
2155 0 : for ( size_t n = GetItemList()->size(); n && !pSelMenu; )
2156 : {
2157 0 : MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
2158 :
2159 0 : if( pData->nId == nItemId )
2160 0 : pSelMenu = this;
2161 0 : else if ( pData->pSubMenu )
2162 0 : pSelMenu = pData->pSubMenu->ImplFindMenu( nItemId );
2163 : }
2164 :
2165 0 : return pSelMenu;
2166 : }
2167 :
2168 10 : void Menu::RemoveDisabledEntries( bool bCheckPopups, bool bRemoveEmptyPopups )
2169 : {
2170 62 : for ( sal_uInt16 n = 0; n < GetItemCount(); n++ )
2171 : {
2172 52 : bool bRemove = false;
2173 52 : MenuItemData* pItem = pItemList->GetDataFromPos( n );
2174 52 : if ( pItem->eType == MenuItemType::SEPARATOR )
2175 : {
2176 4 : if ( !n || ( GetItemType( n-1 ) == MenuItemType::SEPARATOR ) )
2177 0 : bRemove = true;
2178 : }
2179 : else
2180 48 : bRemove = !pItem->bEnabled;
2181 :
2182 52 : if ( bCheckPopups && pItem->pSubMenu )
2183 : {
2184 8 : pItem->pSubMenu->RemoveDisabledEntries( true );
2185 8 : if ( bRemoveEmptyPopups && !pItem->pSubMenu->GetItemCount() )
2186 2 : bRemove = true;
2187 : }
2188 :
2189 52 : if ( bRemove )
2190 8 : RemoveItem( n-- );
2191 : }
2192 :
2193 10 : if ( GetItemCount() )
2194 : {
2195 8 : sal_uInt16 nLast = GetItemCount() - 1;
2196 8 : MenuItemData* pItem = pItemList->GetDataFromPos( nLast );
2197 8 : if ( pItem->eType == MenuItemType::SEPARATOR )
2198 0 : RemoveItem( nLast );
2199 : }
2200 10 : delete mpLayoutData, mpLayoutData = NULL;
2201 10 : }
2202 :
2203 0 : bool Menu::HasValidEntries( bool bCheckPopups )
2204 : {
2205 0 : bool bValidEntries = false;
2206 0 : sal_uInt16 nCount = GetItemCount();
2207 0 : for ( sal_uInt16 n = 0; !bValidEntries && ( n < nCount ); n++ )
2208 : {
2209 0 : MenuItemData* pItem = pItemList->GetDataFromPos( n );
2210 0 : if ( pItem->bEnabled && ( pItem->eType != MenuItemType::SEPARATOR ) )
2211 : {
2212 0 : if ( bCheckPopups && pItem->pSubMenu )
2213 0 : bValidEntries = pItem->pSubMenu->HasValidEntries( true );
2214 : else
2215 0 : bValidEntries = true;
2216 : }
2217 : }
2218 0 : return bValidEntries;
2219 : }
2220 :
2221 0 : sal_uLong Menu::DeactivateMenuBar(sal_uLong nFocusId)
2222 : {
2223 0 : return nFocusId;
2224 : }
2225 :
2226 0 : void Menu::MenuBarKeyInput(const KeyEvent&)
2227 : {
2228 0 : }
2229 :
2230 13148 : void Menu::ImplKillLayoutData() const
2231 : {
2232 13148 : delete mpLayoutData, mpLayoutData = NULL;
2233 13148 : }
2234 :
2235 4 : void Menu::ImplFillLayoutData() const
2236 : {
2237 4 : if( pWindow && pWindow->IsReallyVisible() )
2238 : {
2239 4 : mpLayoutData = new MenuLayoutData();
2240 4 : if (IsMenuBar())
2241 : {
2242 2 : ImplPaint( pWindow, 0, 0, 0, false, true );
2243 : }
2244 : else
2245 : {
2246 2 : MenuFloatingWindow* pFloat = static_cast<MenuFloatingWindow*>(pWindow);
2247 2 : ImplPaint( pWindow, pFloat->nScrollerHeight, pFloat->ImplGetStartY(), 0, false, true );
2248 : }
2249 : }
2250 4 : }
2251 :
2252 0 : Rectangle Menu::GetCharacterBounds( sal_uInt16 nItemID, long nIndex ) const
2253 : {
2254 0 : long nItemIndex = -1;
2255 0 : if( ! mpLayoutData )
2256 0 : ImplFillLayoutData();
2257 0 : if( mpLayoutData )
2258 : {
2259 0 : for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ )
2260 : {
2261 0 : if( mpLayoutData->m_aLineItemIds[i] == nItemID )
2262 : {
2263 0 : nItemIndex = mpLayoutData->m_aLineIndices[i];
2264 0 : break;
2265 : }
2266 : }
2267 : }
2268 0 : return (mpLayoutData && nItemIndex != -1) ? mpLayoutData->GetCharacterBounds( nItemIndex+nIndex ) : Rectangle();
2269 : }
2270 :
2271 0 : long Menu::GetIndexForPoint( const Point& rPoint, sal_uInt16& rItemID ) const
2272 : {
2273 0 : long nIndex = -1;
2274 0 : rItemID = 0;
2275 0 : if( ! mpLayoutData )
2276 0 : ImplFillLayoutData();
2277 0 : if( mpLayoutData )
2278 : {
2279 0 : nIndex = mpLayoutData->GetIndexForPoint( rPoint );
2280 0 : for( size_t i = 0; i < mpLayoutData->m_aLineIndices.size(); i++ )
2281 : {
2282 0 : if( mpLayoutData->m_aLineIndices[i] <= nIndex &&
2283 0 : (i == mpLayoutData->m_aLineIndices.size()-1 || mpLayoutData->m_aLineIndices[i+1] > nIndex) )
2284 : {
2285 : // make index relative to item
2286 0 : nIndex -= mpLayoutData->m_aLineIndices[i];
2287 0 : rItemID = mpLayoutData->m_aLineItemIds[i];
2288 0 : break;
2289 : }
2290 : }
2291 : }
2292 0 : return nIndex;
2293 : }
2294 :
2295 3104 : Rectangle Menu::GetBoundingRectangle( sal_uInt16 nPos ) const
2296 : {
2297 3104 : Rectangle aRet;
2298 :
2299 3104 : if( ! mpLayoutData )
2300 4 : ImplFillLayoutData();
2301 3104 : if( mpLayoutData )
2302 : {
2303 3104 : std::map< sal_uInt16, Rectangle >::const_iterator it = mpLayoutData->m_aVisibleItemBoundRects.find( nPos );
2304 3104 : if( it != mpLayoutData->m_aVisibleItemBoundRects.end() )
2305 3104 : aRet = it->second;
2306 : }
2307 3104 : return aRet;
2308 : }
2309 :
2310 0 : void Menu::SetAccessibleName( sal_uInt16 nItemId, const OUString& rStr )
2311 : {
2312 : size_t nPos;
2313 0 : MenuItemData* pData = pItemList->GetData( nItemId, nPos );
2314 :
2315 0 : if ( pData && !rStr.equals( pData->aAccessibleName ) )
2316 : {
2317 0 : pData->aAccessibleName = rStr;
2318 0 : ImplCallEventListeners( VCLEVENT_MENU_ACCESSIBLENAMECHANGED, nPos );
2319 : }
2320 0 : }
2321 :
2322 3970 : OUString Menu::GetAccessibleName( sal_uInt16 nItemId ) const
2323 : {
2324 3970 : MenuItemData* pData = pItemList->GetData( nItemId );
2325 :
2326 3970 : if ( pData )
2327 3970 : return pData->aAccessibleName;
2328 :
2329 0 : return OUString();
2330 : }
2331 :
2332 139868 : void Menu::ImplSetSalMenu( SalMenu *pSalMenu )
2333 : {
2334 139868 : if( mpSalMenu )
2335 0 : ImplGetSVData()->mpDefInst->DestroyMenu( mpSalMenu );
2336 139868 : mpSalMenu = pSalMenu;
2337 139868 : }
2338 :
2339 0 : bool Menu::GetSystemMenuData( SystemMenuData* pData ) const
2340 : {
2341 0 : Menu* pMenu = (Menu*)this;
2342 0 : if( pData && pMenu->ImplGetSalMenu() )
2343 : {
2344 0 : pMenu->ImplGetSalMenu()->GetSystemMenuData( pData );
2345 0 : return true;
2346 : }
2347 : else
2348 0 : return false;
2349 : }
2350 :
2351 14592 : bool Menu::IsHighlighted( sal_uInt16 nItemPos ) const
2352 : {
2353 14592 : bool bRet = false;
2354 :
2355 14592 : if( pWindow )
2356 : {
2357 596 : if (IsMenuBar())
2358 460 : bRet = ( nItemPos == static_cast< MenuBarWindow * > (pWindow)->GetHighlightedItem() );
2359 : else
2360 136 : bRet = ( nItemPos == static_cast< MenuFloatingWindow * > (pWindow)->GetHighlightedItem() );
2361 : }
2362 :
2363 14592 : return bRet;
2364 : }
2365 :
2366 0 : void Menu::HighlightItem( sal_uInt16 nItemPos )
2367 : {
2368 0 : if ( pWindow )
2369 : {
2370 0 : if (IsMenuBar())
2371 : {
2372 0 : MenuBarWindow* pMenuWin = static_cast< MenuBarWindow* >( pWindow );
2373 0 : pMenuWin->SetAutoPopup( false );
2374 0 : pMenuWin->ChangeHighlightItem( nItemPos, false );
2375 : }
2376 : else
2377 : {
2378 0 : static_cast< MenuFloatingWindow* >( pWindow )->ChangeHighlightItem( nItemPos, false );
2379 : }
2380 : }
2381 0 : }
2382 :
2383 : // - MenuBar -
2384 :
2385 11018 : IMenuBarWindow* MenuBar::getMenuBarWindow()
2386 : {
2387 : // so far just a dynamic_cast, hopefully to be turned into something saner
2388 : // at some stage
2389 11018 : IMenuBarWindow *pWin = dynamic_cast<IMenuBarWindow*>(pWindow);
2390 : assert(pWin);
2391 11018 : return pWin;
2392 : }
2393 :
2394 5478 : MenuBar::MenuBar()
2395 : : Menu(),
2396 : mbCloseBtnVisible(false),
2397 : mbFloatBtnVisible(false),
2398 : mbHideBtnVisible(false),
2399 5478 : mbDisplayable(true)
2400 : {
2401 5478 : mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu(true, this);
2402 5478 : }
2403 :
2404 0 : MenuBar::MenuBar( const MenuBar& rMenu )
2405 : : Menu(),
2406 : mbCloseBtnVisible(false),
2407 : mbFloatBtnVisible(false),
2408 : mbHideBtnVisible(false),
2409 0 : mbDisplayable(true)
2410 : {
2411 0 : mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu(true, this);
2412 0 : *this = rMenu;
2413 0 : }
2414 :
2415 16416 : MenuBar::~MenuBar()
2416 : {
2417 5472 : ImplDestroy( this, true );
2418 10944 : }
2419 :
2420 0 : void MenuBar::ClosePopup(Menu *pMenu)
2421 : {
2422 0 : getMenuBarWindow()->PopupClosed(pMenu);
2423 0 : }
2424 :
2425 0 : sal_uLong MenuBar::DeactivateMenuBar(sal_uLong nFocusId)
2426 : {
2427 0 : nFocusId = getMenuBarWindow()->GetFocusId();
2428 0 : if (nFocusId)
2429 : {
2430 0 : getMenuBarWindow()->SetFocusId(0);
2431 0 : ImplGetSVData()->maWinData.mbNoDeactivate = false;
2432 : }
2433 :
2434 0 : return nFocusId;
2435 : }
2436 :
2437 0 : void MenuBar::MenuBarKeyInput(const KeyEvent& rEvent)
2438 : {
2439 0 : pWindow->KeyInput(rEvent);
2440 0 : }
2441 :
2442 7210 : void MenuBar::ShowCloseButton(bool bShow)
2443 : {
2444 7210 : ShowButtons( bShow, mbFloatBtnVisible, mbHideBtnVisible );
2445 7210 : }
2446 :
2447 7210 : void MenuBar::ShowButtons( bool bClose, bool bFloat, bool bHide )
2448 : {
2449 8892 : if ((bClose != mbCloseBtnVisible) ||
2450 3364 : (bFloat != mbFloatBtnVisible) ||
2451 1682 : (bHide != mbHideBtnVisible))
2452 : {
2453 5528 : mbCloseBtnVisible = bClose;
2454 5528 : mbFloatBtnVisible = bFloat;
2455 5528 : mbHideBtnVisible = bHide;
2456 5528 : getMenuBarWindow()->ShowButtons(bClose, bFloat, bHide);
2457 : }
2458 7210 : }
2459 :
2460 5474 : void MenuBar::SetDisplayable( bool bDisplayable )
2461 : {
2462 5474 : if( bDisplayable != mbDisplayable )
2463 : {
2464 0 : mbDisplayable = bDisplayable;
2465 0 : getMenuBarWindow()->LayoutChanged();
2466 : }
2467 5474 : }
2468 :
2469 5480 : vcl::Window* MenuBar::ImplCreate(vcl::Window* pParent, vcl::Window* pWindow, MenuBar* pMenu, const css::uno::Reference<css::frame::XFrame> &/*rFrame*/)
2470 : {
2471 5480 : MenuBarWindow *pMenuBarWindow = dynamic_cast<MenuBarWindow*>(pWindow);
2472 5480 : if (!pMenuBarWindow)
2473 : {
2474 5478 : pWindow = pMenuBarWindow = new MenuBarWindow( pParent );
2475 : }
2476 :
2477 5480 : pMenu->pStartedFrom = 0;
2478 5480 : pMenu->pWindow = pWindow;
2479 5480 : pMenuBarWindow->SetMenu(pMenu);
2480 5480 : long nHeight = pWindow ? pMenu->ImplCalcSize(pWindow).Height() : 0;
2481 :
2482 : // depending on the native implementation or the displayable flag
2483 : // the menubar windows is suppressed (ie, height=0)
2484 5480 : if (!pMenu->IsDisplayable() || (pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar()))
2485 : {
2486 0 : nHeight = 0;
2487 : }
2488 :
2489 5480 : pMenuBarWindow->SetHeight(nHeight);
2490 5480 : return pWindow;
2491 : }
2492 :
2493 10948 : void MenuBar::ImplDestroy( MenuBar* pMenu, bool bDelete )
2494 : {
2495 10948 : vcl::Window *pWindow = pMenu->ImplGetWindow();
2496 10948 : if (pWindow && bDelete)
2497 : {
2498 5474 : pMenu->getMenuBarWindow()->KillActivePopup();
2499 5474 : delete pWindow;
2500 : }
2501 10948 : pMenu->pWindow = NULL;
2502 10948 : }
2503 :
2504 0 : bool MenuBar::ImplHandleKeyEvent( const KeyEvent& rKEvent, bool bFromMenu )
2505 : {
2506 0 : bool bDone = false;
2507 :
2508 : // No keyboard processing when system handles the menu or our menubar is invisible
2509 0 : if( !IsDisplayable() ||
2510 0 : ( ImplGetSalMenu() && ImplGetSalMenu()->VisibleMenuBar() ) )
2511 0 : return bDone;
2512 :
2513 : // check for enabled, if this method is called from another window...
2514 0 : vcl::Window* pWin = ImplGetWindow();
2515 0 : if ( pWin && pWin->IsEnabled() && pWin->IsInputEnabled() && ! pWin->IsInModalMode() )
2516 0 : bDone = getMenuBarWindow()->HandleKeyEvent( rKEvent, bFromMenu );
2517 0 : return bDone;
2518 : }
2519 :
2520 16 : void MenuBar::SelectItem(sal_uInt16 nId)
2521 : {
2522 16 : IMenuBarWindow* pMenuWin = getMenuBarWindow();
2523 :
2524 16 : if (pWindow)
2525 : {
2526 16 : pWindow->GrabFocus();
2527 16 : nId = GetItemPos( nId );
2528 :
2529 : // #99705# popup the selected menu
2530 16 : pMenuWin->SetAutoPopup( true );
2531 16 : if (ITEMPOS_INVALID != pMenuWin->GetHighlightedItem())
2532 : {
2533 16 : pMenuWin->KillActivePopup();
2534 16 : pMenuWin->ChangeHighlightItem( ITEMPOS_INVALID, false );
2535 : }
2536 16 : if (nId != ITEMPOS_INVALID)
2537 16 : pMenuWin->ChangeHighlightItem( nId, false );
2538 : }
2539 16 : }
2540 :
2541 : // handler for native menu selection and command events
2542 :
2543 0 : bool MenuBar::HandleMenuActivateEvent( Menu *pMenu ) const
2544 : {
2545 0 : if( pMenu )
2546 : {
2547 0 : ImplMenuDelData aDelData( this );
2548 :
2549 0 : pMenu->pStartedFrom = (Menu*)this;
2550 0 : pMenu->bInCallback = true;
2551 0 : pMenu->Activate();
2552 :
2553 0 : if( !aDelData.isDeleted() )
2554 0 : pMenu->bInCallback = false;
2555 : }
2556 0 : return true;
2557 : }
2558 :
2559 0 : bool MenuBar::HandleMenuDeActivateEvent( Menu *pMenu ) const
2560 : {
2561 0 : if( pMenu )
2562 : {
2563 0 : ImplMenuDelData aDelData( this );
2564 :
2565 0 : pMenu->pStartedFrom = (Menu*)this;
2566 0 : pMenu->bInCallback = true;
2567 0 : pMenu->Deactivate();
2568 0 : if( !aDelData.isDeleted() )
2569 0 : pMenu->bInCallback = false;
2570 : }
2571 0 : return true;
2572 : }
2573 :
2574 0 : bool MenuBar::HandleMenuHighlightEvent( Menu *pMenu, sal_uInt16 nHighlightEventId ) const
2575 : {
2576 0 : if( !pMenu )
2577 0 : pMenu = ((Menu*) this)->ImplFindMenu( nHighlightEventId );
2578 0 : if( pMenu )
2579 : {
2580 0 : ImplMenuDelData aDelData( pMenu );
2581 :
2582 0 : if( mnHighlightedItemPos != ITEMPOS_INVALID )
2583 0 : pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, mnHighlightedItemPos );
2584 :
2585 0 : if( !aDelData.isDeleted() )
2586 : {
2587 0 : pMenu->mnHighlightedItemPos = pMenu->GetItemPos( nHighlightEventId );
2588 0 : pMenu->nSelectedId = nHighlightEventId;
2589 0 : pMenu->pStartedFrom = (Menu*)this;
2590 0 : pMenu->ImplCallHighlight( pMenu->mnHighlightedItemPos );
2591 : }
2592 0 : return true;
2593 : }
2594 : else
2595 0 : return false;
2596 : }
2597 :
2598 0 : bool MenuBar::HandleMenuCommandEvent( Menu *pMenu, sal_uInt16 nCommandEventId ) const
2599 : {
2600 0 : if( !pMenu )
2601 0 : pMenu = ((Menu*) this)->ImplFindMenu( nCommandEventId );
2602 0 : if( pMenu )
2603 : {
2604 0 : pMenu->nSelectedId = nCommandEventId;
2605 0 : pMenu->pStartedFrom = (Menu*)this;
2606 0 : pMenu->ImplSelect();
2607 0 : return true;
2608 : }
2609 : else
2610 0 : return false;
2611 : }
2612 :
2613 0 : sal_uInt16 MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const OUString& i_rToolTip, sal_uInt16 i_nPos )
2614 : {
2615 0 : return getMenuBarWindow()->AddMenuBarButton(i_rImage, i_rLink, i_rToolTip, i_nPos);
2616 : }
2617 :
2618 0 : void MenuBar::SetMenuBarButtonHighlightHdl( sal_uInt16 nId, const Link& rLink )
2619 : {
2620 0 : getMenuBarWindow()->SetMenuBarButtonHighlightHdl(nId, rLink);
2621 0 : }
2622 :
2623 0 : Rectangle MenuBar::GetMenuBarButtonRectPixel( sal_uInt16 nId )
2624 : {
2625 0 : return getMenuBarWindow()->GetMenuBarButtonRectPixel(nId);
2626 : }
2627 :
2628 0 : void MenuBar::RemoveMenuBarButton( sal_uInt16 nId )
2629 : {
2630 0 : getMenuBarWindow()->RemoveMenuBarButton(nId);
2631 0 : }
2632 :
2633 0 : bool MenuBar::HandleMenuButtonEvent( Menu *, sal_uInt16 i_nButtonId )
2634 : {
2635 0 : return getMenuBarWindow()->HandleMenuButtonEvent(i_nButtonId);
2636 : }
2637 :
2638 : // bool PopupMenu::bAnyPopupInExecute = false;
2639 :
2640 131201 : PopupMenu::PopupMenu()
2641 131201 : : pRefAutoSubMenu(NULL)
2642 : {
2643 131201 : mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu(false, this);
2644 131201 : }
2645 :
2646 3213 : PopupMenu::PopupMenu( const ResId& rResId )
2647 3213 : : pRefAutoSubMenu(NULL)
2648 : {
2649 3213 : mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu(false, this);
2650 :
2651 3213 : ResMgr* pMgr = rResId.GetResMgr();
2652 3213 : if( ! pMgr )
2653 3213 : return;
2654 :
2655 3213 : rResId.SetRT( RSC_MENU );
2656 3213 : GetRes( rResId );
2657 :
2658 3213 : sal_uLong nObjMask = ReadLongRes();
2659 :
2660 3213 : if( nObjMask & RSC_MENU_ITEMS )
2661 : {
2662 3205 : sal_uLong nObjFollows = ReadLongRes();
2663 : // insert menu items
2664 12999 : for( sal_uLong i = 0; i < nObjFollows; i++ )
2665 : {
2666 9794 : InsertItem( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
2667 9794 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
2668 : }
2669 : }
2670 :
2671 3213 : if( nObjMask & RSC_MENU_TEXT )
2672 : {
2673 0 : aTitleText = ReadStringRes();
2674 : }
2675 3213 : if( nObjMask & RSC_MENU_DEFAULTITEMID )
2676 0 : SetDefaultItem( sal::static_int_cast<sal_uInt16>(ReadLongRes()) );
2677 : }
2678 :
2679 0 : PopupMenu::PopupMenu( const PopupMenu& rMenu )
2680 : : Menu(),
2681 0 : pRefAutoSubMenu(NULL)
2682 : {
2683 0 : mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu(false, this);
2684 0 : *this = rMenu;
2685 0 : }
2686 :
2687 399063 : PopupMenu::~PopupMenu()
2688 : {
2689 134396 : if( pRefAutoSubMenu && *pRefAutoSubMenu == this )
2690 0 : *pRefAutoSubMenu = NULL; // #111060# avoid second delete in ~MenuItemData
2691 264667 : }
2692 :
2693 0 : void PopupMenu::ClosePopup(Menu* pMenu)
2694 : {
2695 0 : MenuFloatingWindow* p = dynamic_cast<MenuFloatingWindow*>(ImplGetWindow());
2696 0 : PopupMenu *pPopup = dynamic_cast<PopupMenu*>(pMenu);
2697 0 : if (p && pMenu)
2698 0 : p->KillActivePopup(pPopup);
2699 0 : }
2700 :
2701 0 : bool PopupMenu::IsInExecute()
2702 : {
2703 0 : return GetActivePopupMenu() ? true : false;
2704 : }
2705 :
2706 0 : PopupMenu* PopupMenu::GetActivePopupMenu()
2707 : {
2708 0 : ImplSVData* pSVData = ImplGetSVData();
2709 0 : return pSVData->maAppData.mpActivePopupMenu;
2710 : }
2711 :
2712 0 : void PopupMenu::EndExecute( sal_uInt16 nSelectId )
2713 : {
2714 0 : if ( ImplGetWindow() )
2715 0 : ImplGetFloatingWindow()->EndExecute( nSelectId );
2716 0 : }
2717 :
2718 0 : void PopupMenu::SelectItem(sal_uInt16 nId)
2719 : {
2720 0 : if ( ImplGetWindow() )
2721 : {
2722 0 : if( nId != ITEMPOS_INVALID )
2723 : {
2724 0 : size_t nPos = 0;
2725 0 : MenuItemData* pData = GetItemList()->GetData( nId, nPos );
2726 0 : if (pData && pData->pSubMenu)
2727 0 : ImplGetFloatingWindow()->ChangeHighlightItem( nPos, true );
2728 : else
2729 0 : ImplGetFloatingWindow()->EndExecute( nId );
2730 : }
2731 : else
2732 : {
2733 0 : MenuFloatingWindow* pFloat = ImplGetFloatingWindow();
2734 0 : pFloat->GrabFocus();
2735 :
2736 0 : for( size_t nPos = 0; nPos < GetItemList()->size(); nPos++ )
2737 : {
2738 0 : MenuItemData* pData = GetItemList()->GetDataFromPos( nPos );
2739 0 : if( pData->pSubMenu )
2740 : {
2741 0 : pFloat->KillActivePopup();
2742 : }
2743 : }
2744 0 : pFloat->ChangeHighlightItem( ITEMPOS_INVALID, false );
2745 : }
2746 : }
2747 0 : }
2748 :
2749 0 : void PopupMenu::SetSelectedEntry( sal_uInt16 nId )
2750 : {
2751 0 : nSelectedId = nId;
2752 0 : }
2753 :
2754 0 : sal_uInt16 PopupMenu::Execute( vcl::Window* pExecWindow, const Point& rPopupPos )
2755 : {
2756 0 : return Execute( pExecWindow, Rectangle( rPopupPos, rPopupPos ), POPUPMENU_EXECUTE_DOWN );
2757 : }
2758 :
2759 0 : sal_uInt16 PopupMenu::Execute( vcl::Window* pExecWindow, const Rectangle& rRect, sal_uInt16 nFlags )
2760 : {
2761 0 : ENSURE_OR_RETURN( pExecWindow, "PopupMenu::Execute: need a non-NULL window!", 0 );
2762 :
2763 0 : sal_uLong nPopupModeFlags = 0;
2764 0 : if ( nFlags & POPUPMENU_EXECUTE_DOWN )
2765 0 : nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
2766 0 : else if ( nFlags & POPUPMENU_EXECUTE_UP )
2767 0 : nPopupModeFlags = FLOATWIN_POPUPMODE_UP;
2768 0 : else if ( nFlags & POPUPMENU_EXECUTE_LEFT )
2769 0 : nPopupModeFlags = FLOATWIN_POPUPMODE_LEFT;
2770 0 : else if ( nFlags & POPUPMENU_EXECUTE_RIGHT )
2771 0 : nPopupModeFlags = FLOATWIN_POPUPMODE_RIGHT;
2772 : else
2773 0 : nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
2774 :
2775 0 : if (nFlags & POPUPMENU_NOMOUSEUPCLOSE ) // allow popup menus to stay open on mouse button up
2776 0 : nPopupModeFlags |= FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE; // useful if the menu was opened on mousebutton down (eg toolbox configuration)
2777 :
2778 0 : if (nFlags & POPUPMENU_NOHORZ_PLACEMENT)
2779 0 : nPopupModeFlags |= FLOATWIN_POPUPMODE_NOHORZPLACEMENT;
2780 :
2781 0 : return ImplExecute( pExecWindow, rRect, nPopupModeFlags, 0, false );
2782 : }
2783 :
2784 16 : sal_uInt16 PopupMenu::ImplExecute( vcl::Window* pW, const Rectangle& rRect, sal_uLong nPopupModeFlags, Menu* pSFrom, bool bPreSelectFirst )
2785 : {
2786 16 : if ( !pSFrom && ( PopupMenu::IsInExecute() || !GetItemCount() ) )
2787 0 : return 0;
2788 :
2789 16 : delete mpLayoutData, mpLayoutData = NULL;
2790 :
2791 16 : ImplSVData* pSVData = ImplGetSVData();
2792 :
2793 16 : pStartedFrom = pSFrom;
2794 16 : nSelectedId = 0;
2795 16 : bCanceled = false;
2796 :
2797 16 : sal_uLong nFocusId = 0;
2798 16 : bool bRealExecute = false;
2799 16 : if ( !pStartedFrom )
2800 : {
2801 0 : pSVData->maWinData.mbNoDeactivate = true;
2802 0 : nFocusId = Window::SaveFocus();
2803 0 : bRealExecute = true;
2804 : }
2805 : else
2806 : {
2807 : // assure that only one menu is open at a time
2808 16 : if (pStartedFrom->IsMenuBar() && pSVData->maWinData.mpFirstFloat)
2809 0 : pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
2810 : }
2811 :
2812 : DBG_ASSERT( !ImplGetWindow(), "Win?!" );
2813 16 : Rectangle aRect( rRect );
2814 16 : aRect.SetPos( pW->OutputToScreenPixel( aRect.TopLeft() ) );
2815 :
2816 16 : WinBits nStyle = WB_BORDER;
2817 16 : if (bRealExecute)
2818 0 : nPopupModeFlags |= FLOATWIN_POPUPMODE_NEWLEVEL;
2819 16 : if (!pStartedFrom || !pStartedFrom->IsMenuBar())
2820 0 : nPopupModeFlags |= FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK | FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE;
2821 :
2822 16 : nPopupModeFlags |= FLOATWIN_POPUPMODE_NOKEYCLOSE;
2823 :
2824 : // could be useful during debugging.
2825 : // nPopupModeFlags |= FLOATWIN_POPUPMODE_NOFOCUSCLOSE;
2826 :
2827 16 : ImplDelData aDelData;
2828 16 : pW->ImplAddDel( &aDelData );
2829 :
2830 16 : bInCallback = true; // set it here, if Activate overloaded
2831 16 : Activate();
2832 16 : bInCallback = false;
2833 :
2834 16 : if ( aDelData.IsDead() )
2835 0 : return 0; // Error
2836 :
2837 16 : pW->ImplRemoveDel( &aDelData );
2838 :
2839 16 : if ( bCanceled || bKilled )
2840 0 : return 0;
2841 :
2842 16 : if ( !GetItemCount() )
2843 0 : return 0;
2844 :
2845 : // The flag MENU_FLAG_HIDEDISABLEDENTRIES is inherited.
2846 16 : if ( pSFrom )
2847 : {
2848 16 : if ( pSFrom->nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES )
2849 0 : nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES;
2850 : else
2851 16 : nMenuFlags &= ~MENU_FLAG_HIDEDISABLEDENTRIES;
2852 : }
2853 : else
2854 : // #102790# context menus shall never show disabled entries
2855 0 : nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES;
2856 :
2857 16 : sal_uInt16 nVisibleEntries = ImplGetVisibleItemCount();
2858 16 : if ( !nVisibleEntries )
2859 : {
2860 0 : ResMgr* pResMgr = ImplGetResMgr();
2861 0 : if( pResMgr )
2862 : {
2863 0 : OUString aTmpEntryText( ResId( SV_RESID_STRING_NOSELECTIONPOSSIBLE, *pResMgr ) );
2864 : MenuItemData* pData = pItemList->Insert(
2865 0 : 0xFFFF, MenuItemType::STRING, MenuItemBits::NONE, aTmpEntryText, Image(), NULL, 0xFFFF, OString() );
2866 0 : size_t nPos = 0;
2867 0 : pData = pItemList->GetData( pData->nId, nPos );
2868 : assert(pData);
2869 0 : if (pData)
2870 : {
2871 0 : pData->bIsTemporary = true;
2872 : }
2873 0 : ImplCallEventListeners(VCLEVENT_MENU_SUBMENUCHANGED, nPos);
2874 : }
2875 : }
2876 16 : else if ( Application::GetSettings().GetStyleSettings().GetAutoMnemonic() && !( nMenuFlags & MENU_FLAG_NOAUTOMNEMONICS ) )
2877 : {
2878 16 : CreateAutoMnemonics();
2879 : }
2880 :
2881 16 : MenuFloatingWindow* pWin = new MenuFloatingWindow( this, pW, nStyle | WB_SYSTEMWINDOW );
2882 16 : if( pSVData->maNWFData.mbFlatMenu )
2883 0 : pWin->SetBorderStyle( WindowBorderStyle::NOBORDER );
2884 : else
2885 16 : pWin->SetBorderStyle( pWin->GetBorderStyle() | WindowBorderStyle::MENU );
2886 16 : pWindow = pWin;
2887 :
2888 16 : Size aSz = ImplCalcSize( pWin );
2889 :
2890 16 : Rectangle aDesktopRect(pWin->GetDesktopRectPixel());
2891 16 : if( Application::GetScreenCount() > 1 && Application::IsUnifiedDisplay() )
2892 : {
2893 0 : vcl::Window* pDeskW = pWindow->GetWindow( WINDOW_REALPARENT );
2894 0 : if( ! pDeskW )
2895 0 : pDeskW = pWindow;
2896 0 : Point aDesktopTL( pDeskW->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) );
2897 : aDesktopRect = Application::GetScreenPosSizePixel(
2898 0 : Application::GetBestScreen( Rectangle( aDesktopTL, aRect.GetSize() ) ));
2899 : }
2900 :
2901 16 : long nMaxHeight = aDesktopRect.GetHeight();
2902 :
2903 : //rhbz#1021915. If a menu won't fit in the desired location the default
2904 : //mode is to place it somewhere it will fit. e.g. above, left, right. For
2905 : //some cases, e.g. menubars, it's desirable to limit the options to
2906 : //above/below and force the menu to scroll if it won't fit
2907 16 : if (nPopupModeFlags & FLOATWIN_POPUPMODE_NOHORZPLACEMENT)
2908 : {
2909 16 : vcl::Window* pRef = pWin;
2910 16 : if ( pRef->GetParent() )
2911 16 : pRef = pRef->GetParent();
2912 :
2913 32 : Rectangle devRect( pRef->OutputToAbsoluteScreenPixel( aRect.TopLeft() ),
2914 48 : pRef->OutputToAbsoluteScreenPixel( aRect.BottomRight() ) );
2915 :
2916 16 : long nHeightAbove = devRect.Top() - aDesktopRect.Top();
2917 16 : long nHeightBelow = aDesktopRect.Bottom() - devRect.Bottom();
2918 16 : nMaxHeight = std::min(nMaxHeight, std::max(nHeightAbove, nHeightBelow));
2919 : }
2920 :
2921 16 : if (pStartedFrom && pStartedFrom->IsMenuBar())
2922 16 : nMaxHeight -= pW->GetSizePixel().Height();
2923 : sal_Int32 nLeft, nTop, nRight, nBottom;
2924 16 : pWindow->GetBorder( nLeft, nTop, nRight, nBottom );
2925 16 : nMaxHeight -= nTop+nBottom;
2926 16 : if ( aSz.Height() > nMaxHeight )
2927 : {
2928 0 : pWin->EnableScrollMenu( true );
2929 0 : sal_uInt16 nStart = ImplGetFirstVisible();
2930 0 : sal_uInt16 nEntries = ImplCalcVisEntries( nMaxHeight, nStart );
2931 0 : aSz.Height() = ImplCalcHeight( nEntries );
2932 : }
2933 :
2934 16 : pWin->SetFocusId( nFocusId );
2935 16 : pWin->SetOutputSizePixel( aSz );
2936 : // #102158# menus must never grab the focus, otherwise
2937 : // they will be closed immediately
2938 : // from now on focus grabbing is only prohibited automatically if
2939 : // FLOATWIN_POPUPMODE_GRABFOCUS was set (which is done below), because some
2940 : // floaters (like floating toolboxes) may grab the focus
2941 : // pWin->GrabFocus();
2942 16 : if ( GetItemCount() )
2943 : {
2944 16 : SalMenu* pMenu = ImplGetSalMenu();
2945 16 : if( pMenu && bRealExecute && pMenu->ShowNativePopupMenu( pWin, aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS ) )
2946 : {
2947 0 : pWin->StopExecute(0);
2948 0 : pWin->doShutdown();
2949 0 : pWindow->doLazyDelete();
2950 0 : pWindow = NULL;
2951 0 : return nSelectedId;
2952 : }
2953 : else
2954 : {
2955 16 : pWin->StartPopupMode( aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS );
2956 : }
2957 16 : if( pSFrom )
2958 : {
2959 : sal_uInt16 aPos;
2960 16 : if (pSFrom->IsMenuBar())
2961 16 : aPos = static_cast<MenuBarWindow *>(pSFrom->pWindow)->GetHighlightedItem();
2962 : else
2963 0 : aPos = static_cast<MenuFloatingWindow *>(pSFrom->pWindow)->GetHighlightedItem();
2964 :
2965 16 : pWin->SetPosInParent( aPos ); // store position to be sent in SUBMENUDEACTIVATE
2966 16 : pSFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUACTIVATE, aPos );
2967 : }
2968 : }
2969 16 : if ( bPreSelectFirst )
2970 : {
2971 0 : size_t nCount = pItemList->size();
2972 0 : for ( size_t n = 0; n < nCount; n++ )
2973 : {
2974 0 : MenuItemData* pData = pItemList->GetDataFromPos( n );
2975 0 : if ( ( pData->bEnabled
2976 0 : || !Application::GetSettings().GetStyleSettings().GetSkipDisabledInMenus()
2977 : )
2978 0 : && ( pData->eType != MenuItemType::SEPARATOR )
2979 0 : && ImplIsVisible( n )
2980 0 : && ImplIsSelectable( n )
2981 : )
2982 : {
2983 0 : pWin->ChangeHighlightItem( n, false );
2984 0 : break;
2985 : }
2986 : }
2987 : }
2988 16 : if ( bRealExecute )
2989 : {
2990 0 : pWin->ImplAddDel( &aDelData );
2991 :
2992 0 : ImplDelData aModalWinDel;
2993 0 : pW->ImplAddDel( &aModalWinDel );
2994 0 : pW->ImplIncModalCount();
2995 :
2996 0 : pWin->Execute();
2997 :
2998 : DBG_ASSERT( ! aModalWinDel.IsDead(), "window for popup died, modal count incorrect !" );
2999 0 : if( ! aModalWinDel.IsDead() )
3000 0 : pW->ImplDecModalCount();
3001 :
3002 0 : if ( !aDelData.IsDead() )
3003 0 : pWin->ImplRemoveDel( &aDelData );
3004 : else
3005 0 : return 0;
3006 :
3007 : // Restore focus (could already have been
3008 : // restored in Select)
3009 0 : nFocusId = pWin->GetFocusId();
3010 0 : if ( nFocusId )
3011 : {
3012 0 : pWin->SetFocusId( 0 );
3013 0 : pSVData->maWinData.mbNoDeactivate = false;
3014 : }
3015 0 : pWin->ImplEndPopupMode( 0, nFocusId );
3016 :
3017 0 : if ( nSelectedId ) // then clean up .. ( otherwise done by TH )
3018 : {
3019 0 : PopupMenu* pSub = pWin->GetActivePopup();
3020 0 : while ( pSub )
3021 : {
3022 0 : pSub->ImplGetFloatingWindow()->EndPopupMode();
3023 0 : pSub = pSub->ImplGetFloatingWindow()->GetActivePopup();
3024 : }
3025 : }
3026 0 : pWin->doShutdown();
3027 0 : pWindow->doLazyDelete();
3028 0 : pWindow = NULL;
3029 :
3030 : // is there still Select?
3031 0 : Menu* pSelect = ImplFindSelectMenu();
3032 0 : if ( pSelect )
3033 : {
3034 : // Select should be called prior to leaving execute in a popup menu!
3035 0 : Application::RemoveUserEvent( pSelect->nEventId );
3036 0 : pSelect->nEventId = 0;
3037 0 : pSelect->Select();
3038 0 : }
3039 : }
3040 :
3041 16 : return bRealExecute ? nSelectedId : 0;
3042 : }
3043 :
3044 0 : sal_uInt16 PopupMenu::ImplCalcVisEntries( long nMaxHeight, sal_uInt16 nStartEntry, sal_uInt16* pLastVisible ) const
3045 : {
3046 0 : nMaxHeight -= 2 * ImplGetFloatingWindow()->GetScrollerHeight();
3047 :
3048 0 : long nHeight = 0;
3049 0 : size_t nEntries = pItemList->size();
3050 0 : sal_uInt16 nVisEntries = 0;
3051 :
3052 0 : if ( pLastVisible )
3053 0 : *pLastVisible = 0;
3054 :
3055 0 : for ( size_t n = nStartEntry; n < nEntries; n++ )
3056 : {
3057 0 : if ( ImplIsVisible( n ) )
3058 : {
3059 0 : MenuItemData* pData = pItemList->GetDataFromPos( n );
3060 0 : nHeight += pData->aSz.Height();
3061 0 : if ( nHeight > nMaxHeight )
3062 0 : break;
3063 :
3064 0 : if ( pLastVisible )
3065 0 : *pLastVisible = n;
3066 0 : nVisEntries++;
3067 : }
3068 : }
3069 0 : return nVisEntries;
3070 : }
3071 :
3072 0 : long PopupMenu::ImplCalcHeight( sal_uInt16 nEntries ) const
3073 : {
3074 0 : long nHeight = 0;
3075 :
3076 0 : sal_uInt16 nFound = 0;
3077 0 : for ( size_t n = 0; ( nFound < nEntries ) && ( n < pItemList->size() ); n++ )
3078 : {
3079 0 : if ( ImplIsVisible( (sal_uInt16) n ) )
3080 : {
3081 0 : MenuItemData* pData = pItemList->GetDataFromPos( n );
3082 0 : nHeight += pData->aSz.Height();
3083 0 : nFound++;
3084 : }
3085 : }
3086 :
3087 0 : nHeight += 2*ImplGetFloatingWindow()->GetScrollerHeight();
3088 :
3089 0 : return nHeight;
3090 : }
3091 :
3092 836149 : ImplMenuDelData::ImplMenuDelData( const Menu* pMenu )
3093 : : mpNext( 0 )
3094 836149 : , mpMenu( 0 )
3095 : {
3096 836149 : if( pMenu )
3097 836149 : const_cast< Menu* >( pMenu )->ImplAddDel( *this );
3098 836149 : }
3099 :
3100 836149 : ImplMenuDelData::~ImplMenuDelData()
3101 : {
3102 836149 : if( mpMenu )
3103 836149 : const_cast< Menu* >( mpMenu )->ImplRemoveDel( *this );
3104 836149 : }
3105 :
3106 : namespace vcl
3107 : {
3108 556 : MenuInvalidator::MenuInvalidator() {};
3109 :
3110 : static VclEventListeners2* pMenuInvalidateListeners = NULL;
3111 556 : VclEventListeners2* MenuInvalidator::GetMenuInvalidateListeners()
3112 : {
3113 556 : if(!pMenuInvalidateListeners)
3114 2 : pMenuInvalidateListeners = new VclEventListeners2();
3115 556 : return pMenuInvalidateListeners;
3116 : }
3117 556 : void MenuInvalidator::Invalidated()
3118 : {
3119 556 : VclSimpleEvent aEvent(0);
3120 556 : GetMenuInvalidateListeners()->callListeners(&aEvent);
3121 556 : };
3122 1233 : }
3123 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|