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