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