xref: /aoo41x/main/vcl/source/control/tabctrl.cxx (revision cdf0e10c)
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