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