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/debug.hxx" 32 #include "tools/rc.h" 33 34 #include "vcl/svapp.hxx" 35 #include "vcl/help.hxx" 36 #include "vcl/event.hxx" 37 #include "vcl/menu.hxx" 38 #include "vcl/button.hxx" 39 #include "vcl/tabpage.hxx" 40 #include "vcl/tabctrl.hxx" 41 #include "vcl/controllayout.hxx" 42 #include "vcl/sound.hxx" 43 #include "vcl/lstbox.hxx" 44 45 #include "controldata.hxx" 46 #include "svdata.hxx" 47 #include "window.h" 48 49 #include <hash_map> 50 #include <vector> 51 52 // ======================================================================= 53 54 struct ImplTabItem 55 { 56 sal_uInt16 mnId; 57 sal_uInt16 mnTabPageResId; 58 TabPage* mpTabPage; 59 String maText; 60 String maFormatText; 61 String maHelpText; 62 rtl::OString maHelpId; 63 Rectangle maRect; 64 sal_uInt16 mnLine; 65 bool mbFullVisible; 66 bool mbEnabled; 67 Image maTabImage; 68 69 ImplTabItem() 70 : mnId( 0 ), mnTabPageResId( 0 ), mpTabPage( NULL ), 71 mnLine( 0 ), mbFullVisible( sal_False ), mbEnabled( true ) 72 {} 73 }; 74 75 // ----------------------------------------------------------------------- 76 77 struct ImplTabCtrlData 78 { 79 std::hash_map< int, int > maLayoutPageIdToLine; 80 std::hash_map< int, int > maLayoutLineToPageId; 81 std::vector< Rectangle > maTabRectangles; 82 Point maItemsOffset; // offset of the tabitems 83 std::vector< ImplTabItem > maItemList; 84 ListBox* mpListBox; 85 Size maMinSize; 86 }; 87 88 // ----------------------------------------------------------------------- 89 90 #define TAB_OFFSET 3 91 #define TAB_TABOFFSET_X 3 92 #define TAB_TABOFFSET_Y 3 93 #define TAB_EXTRASPACE_X 6 94 #define TAB_BORDER_LEFT 1 95 #define TAB_BORDER_TOP 1 96 #define TAB_BORDER_RIGHT 2 97 #define TAB_BORDER_BOTTOM 2 98 99 // Fuer die Ermittlung von den Tab-Positionen 100 #define TAB_PAGERECT 0xFFFF 101 102 // ======================================================================= 103 104 void TabControl::ImplInit( Window* pParent, WinBits nStyle ) 105 { 106 if ( !(nStyle & WB_NOTABSTOP) ) 107 nStyle |= WB_TABSTOP; 108 if ( !(nStyle & WB_NOGROUP) ) 109 nStyle |= WB_GROUP; 110 if ( !(nStyle & WB_NODIALOGCONTROL) ) 111 nStyle |= WB_DIALOGCONTROL; 112 113 Control::ImplInit( pParent, nStyle, NULL ); 114 115 mnLastWidth = 0; 116 mnLastHeight = 0; 117 mnBtnSize = 0; 118 mnMaxPageWidth = 0; 119 mnActPageId = 0; 120 mnCurPageId = 0; 121 mbFormat = sal_True; 122 mbRestoreHelpId = sal_False; 123 mbRestoreUnqId = sal_False; 124 mbSmallInvalidate = sal_False; 125 mbExtraSpace = sal_False; 126 mpTabCtrlData = new ImplTabCtrlData; 127 mpTabCtrlData->mpListBox = NULL; 128 129 130 ImplInitSettings( sal_True, sal_True, sal_True ); 131 132 if( (nStyle & WB_DROPDOWN) ) 133 { 134 mpTabCtrlData->mpListBox = new ListBox( this, WB_DROPDOWN ); 135 mpTabCtrlData->mpListBox->SetPosSizePixel( Point( 0, 0 ), Size( 200, 20 ) ); 136 mpTabCtrlData->mpListBox->SetSelectHdl( LINK( this, TabControl, ImplListBoxSelectHdl ) ); 137 mpTabCtrlData->mpListBox->Show(); 138 } 139 140 // if the tabcontrol is drawn (ie filled) by a native widget, make sure all contols will have transparent background 141 // otherwise they will paint with a wrong background 142 if( IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL) ) 143 EnableChildTransparentMode( sal_True ); 144 145 if ( pParent->IsDialog() ) 146 pParent->AddChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) ); 147 } 148 149 // ----------------------------------------------------------------- 150 151 const Font& TabControl::GetCanonicalFont( const StyleSettings& _rStyle ) const 152 { 153 return _rStyle.GetAppFont(); 154 } 155 156 // ----------------------------------------------------------------- 157 const Color& TabControl::GetCanonicalTextColor( const StyleSettings& _rStyle ) const 158 { 159 return _rStyle.GetButtonTextColor(); 160 } 161 162 // ----------------------------------------------------------------------- 163 164 void TabControl::ImplInitSettings( sal_Bool bFont, 165 sal_Bool bForeground, sal_Bool bBackground ) 166 { 167 Control::ImplInitSettings( bFont, bForeground ); 168 169 if ( bBackground ) 170 { 171 Window* pParent = GetParent(); 172 if ( !IsControlBackground() && 173 (pParent->IsChildTransparentModeEnabled() 174 || IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL) 175 || IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) ) ) 176 177 { 178 // set transparent mode for NWF tabcontrols to have 179 // the background always cleared properly 180 EnableChildTransparentMode( sal_True ); 181 SetParentClipMode( PARENTCLIPMODE_NOCLIP ); 182 SetPaintTransparent( sal_True ); 183 SetBackground(); 184 ImplGetWindowImpl()->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects; 185 } 186 else 187 { 188 EnableChildTransparentMode( sal_False ); 189 SetParentClipMode( 0 ); 190 SetPaintTransparent( sal_False ); 191 192 if ( IsControlBackground() ) 193 SetBackground( GetControlBackground() ); 194 else 195 SetBackground( pParent->GetBackground() ); 196 } 197 } 198 } 199 200 // ----------------------------------------------------------------------- 201 202 void TabControl::ImplFreeLayoutData() 203 { 204 if( HasLayoutData() ) 205 { 206 ImplClearLayoutData(); 207 mpTabCtrlData->maLayoutPageIdToLine.clear(); 208 mpTabCtrlData->maLayoutLineToPageId.clear(); 209 } 210 } 211 212 // ----------------------------------------------------------------------- 213 214 TabControl::TabControl( Window* pParent, WinBits nStyle ) : 215 Control( WINDOW_TABCONTROL ) 216 { 217 ImplInit( pParent, nStyle ); 218 } 219 220 // ----------------------------------------------------------------------- 221 222 TabControl::TabControl( Window* pParent, const ResId& rResId ) : 223 Control( WINDOW_TABCONTROL ) 224 { 225 rResId.SetRT( RSC_TABCONTROL ); 226 WinBits nStyle = ImplInitRes( rResId ); 227 ImplInit( pParent, nStyle ); 228 ImplLoadRes( rResId ); 229 230 if ( !(nStyle & WB_HIDE) ) 231 Show(); 232 } 233 234 // ----------------------------------------------------------------------- 235 236 void TabControl::ImplLoadRes( const ResId& rResId ) 237 { 238 Control::ImplLoadRes( rResId ); 239 240 sal_uLong nObjMask = ReadLongRes(); 241 242 if ( nObjMask & RSC_TABCONTROL_ITEMLIST ) 243 { 244 sal_uLong nEle = ReadLongRes(); 245 246 // Item hinzufuegen 247 for( sal_uLong i = 0; i < nEle; i++ ) 248 { 249 InsertPage( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) ); 250 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) ); 251 } 252 } 253 } 254 255 // ----------------------------------------------------------------------- 256 257 TabControl::~TabControl() 258 { 259 if ( GetParent()->IsDialog() ) 260 GetParent()->RemoveChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) ); 261 262 ImplFreeLayoutData(); 263 264 // TabCtrl-Daten loeschen 265 if ( mpTabCtrlData ) 266 { 267 if( mpTabCtrlData->mpListBox ) 268 delete mpTabCtrlData->mpListBox; 269 delete mpTabCtrlData; 270 } 271 } 272 273 // ----------------------------------------------------------------------- 274 275 ImplTabItem* TabControl::ImplGetItem( sal_uInt16 nId ) const 276 { 277 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin(); 278 it != mpTabCtrlData->maItemList.end(); ++it ) 279 { 280 if( it->mnId == nId ) 281 return &(*it); 282 } 283 284 return NULL; 285 } 286 287 // ----------------------------------------------------------------------- 288 289 Size TabControl::ImplGetItemSize( ImplTabItem* pItem, long nMaxWidth ) 290 { 291 pItem->maFormatText = pItem->maText; 292 Size aSize( GetCtrlTextWidth( pItem->maFormatText ), GetTextHeight() ); 293 Size aImageSize( 0, 0 ); 294 if( !!pItem->maTabImage ) 295 { 296 aImageSize = pItem->maTabImage.GetSizePixel(); 297 if( pItem->maFormatText.Len() ) 298 aImageSize.Width() += GetTextHeight()/4; 299 } 300 aSize.Width() += aImageSize.Width(); 301 if( aImageSize.Height() > aSize.Height() ) 302 aSize.Height() = aImageSize.Height(); 303 304 aSize.Width() += TAB_TABOFFSET_X*2; 305 aSize.Height() += TAB_TABOFFSET_Y*2; 306 307 Rectangle aCtrlRegion( Point( 0, 0 ), aSize ); 308 Rectangle aBoundingRgn, aContentRgn; 309 const ImplControlValue aControlValue; 310 if(GetNativeControlRegion( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion, 311 CTRL_STATE_ENABLED, aControlValue, rtl::OUString(), 312 aBoundingRgn, aContentRgn ) ) 313 { 314 return aContentRgn.GetSize(); 315 } 316 317 // For systems without synthetic bold support 318 if ( mbExtraSpace ) 319 aSize.Width() += TAB_EXTRASPACE_X; 320 // For languages with short names (e.g. Chinese), because the space is 321 // normally only one pixel per char 322 else if ( pItem->maFormatText.Len() < TAB_EXTRASPACE_X ) 323 aSize.Width() += TAB_EXTRASPACE_X-pItem->maFormatText.Len(); 324 325 // Evt. den Text kuerzen 326 if ( aSize.Width()+4 >= nMaxWidth ) 327 { 328 XubString aAppendStr( RTL_CONSTASCII_USTRINGPARAM( "..." ) ); 329 pItem->maFormatText += aAppendStr; 330 do 331 { 332 pItem->maFormatText.Erase( pItem->maFormatText.Len()-aAppendStr.Len()-1, 1 ); 333 aSize.Width() = GetCtrlTextWidth( pItem->maFormatText ); 334 aSize.Width() += aImageSize.Width(); 335 aSize.Width() += TAB_TABOFFSET_X*2; 336 } 337 while ( (aSize.Width()+4 >= nMaxWidth) && (pItem->maFormatText.Len() > aAppendStr.Len()) ); 338 if ( aSize.Width()+4 >= nMaxWidth ) 339 { 340 pItem->maFormatText.Assign( '.' ); 341 aSize.Width() = 1; 342 } 343 } 344 345 if( pItem->maFormatText.Len() == 0 ) 346 { 347 if( aSize.Height() < aImageSize.Height()+4 ) //leave space for focus rect 348 aSize.Height() = aImageSize.Height()+4; 349 } 350 351 return aSize; 352 } 353 354 // ----------------------------------------------------------------------- 355 356 Rectangle TabControl::ImplGetTabRect( sal_uInt16 nItemPos, long nWidth, long nHeight ) 357 { 358 Size aWinSize = Control::GetOutputSizePixel(); 359 if ( nWidth < 0 ) 360 nWidth = aWinSize.Width(); 361 if ( nHeight < 0 ) 362 nHeight = aWinSize.Height(); 363 364 if ( mpTabCtrlData->maItemList.empty() ) 365 { 366 long nW = nWidth-TAB_OFFSET*2; 367 long nH = nHeight-TAB_OFFSET*2; 368 return (nW > 0 && nH > 0) 369 ? Rectangle( Point( TAB_OFFSET, TAB_OFFSET ), Size( nW, nH ) ) 370 : Rectangle(); 371 } 372 373 if ( nItemPos == TAB_PAGERECT ) 374 { 375 sal_uInt16 nLastPos; 376 if ( mnCurPageId ) 377 nLastPos = GetPagePos( mnCurPageId ); 378 else 379 nLastPos = 0; 380 381 Rectangle aRect = ImplGetTabRect( nLastPos, nWidth, nHeight ); 382 long nW = nWidth-TAB_OFFSET*2; 383 long nH = nHeight-aRect.Bottom()-TAB_OFFSET*2; 384 aRect = (nW > 0 && nH > 0) 385 ? Rectangle( Point( TAB_OFFSET, aRect.Bottom()+TAB_OFFSET ), Size( nW, nH ) ) 386 : Rectangle(); 387 return aRect; 388 } 389 390 nWidth -= 1; 391 392 if ( (nWidth <= 0) || (nHeight <= 0) ) 393 return Rectangle(); 394 395 if ( mbFormat || (mnLastWidth != nWidth) || (mnLastHeight != nHeight) ) 396 { 397 Font aFont( GetFont() ); 398 Font aLightFont = aFont; 399 aFont.SetTransparent( sal_True ); 400 aFont.SetWeight( (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus) ? WEIGHT_BOLD : WEIGHT_LIGHT ); 401 aLightFont.SetTransparent( sal_True ); 402 aLightFont.SetWeight( WEIGHT_LIGHT ); 403 404 // If Bold and none Bold strings have the same width, we 405 // add in the calcultion extra space, so that the tabs 406 // looks better. The could be the case on systems without 407 // an bold UI font and without synthetic bold support 408 XubString aTestStr( RTL_CONSTASCII_USTRINGPARAM( "Abc." ) ); 409 SetFont( aLightFont ); 410 long nTextWidth1 = GetTextWidth( aTestStr ); 411 SetFont( aFont ); 412 long nTextWidth2 = GetTextWidth( aTestStr ); 413 mbExtraSpace = (nTextWidth1 == nTextWidth2); 414 415 Size aSize; 416 const long nOffsetX = 2 + GetItemsOffset().X(); 417 const long nOffsetY = 2 + GetItemsOffset().Y(); 418 long nX = nOffsetX; 419 long nY = nOffsetY; 420 long nMaxWidth = nWidth; 421 sal_uInt16 nPos = 0; 422 423 if ( (mnMaxPageWidth > 0) && (mnMaxPageWidth < nMaxWidth) ) 424 nMaxWidth = mnMaxPageWidth; 425 nMaxWidth -= GetItemsOffset().X(); 426 427 sal_uInt16 nLines = 0; 428 sal_uInt16 nCurLine = 0; 429 long nLineWidthAry[100]; 430 sal_uInt16 nLinePosAry[101]; 431 432 nLineWidthAry[0] = 0; 433 nLinePosAry[0] = 0; 434 for( std::vector<ImplTabItem>::iterator it = mpTabCtrlData->maItemList.begin(); 435 it != mpTabCtrlData->maItemList.end(); ++it ) 436 { 437 aSize = ImplGetItemSize( &(*it), nMaxWidth ); 438 439 if ( ((nX+aSize.Width()) > nWidth - 2) && (nWidth > 2+nOffsetX) ) 440 { 441 if ( nLines == 99 ) 442 break; 443 444 nX = nOffsetX; 445 nY += aSize.Height(); 446 nLines++; 447 nLineWidthAry[nLines] = 0; 448 nLinePosAry[nLines] = nPos; 449 } 450 451 Rectangle aNewRect( Point( nX, nY ), aSize ); 452 if ( mbSmallInvalidate && (it->maRect != aNewRect) ) 453 mbSmallInvalidate = sal_False; 454 it->maRect = aNewRect; 455 it->mnLine = nLines; 456 it->mbFullVisible = sal_True; 457 458 nLineWidthAry[nLines] += aSize.Width(); 459 nX += aSize.Width(); 460 461 if ( it->mnId == mnCurPageId ) 462 nCurLine = nLines; 463 464 nPos++; 465 } 466 467 if ( nLines && !mpTabCtrlData->maItemList.empty() ) 468 { 469 long nDX = 0; 470 long nModDX = 0; 471 long nIDX = 0; 472 sal_uInt16 i; 473 sal_uInt16 n; 474 long nLineHeightAry[100]; 475 long nIH = mpTabCtrlData->maItemList[0].maRect.Bottom()-2; 476 477 i = 0; 478 while ( i < nLines+1 ) 479 { 480 if ( i <= nCurLine ) 481 nLineHeightAry[i] = nIH*(nLines-(nCurLine-i)) + GetItemsOffset().Y(); 482 else 483 nLineHeightAry[i] = nIH*(i-nCurLine-1) + GetItemsOffset().Y(); 484 i++; 485 } 486 487 i = 0; 488 n = 0; 489 nLinePosAry[nLines+1] = (sal_uInt16)mpTabCtrlData->maItemList.size(); 490 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin(); 491 it != mpTabCtrlData->maItemList.end(); ++it ) 492 { 493 if ( i == nLinePosAry[n] ) 494 { 495 if ( n == nLines+1 ) 496 break; 497 498 nIDX = 0; 499 if( nLinePosAry[n+1]-i > 0 ) 500 { 501 nDX = (nWidth-nOffsetX-nLineWidthAry[n]) / (nLinePosAry[n+1]-i); 502 nModDX = (nWidth-nOffsetX-nLineWidthAry[n]) % (nLinePosAry[n+1]-i); 503 } 504 else 505 { 506 // FIXME: this is a bad case of tabctrl way too small 507 nDX = 0; 508 nModDX = 0; 509 } 510 n++; 511 } 512 513 it->maRect.Left() += nIDX; 514 it->maRect.Right() += nIDX+nDX; 515 it->maRect.Top() = nLineHeightAry[n-1]; 516 it->maRect.Bottom() = nLineHeightAry[n-1]+nIH; 517 nIDX += nDX; 518 519 if ( nModDX ) 520 { 521 nIDX++; 522 it->maRect.Right()++; 523 nModDX--; 524 } 525 526 i++; 527 } 528 } 529 else 530 {//only one line 531 if(ImplGetSVData()->maNWFData.mbCenteredTabs) 532 { 533 int nRightSpace=nMaxWidth;//space left on the right by the tabs 534 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin(); 535 it != mpTabCtrlData->maItemList.end(); ++it ) 536 { 537 nRightSpace-=it->maRect.Right()-it->maRect.Left(); 538 } 539 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin(); 540 it != mpTabCtrlData->maItemList.end(); ++it ) 541 { 542 it->maRect.Left()+=(int) (nRightSpace/2); 543 it->maRect.Right()+=(int) (nRightSpace/2); 544 } 545 } 546 } 547 548 mnLastWidth = nWidth; 549 mnLastHeight = nHeight; 550 mbFormat = sal_False; 551 } 552 553 return size_t(nItemPos) < mpTabCtrlData->maItemList.size() ? mpTabCtrlData->maItemList[nItemPos].maRect : Rectangle(); 554 } 555 556 // ----------------------------------------------------------------------- 557 558 void TabControl::ImplChangeTabPage( sal_uInt16 nId, sal_uInt16 nOldId ) 559 { 560 ImplFreeLayoutData(); 561 562 ImplTabItem* pOldItem = ImplGetItem( nOldId ); 563 ImplTabItem* pItem = ImplGetItem( nId ); 564 TabPage* pOldPage = (pOldItem) ? pOldItem->mpTabPage : NULL; 565 TabPage* pPage = (pItem) ? pItem->mpTabPage : NULL; 566 Window* pCtrlParent = GetParent(); 567 568 if ( IsReallyVisible() && IsUpdateMode() ) 569 { 570 sal_uInt16 nPos = GetPagePos( nId ); 571 Rectangle aRect = ImplGetTabRect( nPos ); 572 573 if ( !pOldItem || (pOldItem->mnLine != pItem->mnLine) ) 574 { 575 aRect.Left() = 0; 576 aRect.Top() = 0; 577 aRect.Right() = Control::GetOutputSizePixel().Width(); 578 } 579 else 580 { 581 aRect.Left() -= 3; 582 aRect.Top() -= 2; 583 aRect.Right() += 3; 584 Invalidate( aRect ); 585 nPos = GetPagePos( nOldId ); 586 aRect = ImplGetTabRect( nPos ); 587 aRect.Left() -= 3; 588 aRect.Top() -= 2; 589 aRect.Right() += 3; 590 } 591 Invalidate( aRect ); 592 } 593 594 if ( pOldPage == pPage ) 595 return; 596 597 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT ); 598 599 if ( pOldPage ) 600 { 601 if ( mbRestoreHelpId ) 602 pCtrlParent->SetHelpId( rtl::OString() ); 603 if ( mbRestoreUnqId ) 604 pCtrlParent->SetUniqueId( rtl::OString() ); 605 pOldPage->DeactivatePage(); 606 } 607 608 if ( pPage ) 609 { 610 pPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() ); 611 612 // activate page here so the conbtrols can be switched 613 // also set the help id of the parent window to that of the tab page 614 if ( !GetHelpId().getLength() ) 615 { 616 mbRestoreHelpId = sal_True; 617 pCtrlParent->SetHelpId( pPage->GetHelpId() ); 618 } 619 if ( !pCtrlParent->GetUniqueId().getLength() ) 620 { 621 mbRestoreUnqId = sal_True; 622 pCtrlParent->SetUniqueId( pPage->GetUniqueId() ); 623 } 624 625 pPage->ActivatePage(); 626 627 if ( pOldPage && pOldPage->HasChildPathFocus() ) 628 { 629 sal_uInt16 n = 0; 630 Window* pFirstChild = pPage->ImplGetDlgWindow( n, DLGWINDOW_FIRST ); 631 if ( pFirstChild ) 632 pFirstChild->ImplControlFocus( GETFOCUS_INIT ); 633 else 634 GrabFocus(); 635 } 636 637 pPage->Show(); 638 } 639 640 if ( pOldPage ) 641 pOldPage->Hide(); 642 643 // Invalidate the same region that will be send to NWF 644 // to always allow for bitmap caching 645 // see Window::DrawNativeControl() 646 if( IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL ) ) 647 { 648 aRect.Left() -= TAB_OFFSET; 649 aRect.Top() -= TAB_OFFSET; 650 aRect.Right() += TAB_OFFSET; 651 aRect.Bottom() += TAB_OFFSET; 652 } 653 654 Invalidate( aRect ); 655 } 656 657 // ----------------------------------------------------------------------- 658 659 sal_Bool TabControl::ImplPosCurTabPage() 660 { 661 // Aktuelle TabPage resizen/positionieren 662 ImplTabItem* pItem = ImplGetItem( GetCurPageId() ); 663 if ( pItem && pItem->mpTabPage ) 664 { 665 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT ); 666 pItem->mpTabPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() ); 667 return sal_True; 668 } 669 670 return sal_False; 671 } 672 673 // ----------------------------------------------------------------------- 674 675 void TabControl::ImplActivateTabPage( sal_Bool bNext ) 676 { 677 sal_uInt16 nCurPos = GetPagePos( GetCurPageId() ); 678 679 if ( bNext ) 680 nCurPos = (nCurPos + 1) % GetPageCount(); 681 else 682 { 683 if ( !nCurPos ) 684 nCurPos = GetPageCount()-1; 685 else 686 nCurPos--; 687 } 688 689 SelectTabPage( GetPageId( nCurPos ) ); 690 } 691 692 // ----------------------------------------------------------------------- 693 694 void TabControl::ImplShowFocus() 695 { 696 if ( !GetPageCount() || mpTabCtrlData->mpListBox ) 697 return; 698 699 // make sure the focussed item rect is computed using a bold font 700 // the font may have changed meanwhile due to mouse over 701 702 Font aOldFont( GetFont() ); 703 Font aFont( aOldFont ); 704 aFont.SetWeight( (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus) ? WEIGHT_BOLD : WEIGHT_LIGHT ); 705 SetFont( aFont ); 706 707 sal_uInt16 nCurPos = GetPagePos( mnCurPageId ); 708 Rectangle aRect = ImplGetTabRect( nCurPos ); 709 const ImplTabItem& rItem = mpTabCtrlData->maItemList[ nCurPos ]; 710 Size aTabSize = aRect.GetSize(); 711 Size aImageSize( 0, 0 ); 712 long nTextHeight = GetTextHeight(); 713 long nTextWidth = GetCtrlTextWidth( rItem.maFormatText ); 714 sal_uInt16 nOff; 715 716 if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_MONO) ) 717 nOff = 1; 718 else 719 nOff = 0; 720 721 if( !! rItem.maTabImage ) 722 { 723 aImageSize = rItem.maTabImage.GetSizePixel(); 724 if( rItem.maFormatText.Len() ) 725 aImageSize.Width() += GetTextHeight()/4; 726 } 727 728 if( rItem.maFormatText.Len() ) 729 { 730 // show focus around text 731 aRect.Left() = aRect.Left()+aImageSize.Width()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1-1; 732 aRect.Top() = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-1-1; 733 aRect.Right() = aRect.Left()+nTextWidth+2; 734 aRect.Bottom() = aRect.Top()+nTextHeight+2; 735 } 736 else 737 { 738 // show focus around image 739 long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1; 740 long nYPos = aRect.Top(); 741 if( aImageSize.Height() < aRect.GetHeight() ) 742 nYPos += (aRect.GetHeight() - aImageSize.Height())/2; 743 744 aRect.Left() = nXPos - 2; 745 aRect.Top() = nYPos - 2; 746 aRect.Right() = aRect.Left() + aImageSize.Width() + 4; 747 aRect.Bottom() = aRect.Top() + aImageSize.Height() + 4; 748 } 749 ShowFocus( aRect ); 750 751 SetFont( aOldFont ); 752 } 753 754 // ----------------------------------------------------------------------- 755 756 void TabControl::ImplDrawItem( ImplTabItem* pItem, const Rectangle& rCurRect, bool bLayout, bool bFirstInGroup, bool bLastInGroup, bool bIsCurrentItem ) 757 { 758 if ( pItem->maRect.IsEmpty() ) 759 return; 760 761 if( bLayout ) 762 { 763 if( !HasLayoutData() ) 764 { 765 mpControlData->mpLayoutData = new vcl::ControlLayoutData(); 766 mpTabCtrlData->maLayoutLineToPageId.clear(); 767 mpTabCtrlData->maLayoutPageIdToLine.clear(); 768 mpTabCtrlData->maTabRectangles.clear(); 769 } 770 } 771 772 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); 773 Rectangle aRect = pItem->maRect; 774 long nLeftBottom = aRect.Bottom(); 775 long nRightBottom = aRect.Bottom(); 776 sal_Bool bLeftBorder = sal_True; 777 sal_Bool bRightBorder = sal_True; 778 sal_uInt16 nOff; 779 sal_Bool bNativeOK = sal_False; 780 781 sal_uInt16 nOff2 = 0; 782 sal_uInt16 nOff3 = 0; 783 784 if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) 785 nOff = 1; 786 else 787 nOff = 0; 788 789 // Wenn wir die aktuelle Page sind, muessen wir etwas mehr zeichnen 790 if ( pItem->mnId == mnCurPageId ) 791 { 792 nOff2 = 2; 793 if( ! ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise ) 794 nOff3 = 1; 795 } 796 else 797 { 798 Point aLeftTestPos = aRect.BottomLeft(); 799 Point aRightTestPos = aRect.BottomRight(); 800 if ( aLeftTestPos.Y() == rCurRect.Bottom() ) 801 { 802 aLeftTestPos.X() -= 2; 803 if ( rCurRect.IsInside( aLeftTestPos ) ) 804 bLeftBorder = sal_False; 805 aRightTestPos.X() += 2; 806 if ( rCurRect.IsInside( aRightTestPos ) ) 807 bRightBorder = sal_False; 808 } 809 else 810 { 811 if ( rCurRect.IsInside( aLeftTestPos ) ) 812 nLeftBottom -= 2; 813 if ( rCurRect.IsInside( aRightTestPos ) ) 814 nRightBottom -= 2; 815 } 816 } 817 818 if( !bLayout && (bNativeOK = IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL)) == sal_True ) 819 { 820 Rectangle aCtrlRegion( pItem->maRect ); 821 ControlState nState = 0; 822 823 if( pItem->mnId == mnCurPageId ) 824 { 825 nState |= CTRL_STATE_SELECTED; 826 // only the selected item can be focussed 827 if ( HasFocus() ) 828 nState |= CTRL_STATE_FOCUSED; 829 } 830 if ( IsEnabled() ) 831 nState |= CTRL_STATE_ENABLED; 832 if( IsMouseOver() && pItem->maRect.IsInside( GetPointerPosPixel() ) ) 833 { 834 nState |= CTRL_STATE_ROLLOVER; 835 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin(); 836 it != mpTabCtrlData->maItemList.end(); ++it ) 837 { 838 if( (&(*it) != pItem) && (it->maRect.IsInside( GetPointerPosPixel() ) ) ) 839 { 840 nState &= ~CTRL_STATE_ROLLOVER; // avoid multiple highlighted tabs 841 break; 842 } 843 } 844 } 845 846 TabitemValue tiValue; 847 if(pItem->maRect.Left() < 5) 848 tiValue.mnAlignment |= TABITEM_LEFTALIGNED; 849 if(pItem->maRect.Right() > mnLastWidth - 5) 850 tiValue.mnAlignment |= TABITEM_RIGHTALIGNED; 851 if ( bFirstInGroup ) 852 tiValue.mnAlignment |= TABITEM_FIRST_IN_GROUP; 853 if ( bLastInGroup ) 854 tiValue.mnAlignment |= TABITEM_LAST_IN_GROUP; 855 856 bNativeOK = DrawNativeControl( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion, nState, 857 tiValue, rtl::OUString() ); 858 } 859 860 if( ! bLayout && !bNativeOK ) 861 { 862 if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) 863 { 864 SetLineColor( rStyleSettings.GetLightColor() ); 865 DrawPixel( Point( aRect.Left()+1-nOff2, aRect.Top()+1-nOff2 ) ); // diagonally indented top-left pixel 866 if ( bLeftBorder ) 867 { 868 DrawLine( Point( aRect.Left()-nOff2, aRect.Top()+2-nOff2 ), 869 Point( aRect.Left()-nOff2, nLeftBottom-1 ) ); 870 } 871 DrawLine( Point( aRect.Left()+2-nOff2, aRect.Top()-nOff2 ), // top line starting 2px from left border 872 Point( aRect.Right()+nOff2-3, aRect.Top()-nOff2 ) ); // ending 3px from right border 873 874 if ( bRightBorder ) 875 { 876 SetLineColor( rStyleSettings.GetShadowColor() ); 877 DrawLine( Point( aRect.Right()+nOff2-2, aRect.Top()+1-nOff2 ), 878 Point( aRect.Right()+nOff2-2, nRightBottom-1 ) ); 879 880 SetLineColor( rStyleSettings.GetDarkShadowColor() ); 881 DrawLine( Point( aRect.Right()+nOff2-1, aRect.Top()+3-nOff2 ), 882 Point( aRect.Right()+nOff2-1, nRightBottom-1 ) ); 883 } 884 } 885 else 886 { 887 SetLineColor( Color( COL_BLACK ) ); 888 DrawPixel( Point( aRect.Left()+1-nOff2, aRect.Top()+1-nOff2 ) ); 889 DrawPixel( Point( aRect.Right()+nOff2-2, aRect.Top()+1-nOff2 ) ); 890 if ( bLeftBorder ) 891 { 892 DrawLine( Point( aRect.Left()-nOff2, aRect.Top()+2-nOff2 ), 893 Point( aRect.Left()-nOff2, nLeftBottom-1 ) ); 894 } 895 DrawLine( Point( aRect.Left()+2-nOff2, aRect.Top()-nOff2 ), 896 Point( aRect.Right()-3, aRect.Top()-nOff2 ) ); 897 if ( bRightBorder ) 898 { 899 DrawLine( Point( aRect.Right()+nOff2-1, aRect.Top()+2-nOff2 ), 900 Point( aRect.Right()+nOff2-1, nRightBottom-1 ) ); 901 } 902 } 903 } 904 905 if( bLayout ) 906 { 907 int nLine = mpControlData->mpLayoutData->m_aLineIndices.size(); 908 mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.Len() ); 909 mpTabCtrlData->maLayoutPageIdToLine[ (int)pItem->mnId ] = nLine; 910 mpTabCtrlData->maLayoutLineToPageId[ nLine ] = (int)pItem->mnId; 911 mpTabCtrlData->maTabRectangles.push_back( aRect ); 912 } 913 914 // set font accordingly, current item is painted bold 915 // we set the font attributes always before drawing to be re-entrant (DrawNativeControl may trigger additional paints) 916 Font aFont( GetFont() ); 917 aFont.SetTransparent( sal_True ); 918 aFont.SetWeight( ((bIsCurrentItem) && (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus)) ? WEIGHT_BOLD : WEIGHT_LIGHT ); 919 SetFont( aFont ); 920 921 Size aTabSize = aRect.GetSize(); 922 Size aImageSize( 0, 0 ); 923 long nTextHeight = GetTextHeight(); 924 long nTextWidth = GetCtrlTextWidth( pItem->maFormatText ); 925 if( !! pItem->maTabImage ) 926 { 927 aImageSize = pItem->maTabImage.GetSizePixel(); 928 if( pItem->maFormatText.Len() ) 929 aImageSize.Width() += GetTextHeight()/4; 930 } 931 long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-nOff3; 932 long nYPos = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-nOff3; 933 if( pItem->maFormatText.Len() ) 934 { 935 sal_uInt16 nStyle = TEXT_DRAW_MNEMONIC; 936 if( ! pItem->mbEnabled ) 937 nStyle |= TEXT_DRAW_DISABLE; 938 DrawCtrlText( Point( nXPos + aImageSize.Width(), nYPos ), 939 pItem->maFormatText, 940 0, STRING_LEN, nStyle, 941 bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL, 942 bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL 943 ); 944 } 945 946 if( !! pItem->maTabImage ) 947 { 948 Point aImgTL( nXPos, aRect.Top() ); 949 if( aImageSize.Height() < aRect.GetHeight() ) 950 aImgTL.Y() += (aRect.GetHeight() - aImageSize.Height())/2; 951 DrawImage( aImgTL, pItem->maTabImage, pItem->mbEnabled ? 0 : IMAGE_DRAW_DISABLE ); 952 } 953 } 954 955 // ----------------------------------------------------------------------- 956 957 long TabControl::ImplHandleKeyEvent( const KeyEvent& rKeyEvent ) 958 { 959 long nRet = 0; 960 961 if ( GetPageCount() > 1 ) 962 { 963 KeyCode aKeyCode = rKeyEvent.GetKeyCode(); 964 sal_uInt16 nKeyCode = aKeyCode.GetCode(); 965 966 if ( aKeyCode.IsMod1() ) 967 { 968 if ( aKeyCode.IsShift() || (nKeyCode == KEY_PAGEUP) ) 969 { 970 if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEUP) ) 971 { 972 ImplActivateTabPage( sal_False ); 973 nRet = 1; 974 } 975 } 976 else 977 { 978 if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEDOWN) ) 979 { 980 ImplActivateTabPage( sal_True ); 981 nRet = 1; 982 } 983 } 984 } 985 } 986 987 return nRet; 988 } 989 990 991 // ----------------------------------------------------------------------- 992 993 IMPL_LINK( TabControl, ImplListBoxSelectHdl, ListBox*, EMPTYARG ) 994 { 995 SelectTabPage( GetPageId( mpTabCtrlData->mpListBox->GetSelectEntryPos() ) ); 996 return 0; 997 } 998 999 // ----------------------------------------------------------------------- 1000 1001 IMPL_LINK( TabControl, ImplWindowEventListener, VclSimpleEvent*, pEvent ) 1002 { 1003 if ( pEvent && pEvent->ISA( VclWindowEvent ) && (pEvent->GetId() == VCLEVENT_WINDOW_KEYINPUT) ) 1004 { 1005 VclWindowEvent* pWindowEvent = static_cast< VclWindowEvent* >(pEvent); 1006 // Do not handle events from TabControl or it's children, which is done in Notify(), where the events can be consumed. 1007 if ( !IsWindowOrChild( pWindowEvent->GetWindow() ) ) 1008 { 1009 KeyEvent* pKeyEvent = static_cast< KeyEvent* >(pWindowEvent->GetData()); 1010 ImplHandleKeyEvent( *pKeyEvent ); 1011 } 1012 } 1013 return 0; 1014 } 1015 1016 1017 // ----------------------------------------------------------------------- 1018 1019 void TabControl::MouseButtonDown( const MouseEvent& rMEvt ) 1020 { 1021 if( mpTabCtrlData->mpListBox == NULL ) 1022 { 1023 if( rMEvt.IsLeft() ) 1024 { 1025 sal_uInt16 nPageId = GetPageId( rMEvt.GetPosPixel() ); 1026 ImplTabItem* pItem = ImplGetItem( nPageId ); 1027 if( pItem && pItem->mbEnabled ) 1028 SelectTabPage( nPageId ); 1029 } 1030 } 1031 } 1032 1033 // ----------------------------------------------------------------------- 1034 1035 void TabControl::KeyInput( const KeyEvent& rKEvt ) 1036 { 1037 if( mpTabCtrlData->mpListBox ) 1038 mpTabCtrlData->mpListBox->KeyInput( rKEvt ); 1039 else if ( GetPageCount() > 1 ) 1040 { 1041 KeyCode aKeyCode = rKEvt.GetKeyCode(); 1042 sal_uInt16 nKeyCode = aKeyCode.GetCode(); 1043 1044 if ( (nKeyCode == KEY_LEFT) || (nKeyCode == KEY_RIGHT) ) 1045 { 1046 sal_Bool bNext = (nKeyCode == KEY_RIGHT); 1047 ImplActivateTabPage( bNext ); 1048 } 1049 } 1050 1051 Control::KeyInput( rKEvt ); 1052 } 1053 1054 // ----------------------------------------------------------------------- 1055 1056 void TabControl::Paint( const Rectangle& rRect ) 1057 { 1058 ImplPaint( rRect, false ); 1059 } 1060 1061 // ----------------------------------------------------------------------- 1062 1063 void TabControl::ImplPaint( const Rectangle& rRect, bool bLayout ) 1064 { 1065 if( ! bLayout ) 1066 HideFocus(); 1067 1068 // Hier wird gegebenenfalls auch neu formatiert 1069 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT ); 1070 1071 // find current item 1072 ImplTabItem* pCurItem = NULL; 1073 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin(); 1074 it != mpTabCtrlData->maItemList.end(); ++it ) 1075 { 1076 if ( it->mnId == mnCurPageId ) 1077 { 1078 pCurItem = &(*it); 1079 break; 1080 } 1081 } 1082 1083 // Draw the TabPage border 1084 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); 1085 Rectangle aCurRect; 1086 long nTopOff = 1; 1087 aRect.Left() -= TAB_OFFSET; 1088 aRect.Top() -= TAB_OFFSET; 1089 aRect.Right() += TAB_OFFSET; 1090 aRect.Bottom() += TAB_OFFSET; 1091 1092 // if we have an invisible tabpage or no tabpage at all the tabpage rect should be 1093 // increased to avoid round corners that might be drawn by a theme 1094 // in this case we're only interested in the top border of the tabpage because the tabitems are used 1095 // standalone (eg impress) 1096 sal_Bool bNoTabPage = sal_False; 1097 TabPage* pCurPage = (pCurItem) ? pCurItem->mpTabPage : NULL; 1098 if( !pCurPage || !pCurPage->IsVisible() ) 1099 { 1100 bNoTabPage = sal_True; 1101 aRect.Left()-=10; 1102 aRect.Right()+=10; 1103 } 1104 1105 sal_Bool bNativeOK = sal_False; 1106 if( ! bLayout && (bNativeOK = IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL) ) == sal_True ) 1107 { 1108 const ImplControlValue aControlValue; 1109 1110 ControlState nState = CTRL_STATE_ENABLED; 1111 int part = PART_ENTIRE_CONTROL; 1112 if ( !IsEnabled() ) 1113 nState &= ~CTRL_STATE_ENABLED; 1114 if ( HasFocus() ) 1115 nState |= CTRL_STATE_FOCUSED; 1116 1117 Region aClipRgn( GetActiveClipRegion() ); 1118 aClipRgn.Intersect( aRect ); 1119 if( !rRect.IsEmpty() ) 1120 aClipRgn.Intersect( rRect ); 1121 1122 if( !aClipRgn.IsEmpty() ) 1123 bNativeOK = DrawNativeControl( CTRL_TAB_PANE, part, aRect, nState, 1124 aControlValue, rtl::OUString() ); 1125 } 1126 else 1127 { 1128 if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) 1129 SetLineColor( rStyleSettings.GetLightColor() ); 1130 else 1131 SetLineColor( Color( COL_BLACK ) ); 1132 if ( pCurItem && !pCurItem->maRect.IsEmpty() ) 1133 { 1134 aCurRect = pCurItem->maRect; 1135 if( ! bLayout ) 1136 DrawLine( aRect.TopLeft(), Point( aCurRect.Left()-2, aRect.Top() ) ); 1137 if ( aCurRect.Right()+1 < aRect.Right() ) 1138 { 1139 if( ! bLayout ) 1140 DrawLine( Point( aCurRect.Right(), aRect.Top() ), aRect.TopRight() ); 1141 } 1142 else 1143 nTopOff = 0; 1144 } 1145 else 1146 if( ! bLayout ) 1147 DrawLine( aRect.TopLeft(), aRect.TopRight() ); 1148 1149 if( ! bLayout ) 1150 { 1151 DrawLine( aRect.TopLeft(), aRect.BottomLeft() ); 1152 1153 if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) 1154 { 1155 // if we have not tab page the bottom line of the tab page 1156 // directly touches the tab items, so choose a color that fits seamlessly 1157 if( bNoTabPage ) 1158 SetLineColor( rStyleSettings.GetDialogColor() ); 1159 else 1160 SetLineColor( rStyleSettings.GetShadowColor() ); 1161 DrawLine( Point( 1, aRect.Bottom()-1 ), 1162 Point( aRect.Right()-1, aRect.Bottom()-1 ) ); 1163 DrawLine( Point( aRect.Right()-1, aRect.Top()+nTopOff ), 1164 Point( aRect.Right()-1, aRect.Bottom()-1 ) ); 1165 if( bNoTabPage ) 1166 SetLineColor( rStyleSettings.GetDialogColor() ); 1167 else 1168 SetLineColor( rStyleSettings.GetDarkShadowColor() ); 1169 DrawLine( Point( 0, aRect.Bottom() ), 1170 Point( aRect.Right(), aRect.Bottom() ) ); 1171 DrawLine( Point( aRect.Right(), aRect.Top()+nTopOff ), 1172 Point( aRect.Right(), aRect.Bottom() ) ); 1173 } 1174 else 1175 { 1176 DrawLine( aRect.TopRight(), aRect.BottomRight() ); 1177 DrawLine( aRect.BottomLeft(), aRect.BottomRight() ); 1178 } 1179 } 1180 } 1181 1182 if ( !mpTabCtrlData->maItemList.empty() && mpTabCtrlData->mpListBox == NULL ) 1183 { 1184 // Some native toolkits (GTK+) draw tabs right-to-left, with an 1185 // overlap between adjacent tabs 1186 bool bDrawTabsRTL = IsNativeControlSupported( CTRL_TAB_ITEM, PART_TABS_DRAW_RTL ); 1187 ImplTabItem * pFirstTab = NULL; 1188 ImplTabItem * pLastTab = NULL; 1189 size_t idx; 1190 1191 // Event though there is a tab overlap with GTK+, the first tab is not 1192 // overlapped on the left side. Other tookits ignore this option. 1193 if ( bDrawTabsRTL ) 1194 { 1195 pFirstTab = &mpTabCtrlData->maItemList.front(); 1196 pLastTab = &mpTabCtrlData->maItemList.back(); 1197 idx = mpTabCtrlData->maItemList.size()-1; 1198 } 1199 else 1200 { 1201 pLastTab = &mpTabCtrlData->maItemList.back(); 1202 pFirstTab = &mpTabCtrlData->maItemList.front(); 1203 idx = 0; 1204 } 1205 1206 while ( idx < mpTabCtrlData->maItemList.size() ) 1207 { 1208 ImplTabItem* pItem = &mpTabCtrlData->maItemList[idx]; 1209 if ( pItem != pCurItem ) 1210 { 1211 Region aClipRgn( GetActiveClipRegion() ); 1212 aClipRgn.Intersect( pItem->maRect ); 1213 if( !rRect.IsEmpty() ) 1214 aClipRgn.Intersect( rRect ); 1215 if( bLayout || !aClipRgn.IsEmpty() ) 1216 ImplDrawItem( pItem, aCurRect, bLayout, (pItem==pFirstTab), (pItem==pLastTab), sal_False ); 1217 } 1218 1219 if ( bDrawTabsRTL ) 1220 idx--; 1221 else 1222 idx++; 1223 } 1224 1225 if ( pCurItem ) 1226 { 1227 Region aClipRgn( GetActiveClipRegion() ); 1228 aClipRgn.Intersect( pCurItem->maRect ); 1229 if( !rRect.IsEmpty() ) 1230 aClipRgn.Intersect( rRect ); 1231 if( bLayout || !aClipRgn.IsEmpty() ) 1232 ImplDrawItem( pCurItem, aCurRect, bLayout, (pCurItem==pFirstTab), (pCurItem==pLastTab), sal_True ); 1233 } 1234 } 1235 1236 if ( !bLayout && HasFocus() ) 1237 ImplShowFocus(); 1238 1239 if( ! bLayout ) 1240 mbSmallInvalidate = sal_True; 1241 } 1242 1243 // ----------------------------------------------------------------------- 1244 1245 void TabControl::Resize() 1246 { 1247 ImplFreeLayoutData(); 1248 1249 if ( !IsReallyShown() ) 1250 return; 1251 1252 if( mpTabCtrlData->mpListBox ) 1253 { 1254 // get the listbox' preferred size 1255 Size aTabCtrlSize( GetSizePixel() ); 1256 long nPrefWidth = mpTabCtrlData->mpListBox->GetOptimalSize( WINDOWSIZE_PREFERRED ).Width(); 1257 if( nPrefWidth > aTabCtrlSize.Width() ) 1258 nPrefWidth = aTabCtrlSize.Width(); 1259 Size aNewSize( nPrefWidth, LogicToPixel( Size( 12, 12 ), MapMode( MAP_APPFONT ) ).Height() ); 1260 Point aNewPos( (aTabCtrlSize.Width() - nPrefWidth) / 2, 0 ); 1261 mpTabCtrlData->mpListBox->SetPosSizePixel( aNewPos, aNewSize ); 1262 } 1263 1264 mbFormat = sal_True; 1265 1266 // Aktuelle TabPage resizen/positionieren 1267 sal_Bool bTabPage = ImplPosCurTabPage(); 1268 // Feststellen, was invalidiert werden muss 1269 Size aNewSize = Control::GetOutputSizePixel(); 1270 long nNewWidth = aNewSize.Width(); 1271 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin(); 1272 it != mpTabCtrlData->maItemList.end(); ++it ) 1273 { 1274 if ( !it->mbFullVisible || 1275 (it->maRect.Right()-2 >= nNewWidth) ) 1276 { 1277 mbSmallInvalidate = sal_False; 1278 break; 1279 } 1280 } 1281 1282 if ( mbSmallInvalidate ) 1283 { 1284 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT ); 1285 aRect.Left() -= TAB_OFFSET+TAB_BORDER_LEFT; 1286 aRect.Top() -= TAB_OFFSET+TAB_BORDER_TOP; 1287 aRect.Right() += TAB_OFFSET+TAB_BORDER_RIGHT; 1288 aRect.Bottom() += TAB_OFFSET+TAB_BORDER_BOTTOM; 1289 if ( bTabPage ) 1290 Invalidate( aRect, INVALIDATE_NOCHILDREN ); 1291 else 1292 Invalidate( aRect ); 1293 1294 } 1295 else 1296 { 1297 if ( bTabPage ) 1298 Invalidate( INVALIDATE_NOCHILDREN ); 1299 else 1300 Invalidate(); 1301 } 1302 } 1303 1304 // ----------------------------------------------------------------------- 1305 1306 void TabControl::GetFocus() 1307 { 1308 if( ! mpTabCtrlData->mpListBox ) 1309 { 1310 ImplShowFocus(); 1311 SetInputContext( InputContext( GetFont() ) ); 1312 } 1313 else 1314 { 1315 if( mpTabCtrlData->mpListBox->IsReallyVisible() ) 1316 mpTabCtrlData->mpListBox->GrabFocus(); 1317 } 1318 Control::GetFocus(); 1319 } 1320 1321 // ----------------------------------------------------------------------- 1322 1323 void TabControl::LoseFocus() 1324 { 1325 if( ! mpTabCtrlData->mpListBox ) 1326 HideFocus(); 1327 Control::LoseFocus(); 1328 } 1329 1330 // ----------------------------------------------------------------------- 1331 1332 void TabControl::RequestHelp( const HelpEvent& rHEvt ) 1333 { 1334 sal_uInt16 nItemId = rHEvt.KeyboardActivated() ? mnCurPageId : GetPageId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) ); 1335 1336 if ( nItemId ) 1337 { 1338 if ( rHEvt.GetMode() & HELPMODE_BALLOON ) 1339 { 1340 XubString aStr = GetHelpText( nItemId ); 1341 if ( aStr.Len() ) 1342 { 1343 Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) ); 1344 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); 1345 aItemRect.Left() = aPt.X(); 1346 aItemRect.Top() = aPt.Y(); 1347 aPt = OutputToScreenPixel( aItemRect.BottomRight() ); 1348 aItemRect.Right() = aPt.X(); 1349 aItemRect.Bottom() = aPt.Y(); 1350 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr ); 1351 return; 1352 } 1353 } 1354 else if ( rHEvt.GetMode() & HELPMODE_EXTENDED ) 1355 { 1356 rtl::OUString aHelpId( rtl::OStringToOUString( GetHelpId( nItemId ), RTL_TEXTENCODING_UTF8 ) ); 1357 if ( aHelpId.getLength() ) 1358 { 1359 // Wenn eine Hilfe existiert, dann ausloesen 1360 Help* pHelp = Application::GetHelp(); 1361 if ( pHelp ) 1362 pHelp->Start( aHelpId, this ); 1363 return; 1364 } 1365 } 1366 1367 // Bei Quick- oder Balloon-Help zeigen wir den Text an, 1368 // wenn dieser abgeschnitten ist 1369 if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) ) 1370 { 1371 ImplTabItem* pItem = ImplGetItem( nItemId ); 1372 const XubString& rStr = pItem->maText; 1373 if ( rStr != pItem->maFormatText ) 1374 { 1375 Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) ); 1376 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); 1377 aItemRect.Left() = aPt.X(); 1378 aItemRect.Top() = aPt.Y(); 1379 aPt = OutputToScreenPixel( aItemRect.BottomRight() ); 1380 aItemRect.Right() = aPt.X(); 1381 aItemRect.Bottom() = aPt.Y(); 1382 if ( rStr.Len() ) 1383 { 1384 if ( rHEvt.GetMode() & HELPMODE_BALLOON ) 1385 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, rStr ); 1386 else 1387 Help::ShowQuickHelp( this, aItemRect, rStr ); 1388 return; 1389 } 1390 } 1391 } 1392 1393 if ( rHEvt.GetMode() & HELPMODE_QUICK ) 1394 { 1395 ImplTabItem* pItem = ImplGetItem( nItemId ); 1396 const XubString& rHelpText = pItem->maHelpText; 1397 // show tooltip if not text but image is set and helptext is available 1398 if ( rHelpText.Len() > 0 && pItem->maText.Len() == 0 && !!pItem->maTabImage ) 1399 { 1400 Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) ); 1401 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); 1402 aItemRect.Left() = aPt.X(); 1403 aItemRect.Top() = aPt.Y(); 1404 aPt = OutputToScreenPixel( aItemRect.BottomRight() ); 1405 aItemRect.Right() = aPt.X(); 1406 aItemRect.Bottom() = aPt.Y(); 1407 Help::ShowQuickHelp( this, aItemRect, rHelpText ); 1408 return; 1409 } 1410 } 1411 } 1412 1413 Control::RequestHelp( rHEvt ); 1414 } 1415 1416 // ----------------------------------------------------------------------- 1417 1418 void TabControl::Command( const CommandEvent& rCEvt ) 1419 { 1420 if( (mpTabCtrlData->mpListBox == NULL) && (rCEvt.GetCommand() == COMMAND_CONTEXTMENU) && (GetPageCount() > 1) ) 1421 { 1422 Point aMenuPos; 1423 sal_Bool bMenu; 1424 if ( rCEvt.IsMouseEvent() ) 1425 { 1426 aMenuPos = rCEvt.GetMousePosPixel(); 1427 bMenu = GetPageId( aMenuPos ) != 0; 1428 } 1429 else 1430 { 1431 aMenuPos = ImplGetTabRect( GetPagePos( mnCurPageId ) ).Center(); 1432 bMenu = sal_True; 1433 } 1434 1435 if ( bMenu ) 1436 { 1437 PopupMenu aMenu; 1438 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin(); 1439 it != mpTabCtrlData->maItemList.end(); ++it ) 1440 { 1441 aMenu.InsertItem( it->mnId, it->maText, MIB_CHECKABLE | MIB_RADIOCHECK ); 1442 if ( it->mnId == mnCurPageId ) 1443 aMenu.CheckItem( it->mnId ); 1444 aMenu.SetHelpId( it->mnId, it->maHelpId ); 1445 } 1446 1447 sal_uInt16 nId = aMenu.Execute( this, aMenuPos ); 1448 if ( nId && (nId != mnCurPageId) ) 1449 SelectTabPage( nId ); 1450 return; 1451 } 1452 } 1453 1454 Control::Command( rCEvt ); 1455 } 1456 1457 // ----------------------------------------------------------------------- 1458 1459 void TabControl::StateChanged( StateChangedType nType ) 1460 { 1461 Control::StateChanged( nType ); 1462 1463 if ( nType == STATE_CHANGE_INITSHOW ) 1464 { 1465 ImplPosCurTabPage(); 1466 if( mpTabCtrlData->mpListBox ) 1467 Resize(); 1468 } 1469 else if ( nType == STATE_CHANGE_UPDATEMODE ) 1470 { 1471 if ( IsUpdateMode() ) 1472 Invalidate(); 1473 } 1474 else if ( (nType == STATE_CHANGE_ZOOM) || 1475 (nType == STATE_CHANGE_CONTROLFONT) ) 1476 { 1477 ImplInitSettings( sal_True, sal_False, sal_False ); 1478 Invalidate(); 1479 } 1480 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND ) 1481 { 1482 ImplInitSettings( sal_False, sal_True, sal_False ); 1483 Invalidate(); 1484 } 1485 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) 1486 { 1487 ImplInitSettings( sal_False, sal_False, sal_True ); 1488 Invalidate(); 1489 } 1490 } 1491 1492 // ----------------------------------------------------------------------- 1493 1494 void TabControl::DataChanged( const DataChangedEvent& rDCEvt ) 1495 { 1496 Control::DataChanged( rDCEvt ); 1497 1498 if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || 1499 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || 1500 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && 1501 (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) 1502 { 1503 ImplInitSettings( sal_True, sal_True, sal_True ); 1504 Invalidate(); 1505 } 1506 } 1507 1508 // ----------------------------------------------------------------------- 1509 1510 Rectangle* TabControl::ImplFindPartRect( const Point& rPt ) 1511 { 1512 ImplTabItem* pFoundItem = NULL; 1513 int nFound = 0; 1514 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin(); 1515 it != mpTabCtrlData->maItemList.end(); ++it ) 1516 { 1517 if ( it->maRect.IsInside( rPt ) ) 1518 { 1519 // assure that only one tab is highlighted at a time 1520 nFound++; 1521 pFoundItem = &(*it); 1522 } 1523 } 1524 // assure that only one tab is highlighted at a time 1525 return nFound == 1 ? &pFoundItem->maRect : NULL; 1526 } 1527 1528 long TabControl::PreNotify( NotifyEvent& rNEvt ) 1529 { 1530 long nDone = 0; 1531 const MouseEvent* pMouseEvt = NULL; 1532 1533 if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL ) 1534 { 1535 if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() ) 1536 { 1537 // trigger redraw if mouse over state has changed 1538 if( IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) ) 1539 { 1540 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() ); 1541 Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() ); 1542 if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) ) 1543 { 1544 Region aClipRgn; 1545 if( pLastRect ) 1546 { 1547 // allow for slightly bigger tabitems 1548 // as used by gtk 1549 // TODO: query for the correct sizes 1550 Rectangle aRect(*pLastRect); 1551 aRect.nLeft-=2; 1552 aRect.nRight+=2; 1553 aRect.nTop-=3; 1554 aClipRgn.Union( aRect ); 1555 } 1556 if( pRect ) 1557 { 1558 // allow for slightly bigger tabitems 1559 // as used by gtk 1560 // TODO: query for the correct sizes 1561 Rectangle aRect(*pRect); 1562 aRect.nLeft-=2; 1563 aRect.nRight+=2; 1564 aRect.nTop-=3; 1565 aClipRgn.Union( aRect ); 1566 } 1567 if( !aClipRgn.IsEmpty() ) 1568 Invalidate( aClipRgn ); 1569 } 1570 } 1571 } 1572 } 1573 1574 return nDone ? nDone : Control::PreNotify(rNEvt); 1575 } 1576 1577 // ----------------------------------------------------------------------- 1578 1579 long TabControl::Notify( NotifyEvent& rNEvt ) 1580 { 1581 long nRet = 0; 1582 1583 if ( rNEvt.GetType() == EVENT_KEYINPUT ) 1584 nRet = ImplHandleKeyEvent( *rNEvt.GetKeyEvent() ); 1585 1586 return nRet ? nRet : Control::Notify( rNEvt ); 1587 } 1588 1589 // ----------------------------------------------------------------------- 1590 1591 void TabControl::ActivatePage() 1592 { 1593 maActivateHdl.Call( this ); 1594 } 1595 1596 // ----------------------------------------------------------------------- 1597 1598 long TabControl::DeactivatePage() 1599 { 1600 if ( maDeactivateHdl.IsSet() ) 1601 return maDeactivateHdl.Call( this ); 1602 else 1603 return sal_True; 1604 } 1605 1606 // ----------------------------------------------------------------------- 1607 1608 void TabControl::SetTabPageSizePixel( const Size& rSize ) 1609 { 1610 ImplFreeLayoutData(); 1611 1612 Size aNewSize( rSize ); 1613 aNewSize.Width() += TAB_OFFSET*2; 1614 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT, 1615 aNewSize.Width(), aNewSize.Height() ); 1616 aNewSize.Height() += aRect.Top()+TAB_OFFSET; 1617 Window::SetOutputSizePixel( aNewSize ); 1618 } 1619 1620 // ----------------------------------------------------------------------- 1621 1622 Size TabControl::GetTabPageSizePixel() const 1623 { 1624 Rectangle aRect = ((TabControl*)this)->ImplGetTabRect( TAB_PAGERECT ); 1625 return aRect.GetSize(); 1626 } 1627 1628 // ----------------------------------------------------------------------- 1629 1630 void TabControl::InsertPage( const ResId& rResId, sal_uInt16 nPos ) 1631 { 1632 GetRes( rResId.SetRT( RSC_TABCONTROLITEM ) ); 1633 1634 sal_uLong nObjMask = ReadLongRes(); 1635 sal_uInt16 nItemId = 1; 1636 1637 // ID 1638 if ( nObjMask & RSC_TABCONTROLITEM_ID ) 1639 nItemId = sal::static_int_cast<sal_uInt16>(ReadLongRes()); 1640 1641 // Text 1642 XubString aTmpStr; 1643 if( nObjMask & RSC_TABCONTROLITEM_TEXT ) 1644 aTmpStr = ReadStringRes(); 1645 InsertPage( nItemId, aTmpStr, nPos ); 1646 1647 // PageResID 1648 if ( nObjMask & RSC_TABCONTROLITEM_PAGERESID ) 1649 { 1650 ImplTabItem& rItem = mpTabCtrlData->maItemList[ GetPagePos( nItemId ) ]; 1651 rItem.mnTabPageResId = sal::static_int_cast<sal_uInt16>(ReadLongRes()); 1652 } 1653 } 1654 1655 // ----------------------------------------------------------------------- 1656 1657 void TabControl::InsertPage( sal_uInt16 nPageId, const XubString& rText, 1658 sal_uInt16 nPos ) 1659 { 1660 DBG_ASSERT( nPageId, "TabControl::InsertPage(): PageId == 0" ); 1661 DBG_ASSERT( GetPagePos( nPageId ) == TAB_PAGE_NOTFOUND, 1662 "TabControl::InsertPage(): PageId already exists" ); 1663 1664 // insert new page item 1665 ImplTabItem* pItem = NULL; 1666 if( nPos == TAB_APPEND || size_t(nPos) >= mpTabCtrlData->maItemList.size() ) 1667 { 1668 mpTabCtrlData->maItemList.push_back( ImplTabItem() ); 1669 pItem = &mpTabCtrlData->maItemList.back(); 1670 if( mpTabCtrlData->mpListBox ) 1671 mpTabCtrlData->mpListBox->InsertEntry( rText ); 1672 } 1673 else 1674 { 1675 std::vector< ImplTabItem >::iterator new_it = 1676 mpTabCtrlData->maItemList.insert( mpTabCtrlData->maItemList.begin() + nPos, ImplTabItem() ); 1677 pItem = &(*new_it); 1678 if( mpTabCtrlData->mpListBox ) 1679 mpTabCtrlData->mpListBox->InsertEntry( rText, nPos); 1680 } 1681 if( mpTabCtrlData->mpListBox ) 1682 { 1683 if( ! mnCurPageId ) 1684 mpTabCtrlData->mpListBox->SelectEntryPos( 0 ); 1685 mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() ); 1686 } 1687 1688 // set current page id 1689 if ( !mnCurPageId ) 1690 mnCurPageId = nPageId; 1691 1692 // init new page item 1693 pItem->mnId = nPageId; 1694 pItem->mpTabPage = NULL; 1695 pItem->mnTabPageResId = 0; 1696 pItem->maText = rText; 1697 pItem->mbFullVisible = sal_False; 1698 1699 mbFormat = sal_True; 1700 if ( IsUpdateMode() ) 1701 Invalidate(); 1702 1703 ImplFreeLayoutData(); 1704 if( mpTabCtrlData->mpListBox ) // reposition/resize listbox 1705 Resize(); 1706 1707 ImplCallEventListeners( VCLEVENT_TABPAGE_INSERTED, (void*) (sal_uLong)nPageId ); 1708 } 1709 1710 // ----------------------------------------------------------------------- 1711 1712 void TabControl::RemovePage( sal_uInt16 nPageId ) 1713 { 1714 sal_uInt16 nPos = GetPagePos( nPageId ); 1715 1716 // does the item exist ? 1717 if ( nPos != TAB_PAGE_NOTFOUND ) 1718 { 1719 //remove page item 1720 std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin() + nPos; 1721 bool bIsCurrentPage = (it->mnId == mnCurPageId); 1722 mpTabCtrlData->maItemList.erase( it ); 1723 if( mpTabCtrlData->mpListBox ) 1724 { 1725 mpTabCtrlData->mpListBox->RemoveEntry( nPos ); 1726 mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() ); 1727 } 1728 1729 // If current page is removed, than first page gets the current page 1730 if ( bIsCurrentPage ) 1731 { 1732 mnCurPageId = 0; 1733 1734 if( ! mpTabCtrlData->maItemList.empty() ) 1735 { 1736 // don't do this by simply setting mnCurPageId to pFirstItem->mnId 1737 // this leaves a lot of stuff (such trivias as _showing_ the new current page) undone 1738 // instead, call SetCurPageId 1739 // without this, the next (outside) call to SetCurPageId with the id of the first page 1740 // will result in doing nothing (as we assume that nothing changed, then), and the page 1741 // will never be shown. 1742 // 86875 - 05/11/2001 - frank.schoenheit@germany.sun.com 1743 1744 SetCurPageId( mpTabCtrlData->maItemList[0].mnId ); 1745 } 1746 } 1747 1748 mbFormat = sal_True; 1749 if ( IsUpdateMode() ) 1750 Invalidate(); 1751 1752 ImplFreeLayoutData(); 1753 1754 ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVED, (void*) (sal_uLong) nPageId ); 1755 } 1756 } 1757 1758 // ----------------------------------------------------------------------- 1759 1760 void TabControl::Clear() 1761 { 1762 // clear item list 1763 mpTabCtrlData->maItemList.clear(); 1764 mnCurPageId = 0; 1765 if( mpTabCtrlData->mpListBox ) 1766 mpTabCtrlData->mpListBox->Clear(); 1767 1768 ImplFreeLayoutData(); 1769 1770 mbFormat = sal_True; 1771 if ( IsUpdateMode() ) 1772 Invalidate(); 1773 1774 ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVEDALL ); 1775 } 1776 1777 // ----------------------------------------------------------------------- 1778 1779 void TabControl::EnablePage( sal_uInt16 i_nPageId, bool i_bEnable ) 1780 { 1781 ImplTabItem* pItem = ImplGetItem( i_nPageId ); 1782 1783 if ( pItem && pItem->mbEnabled != i_bEnable ) 1784 { 1785 pItem->mbEnabled = i_bEnable; 1786 mbFormat = sal_True; 1787 if( mpTabCtrlData->mpListBox ) 1788 mpTabCtrlData->mpListBox->SetEntryFlags( GetPagePos( i_nPageId ), 1789 i_bEnable ? 0 : (LISTBOX_ENTRY_FLAG_DISABLE_SELECTION | LISTBOX_ENTRY_FLAG_DRAW_DISABLED) ); 1790 if( pItem->mnId == mnCurPageId ) 1791 { 1792 // SetCurPageId will change to an enabled page 1793 SetCurPageId( mnCurPageId ); 1794 } 1795 else if ( IsUpdateMode() ) 1796 Invalidate(); 1797 } 1798 } 1799 1800 // ----------------------------------------------------------------------- 1801 1802 sal_uInt16 TabControl::GetPageCount() const 1803 { 1804 return (sal_uInt16)mpTabCtrlData->maItemList.size(); 1805 } 1806 1807 // ----------------------------------------------------------------------- 1808 1809 sal_uInt16 TabControl::GetPageId( sal_uInt16 nPos ) const 1810 { 1811 if( size_t(nPos) < mpTabCtrlData->maItemList.size() ) 1812 return mpTabCtrlData->maItemList[ nPos ].mnId; 1813 return 0; 1814 } 1815 1816 // ----------------------------------------------------------------------- 1817 1818 sal_uInt16 TabControl::GetPagePos( sal_uInt16 nPageId ) const 1819 { 1820 for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin(); 1821 it != mpTabCtrlData->maItemList.end(); ++it ) 1822 { 1823 if ( it->mnId == nPageId ) 1824 return (sal_uInt16)(it - mpTabCtrlData->maItemList.begin()); 1825 } 1826 1827 return TAB_PAGE_NOTFOUND; 1828 } 1829 1830 // ----------------------------------------------------------------------- 1831 1832 sal_uInt16 TabControl::GetPageId( const Point& rPos ) const 1833 { 1834 for( size_t i = 0; i < mpTabCtrlData->maItemList.size(); ++i ) 1835 { 1836 if ( ((TabControl*)this)->ImplGetTabRect( static_cast<sal_uInt16>(i) ).IsInside( rPos ) ) 1837 return mpTabCtrlData->maItemList[ i ].mnId; 1838 } 1839 1840 return 0; 1841 } 1842 1843 // ----------------------------------------------------------------------- 1844 1845 void TabControl::SetCurPageId( sal_uInt16 nPageId ) 1846 { 1847 sal_uInt16 nPos = GetPagePos( nPageId ); 1848 while( nPos != TAB_PAGE_NOTFOUND && 1849 ! mpTabCtrlData->maItemList[nPos].mbEnabled ) 1850 { 1851 nPos++; 1852 if( size_t(nPos) >= mpTabCtrlData->maItemList.size() ) 1853 nPos = 0; 1854 if( mpTabCtrlData->maItemList[nPos].mnId == nPageId ) 1855 break; 1856 } 1857 1858 if( nPos != TAB_PAGE_NOTFOUND ) 1859 { 1860 nPageId = mpTabCtrlData->maItemList[nPos].mnId; 1861 if ( nPageId == mnCurPageId ) 1862 { 1863 if ( mnActPageId ) 1864 mnActPageId = nPageId; 1865 return; 1866 } 1867 1868 if ( mnActPageId ) 1869 mnActPageId = nPageId; 1870 else 1871 { 1872 mbFormat = sal_True; 1873 sal_uInt16 nOldId = mnCurPageId; 1874 mnCurPageId = nPageId; 1875 ImplChangeTabPage( nPageId, nOldId ); 1876 } 1877 } 1878 } 1879 1880 // ----------------------------------------------------------------------- 1881 1882 sal_uInt16 TabControl::GetCurPageId() const 1883 { 1884 if ( mnActPageId ) 1885 return mnActPageId; 1886 else 1887 return mnCurPageId; 1888 } 1889 1890 // ----------------------------------------------------------------------- 1891 1892 void TabControl::SelectTabPage( sal_uInt16 nPageId ) 1893 { 1894 if ( nPageId && (nPageId != mnCurPageId) ) 1895 { 1896 ImplFreeLayoutData(); 1897 1898 ImplCallEventListeners( VCLEVENT_TABPAGE_DEACTIVATE, (void*) (sal_uLong) mnCurPageId ); 1899 if ( DeactivatePage() ) 1900 { 1901 mnActPageId = nPageId; 1902 ActivatePage(); 1903 // Page koennte im Activate-Handler umgeschaltet wurden sein 1904 nPageId = mnActPageId; 1905 mnActPageId = 0; 1906 SetCurPageId( nPageId ); 1907 if( mpTabCtrlData->mpListBox ) 1908 mpTabCtrlData->mpListBox->SelectEntryPos( GetPagePos( nPageId ) ); 1909 ImplCallEventListeners( VCLEVENT_TABPAGE_ACTIVATE, (void*) (sal_uLong) nPageId ); 1910 } 1911 } 1912 } 1913 1914 // ----------------------------------------------------------------------- 1915 1916 void TabControl::SetTabPage( sal_uInt16 nPageId, TabPage* pTabPage ) 1917 { 1918 ImplTabItem* pItem = ImplGetItem( nPageId ); 1919 1920 if ( pItem && (pItem->mpTabPage != pTabPage) ) 1921 { 1922 if ( pTabPage ) 1923 { 1924 DBG_ASSERT( !pTabPage->IsVisible(), "TabControl::SetTabPage() - Page is visible" ); 1925 1926 if ( IsDefaultSize() ) 1927 SetTabPageSizePixel( pTabPage->GetSizePixel() ); 1928 1929 // Erst hier setzen, damit Resize nicht TabPage umpositioniert 1930 pItem->mpTabPage = pTabPage; 1931 if ( pItem->mnId == mnCurPageId ) 1932 ImplChangeTabPage( pItem->mnId, 0 ); 1933 } 1934 else 1935 pItem->mpTabPage = NULL; 1936 } 1937 } 1938 1939 // ----------------------------------------------------------------------- 1940 1941 TabPage* TabControl::GetTabPage( sal_uInt16 nPageId ) const 1942 { 1943 ImplTabItem* pItem = ImplGetItem( nPageId ); 1944 1945 if ( pItem ) 1946 return pItem->mpTabPage; 1947 else 1948 return NULL; 1949 } 1950 1951 // ----------------------------------------------------------------------- 1952 1953 sal_uInt16 TabControl::GetTabPageResId( sal_uInt16 nPageId ) const 1954 { 1955 ImplTabItem* pItem = ImplGetItem( nPageId ); 1956 1957 if ( pItem ) 1958 return pItem->mnTabPageResId; 1959 else 1960 return 0; 1961 } 1962 1963 // ----------------------------------------------------------------------- 1964 1965 void TabControl::SetPageText( sal_uInt16 nPageId, const XubString& rText ) 1966 { 1967 ImplTabItem* pItem = ImplGetItem( nPageId ); 1968 1969 if ( pItem && pItem->maText != rText ) 1970 { 1971 pItem->maText = rText; 1972 mbFormat = sal_True; 1973 if( mpTabCtrlData->mpListBox ) 1974 { 1975 sal_uInt16 nPos = GetPagePos( nPageId ); 1976 mpTabCtrlData->mpListBox->RemoveEntry( nPos ); 1977 mpTabCtrlData->mpListBox->InsertEntry( rText, nPos ); 1978 } 1979 if ( IsUpdateMode() ) 1980 Invalidate(); 1981 ImplFreeLayoutData(); 1982 ImplCallEventListeners( VCLEVENT_TABPAGE_PAGETEXTCHANGED, (void*) (sal_uLong) nPageId ); 1983 } 1984 } 1985 1986 // ----------------------------------------------------------------------- 1987 1988 XubString TabControl::GetPageText( sal_uInt16 nPageId ) const 1989 { 1990 ImplTabItem* pItem = ImplGetItem( nPageId ); 1991 1992 if ( pItem ) 1993 return pItem->maText; 1994 else 1995 return ImplGetSVEmptyStr(); 1996 } 1997 1998 // ----------------------------------------------------------------------- 1999 2000 void TabControl::SetHelpText( sal_uInt16 nPageId, const XubString& rText ) 2001 { 2002 ImplTabItem* pItem = ImplGetItem( nPageId ); 2003 2004 if ( pItem ) 2005 pItem->maHelpText = rText; 2006 } 2007 2008 // ----------------------------------------------------------------------- 2009 2010 const XubString& TabControl::GetHelpText( sal_uInt16 nPageId ) const 2011 { 2012 ImplTabItem* pItem = ImplGetItem( nPageId ); 2013 2014 if ( pItem ) 2015 { 2016 if ( !pItem->maHelpText.Len() && pItem->maHelpId.getLength() ) 2017 { 2018 Help* pHelp = Application::GetHelp(); 2019 if ( pHelp ) 2020 pItem->maHelpText = pHelp->GetHelpText( rtl::OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this ); 2021 } 2022 2023 return pItem->maHelpText; 2024 } 2025 else 2026 return ImplGetSVEmptyStr(); 2027 } 2028 2029 // ----------------------------------------------------------------------- 2030 2031 void TabControl::SetHelpId( sal_uInt16 nPageId, const rtl::OString& rHelpId ) 2032 { 2033 ImplTabItem* pItem = ImplGetItem( nPageId ); 2034 2035 if ( pItem ) 2036 pItem->maHelpId = rHelpId; 2037 } 2038 2039 // ----------------------------------------------------------------------- 2040 2041 rtl::OString TabControl::GetHelpId( sal_uInt16 nPageId ) const 2042 { 2043 rtl::OString aRet; 2044 ImplTabItem* pItem = ImplGetItem( nPageId ); 2045 2046 if ( pItem ) 2047 aRet = pItem->maHelpId; 2048 2049 return aRet; 2050 } 2051 2052 // ----------------------------------------------------------------------- 2053 2054 void TabControl::SetPageImage( sal_uInt16 i_nPageId, const Image& i_rImage ) 2055 { 2056 ImplTabItem* pItem = ImplGetItem( i_nPageId ); 2057 2058 if ( pItem ) 2059 { 2060 pItem->maTabImage = i_rImage; 2061 mbFormat = sal_True; 2062 if ( IsUpdateMode() ) 2063 Invalidate(); 2064 } 2065 } 2066 2067 // ----------------------------------------------------------------------- 2068 2069 const Image* TabControl::GetPageImage( sal_uInt16 i_nPageId ) const 2070 { 2071 const ImplTabItem* pItem = ImplGetItem( i_nPageId ); 2072 return pItem ? &pItem->maTabImage : NULL; 2073 } 2074 2075 // ----------------------------------------------------------------------- 2076 2077 Rectangle TabControl::GetCharacterBounds( sal_uInt16 nPageId, long nIndex ) const 2078 { 2079 Rectangle aRet; 2080 2081 if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() ) 2082 FillLayoutData(); 2083 2084 if( HasLayoutData() ) 2085 { 2086 std::hash_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( (int)nPageId ); 2087 if( it != mpTabCtrlData->maLayoutPageIdToLine.end() ) 2088 { 2089 Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( it->second ); 2090 if( (aPair.B() - aPair.A()) >= nIndex ) 2091 aRet = mpControlData->mpLayoutData->GetCharacterBounds( aPair.A() + nIndex ); 2092 } 2093 } 2094 2095 return aRet; 2096 } 2097 2098 // ----------------------------------------------------------------------- 2099 2100 long TabControl::GetIndexForPoint( const Point& rPoint, sal_uInt16& rPageId ) const 2101 { 2102 long nRet = -1; 2103 2104 if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() ) 2105 FillLayoutData(); 2106 2107 if( HasLayoutData() ) 2108 { 2109 int nIndex = mpControlData->mpLayoutData->GetIndexForPoint( rPoint ); 2110 if( nIndex != -1 ) 2111 { 2112 // what line (->pageid) is this index in ? 2113 int nLines = mpControlData->mpLayoutData->GetLineCount(); 2114 int nLine = -1; 2115 while( ++nLine < nLines ) 2116 { 2117 Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( nLine ); 2118 if( aPair.A() <= nIndex && aPair.B() >= nIndex ) 2119 { 2120 nRet = nIndex - aPair.A(); 2121 rPageId = (sal_uInt16)mpTabCtrlData->maLayoutLineToPageId[ nLine ]; 2122 break; 2123 } 2124 } 2125 } 2126 } 2127 2128 return nRet; 2129 } 2130 2131 // ----------------------------------------------------------------------- 2132 2133 void TabControl::FillLayoutData() const 2134 { 2135 mpTabCtrlData->maLayoutLineToPageId.clear(); 2136 mpTabCtrlData->maLayoutPageIdToLine.clear(); 2137 const_cast<TabControl*>(this)->ImplPaint( Rectangle(), true ); 2138 } 2139 2140 // ----------------------------------------------------------------------- 2141 2142 Rectangle TabControl::GetTabPageBounds( sal_uInt16 nPage ) const 2143 { 2144 Rectangle aRet; 2145 2146 if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() ) 2147 FillLayoutData(); 2148 2149 if( HasLayoutData() ) 2150 { 2151 std::hash_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( (int)nPage ); 2152 if( it != mpTabCtrlData->maLayoutPageIdToLine.end() ) 2153 { 2154 if( it->second >= 0 && it->second < static_cast<int>(mpTabCtrlData->maTabRectangles.size()) ) 2155 { 2156 aRet = mpTabCtrlData->maTabRectangles[ it->second ]; 2157 aRet.Union( const_cast<TabControl*>(this)->ImplGetTabRect( TAB_PAGERECT ) ); 2158 } 2159 } 2160 } 2161 2162 return aRet; 2163 } 2164 2165 // ----------------------------------------------------------------------- 2166 2167 Rectangle TabControl::GetTabBounds( sal_uInt16 nPageId ) const 2168 { 2169 Rectangle aRet; 2170 2171 ImplTabItem* pItem = ImplGetItem( nPageId ); 2172 if(pItem) 2173 aRet = pItem->maRect; 2174 2175 return aRet; 2176 } 2177 2178 // ----------------------------------------------------------------------- 2179 2180 void TabControl::SetItemsOffset( const Point& rOffs ) 2181 { 2182 if( mpTabCtrlData ) 2183 mpTabCtrlData->maItemsOffset = rOffs; 2184 } 2185 2186 Point TabControl::GetItemsOffset() const 2187 { 2188 if( mpTabCtrlData ) 2189 return mpTabCtrlData->maItemsOffset; 2190 else 2191 return Point(); 2192 } 2193 2194 // ----------------------------------------------------------------------- 2195 2196 Size TabControl::GetOptimalSize(WindowSizeType eType) const 2197 { 2198 switch (eType) { 2199 case WINDOWSIZE_MINIMUM: 2200 return mpTabCtrlData ? mpTabCtrlData->maMinSize : Size(); 2201 default: 2202 return Control::GetOptimalSize( eType ); 2203 } 2204 } 2205 2206 // ----------------------------------------------------------------------- 2207 2208 void TabControl::SetMinimumSizePixel( const Size& i_rSize ) 2209 { 2210 if( mpTabCtrlData ) 2211 mpTabCtrlData->maMinSize = i_rSize; 2212 } 2213 2214 // ----------------------------------------------------------------------- 2215 2216 2217