xref: /aoo41x/main/vcl/source/control/tabctrl.cxx (revision ad3a95a3)
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 //IAccessibility2 Implementation 2009-----
623 		pPage->Show();
624 //-----IAccessibility2 Implementation 2009
625 
626         if ( pOldPage && pOldPage->HasChildPathFocus() )
627         {
628             sal_uInt16  n = 0;
629             Window* pFirstChild = pPage->ImplGetDlgWindow( n, DLGWINDOW_FIRST );
630             if ( pFirstChild )
631                 pFirstChild->ImplControlFocus( GETFOCUS_INIT );
632             else
633                 GrabFocus();
634         }
635 
636 //IAccessibility2 Implementation 2009-----
637         // pPage->Show();
638 //-----IAccessibility2 Implementation 2009
639     }
640 
641     if ( pOldPage )
642         pOldPage->Hide();
643 
644     // Invalidate the same region that will be send to NWF
645     // to always allow for bitmap caching
646     // see Window::DrawNativeControl()
647     if( IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL ) )
648     {
649         aRect.Left()   -= TAB_OFFSET;
650         aRect.Top()    -= TAB_OFFSET;
651         aRect.Right()  += TAB_OFFSET;
652         aRect.Bottom() += TAB_OFFSET;
653     }
654 
655     Invalidate( aRect );
656 }
657 
658 // -----------------------------------------------------------------------
659 
660 sal_Bool TabControl::ImplPosCurTabPage()
661 {
662     // Aktuelle TabPage resizen/positionieren
663     ImplTabItem* pItem = ImplGetItem( GetCurPageId() );
664     if ( pItem && pItem->mpTabPage )
665     {
666         Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
667         pItem->mpTabPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
668         return sal_True;
669     }
670 
671     return sal_False;
672 }
673 
674 // -----------------------------------------------------------------------
675 
676 void TabControl::ImplActivateTabPage( sal_Bool bNext )
677 {
678     sal_uInt16 nCurPos = GetPagePos( GetCurPageId() );
679 
680     if ( bNext )
681         nCurPos = (nCurPos + 1) % GetPageCount();
682     else
683     {
684         if ( !nCurPos )
685             nCurPos = GetPageCount()-1;
686         else
687             nCurPos--;
688     }
689 
690     SelectTabPage( GetPageId( nCurPos ) );
691 }
692 
693 // -----------------------------------------------------------------------
694 
695 void TabControl::ImplShowFocus()
696 {
697     if ( !GetPageCount() || mpTabCtrlData->mpListBox )
698         return;
699 
700     // make sure the focussed item rect is computed using a bold font
701     // the font may have changed meanwhile due to mouse over
702 
703     Font aOldFont( GetFont() );
704     Font aFont( aOldFont );
705     aFont.SetWeight( (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus) ? WEIGHT_BOLD : WEIGHT_LIGHT );
706     SetFont( aFont );
707 
708     sal_uInt16                   nCurPos     = GetPagePos( mnCurPageId );
709     Rectangle                aRect       = ImplGetTabRect( nCurPos );
710     const ImplTabItem&       rItem       = mpTabCtrlData->maItemList[ nCurPos ];
711     Size                     aTabSize    = aRect.GetSize();
712     Size aImageSize( 0, 0 );
713     long                     nTextHeight = GetTextHeight();
714     long                     nTextWidth  = GetCtrlTextWidth( rItem.maFormatText );
715     sal_uInt16                   nOff;
716 
717     if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_MONO) )
718         nOff = 1;
719     else
720         nOff = 0;
721 
722     if( !! rItem.maTabImage )
723     {
724         aImageSize = rItem.maTabImage.GetSizePixel();
725         if( rItem.maFormatText.Len() )
726             aImageSize.Width() += GetTextHeight()/4;
727     }
728 
729     if( rItem.maFormatText.Len() )
730     {
731         // show focus around text
732         aRect.Left()   = aRect.Left()+aImageSize.Width()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1-1;
733         aRect.Top()    = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-1-1;
734         aRect.Right()  = aRect.Left()+nTextWidth+2;
735         aRect.Bottom() = aRect.Top()+nTextHeight+2;
736     }
737     else
738     {
739         // show focus around image
740         long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1;
741         long nYPos = aRect.Top();
742         if( aImageSize.Height() < aRect.GetHeight() )
743             nYPos += (aRect.GetHeight() - aImageSize.Height())/2;
744 
745         aRect.Left() = nXPos - 2;
746         aRect.Top() = nYPos - 2;
747         aRect.Right() = aRect.Left() + aImageSize.Width() + 4;
748         aRect.Bottom() = aRect.Top() + aImageSize.Height() + 4;
749     }
750     ShowFocus( aRect );
751 
752     SetFont( aOldFont );
753 }
754 
755 // -----------------------------------------------------------------------
756 
757 void TabControl::ImplDrawItem( ImplTabItem* pItem, const Rectangle& rCurRect, bool bLayout, bool bFirstInGroup, bool bLastInGroup, bool bIsCurrentItem )
758 {
759     if ( pItem->maRect.IsEmpty() )
760         return;
761 
762     if( bLayout )
763     {
764         if( !HasLayoutData() )
765         {
766             mpControlData->mpLayoutData = new vcl::ControlLayoutData();
767             mpTabCtrlData->maLayoutLineToPageId.clear();
768             mpTabCtrlData->maLayoutPageIdToLine.clear();
769             mpTabCtrlData->maTabRectangles.clear();
770         }
771     }
772 
773     const StyleSettings&    rStyleSettings  = GetSettings().GetStyleSettings();
774     Rectangle               aRect = pItem->maRect;
775     long                    nLeftBottom = aRect.Bottom();
776     long                    nRightBottom = aRect.Bottom();
777     sal_Bool                    bLeftBorder = sal_True;
778     sal_Bool                    bRightBorder = sal_True;
779     sal_uInt16                  nOff;
780     sal_Bool                    bNativeOK = sal_False;
781 
782     sal_uInt16 nOff2 = 0;
783     sal_uInt16 nOff3 = 0;
784 
785     if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
786         nOff = 1;
787     else
788         nOff = 0;
789 
790     // Wenn wir die aktuelle Page sind, muessen wir etwas mehr zeichnen
791     if ( pItem->mnId == mnCurPageId )
792     {
793         nOff2 = 2;
794         if( ! ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise )
795             nOff3 = 1;
796     }
797     else
798     {
799         Point aLeftTestPos = aRect.BottomLeft();
800         Point aRightTestPos = aRect.BottomRight();
801         if ( aLeftTestPos.Y() == rCurRect.Bottom() )
802         {
803             aLeftTestPos.X() -= 2;
804             if ( rCurRect.IsInside( aLeftTestPos ) )
805                 bLeftBorder = sal_False;
806             aRightTestPos.X() += 2;
807             if ( rCurRect.IsInside( aRightTestPos ) )
808                 bRightBorder = sal_False;
809         }
810         else
811         {
812             if ( rCurRect.IsInside( aLeftTestPos ) )
813                 nLeftBottom -= 2;
814             if ( rCurRect.IsInside( aRightTestPos ) )
815                 nRightBottom -= 2;
816         }
817     }
818 
819     if( !bLayout && (bNativeOK = IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL)) == sal_True )
820     {
821         Rectangle           aCtrlRegion( pItem->maRect );
822         ControlState		nState = 0;
823 
824         if( pItem->mnId == mnCurPageId )
825         {
826             nState |= CTRL_STATE_SELECTED;
827             // only the selected item can be focussed
828             if ( HasFocus() )
829                 nState |= CTRL_STATE_FOCUSED;
830         }
831         if ( IsEnabled() )
832             nState |= CTRL_STATE_ENABLED;
833         if( IsMouseOver() && pItem->maRect.IsInside( GetPointerPosPixel() ) )
834         {
835             nState |= CTRL_STATE_ROLLOVER;
836             for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
837                  it != mpTabCtrlData->maItemList.end(); ++it )
838             {
839                 if( (&(*it) != pItem) && (it->maRect.IsInside( GetPointerPosPixel() ) ) )
840                 {
841                     nState &= ~CTRL_STATE_ROLLOVER; // avoid multiple highlighted tabs
842                     break;
843                 }
844             }
845         }
846 
847         TabitemValue tiValue;
848         if(pItem->maRect.Left() < 5)
849             tiValue.mnAlignment |= TABITEM_LEFTALIGNED;
850         if(pItem->maRect.Right() > mnLastWidth - 5)
851             tiValue.mnAlignment |= TABITEM_RIGHTALIGNED;
852         if ( bFirstInGroup )
853             tiValue.mnAlignment |= TABITEM_FIRST_IN_GROUP;
854         if ( bLastInGroup )
855             tiValue.mnAlignment |= TABITEM_LAST_IN_GROUP;
856 
857         bNativeOK = DrawNativeControl( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
858                     tiValue, rtl::OUString() );
859     }
860 
861     if( ! bLayout && !bNativeOK )
862     {
863         if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
864         {
865             SetLineColor( rStyleSettings.GetLightColor() );
866             DrawPixel( Point( aRect.Left()+1-nOff2, aRect.Top()+1-nOff2 ) );    // diagonally indented top-left pixel
867             if ( bLeftBorder )
868             {
869                 DrawLine( Point( aRect.Left()-nOff2, aRect.Top()+2-nOff2 ),
870                           Point( aRect.Left()-nOff2, nLeftBottom-1 ) );
871             }
872             DrawLine( Point( aRect.Left()+2-nOff2, aRect.Top()-nOff2 ),         // top line starting 2px from left border
873                       Point( aRect.Right()+nOff2-3, aRect.Top()-nOff2 ) );      // ending 3px from right border
874 
875             if ( bRightBorder )
876             {
877                 SetLineColor( rStyleSettings.GetShadowColor() );
878                 DrawLine( Point( aRect.Right()+nOff2-2, aRect.Top()+1-nOff2 ),
879                           Point( aRect.Right()+nOff2-2, nRightBottom-1 ) );
880 
881                 SetLineColor( rStyleSettings.GetDarkShadowColor() );
882                 DrawLine( Point( aRect.Right()+nOff2-1, aRect.Top()+3-nOff2 ),
883                           Point( aRect.Right()+nOff2-1, nRightBottom-1 ) );
884             }
885         }
886         else
887         {
888             SetLineColor( Color( COL_BLACK ) );
889             DrawPixel( Point( aRect.Left()+1-nOff2, aRect.Top()+1-nOff2 ) );
890             DrawPixel( Point( aRect.Right()+nOff2-2, aRect.Top()+1-nOff2 ) );
891             if ( bLeftBorder )
892             {
893                 DrawLine( Point( aRect.Left()-nOff2, aRect.Top()+2-nOff2 ),
894                           Point( aRect.Left()-nOff2, nLeftBottom-1 ) );
895             }
896             DrawLine( Point( aRect.Left()+2-nOff2, aRect.Top()-nOff2 ),
897                       Point( aRect.Right()-3, aRect.Top()-nOff2 ) );
898             if ( bRightBorder )
899             {
900             DrawLine( Point( aRect.Right()+nOff2-1, aRect.Top()+2-nOff2 ),
901                       Point( aRect.Right()+nOff2-1, nRightBottom-1 ) );
902             }
903         }
904     }
905 
906     if( bLayout )
907     {
908         int nLine = mpControlData->mpLayoutData->m_aLineIndices.size();
909         mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.Len() );
910         mpTabCtrlData->maLayoutPageIdToLine[ (int)pItem->mnId ] = nLine;
911         mpTabCtrlData->maLayoutLineToPageId[ nLine ] = (int)pItem->mnId;
912         mpTabCtrlData->maTabRectangles.push_back( aRect );
913     }
914 
915     // set font accordingly, current item is painted bold
916     // we set the font attributes always before drawing to be re-entrant (DrawNativeControl may trigger additional paints)
917     Font aFont( GetFont() );
918     aFont.SetTransparent( sal_True );
919     aFont.SetWeight( ((bIsCurrentItem) && (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus)) ? WEIGHT_BOLD : WEIGHT_LIGHT );
920     SetFont( aFont );
921 
922     Size aTabSize = aRect.GetSize();
923     Size aImageSize( 0, 0 );
924     long nTextHeight = GetTextHeight();
925     long nTextWidth = GetCtrlTextWidth( pItem->maFormatText );
926     if( !! pItem->maTabImage )
927     {
928         aImageSize = pItem->maTabImage.GetSizePixel();
929         if( pItem->maFormatText.Len() )
930             aImageSize.Width() += GetTextHeight()/4;
931     }
932     long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-nOff3;
933     long nYPos = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-nOff3;
934     if( pItem->maFormatText.Len() )
935     {
936         sal_uInt16 nStyle = TEXT_DRAW_MNEMONIC;
937         if( ! pItem->mbEnabled )
938             nStyle |= TEXT_DRAW_DISABLE;
939         DrawCtrlText( Point( nXPos + aImageSize.Width(), nYPos ),
940                       pItem->maFormatText,
941                       0, STRING_LEN, nStyle,
942                       bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL,
943                       bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL
944                       );
945     }
946 
947     if( !! pItem->maTabImage )
948     {
949         Point aImgTL( nXPos, aRect.Top() );
950         if( aImageSize.Height() < aRect.GetHeight() )
951             aImgTL.Y() += (aRect.GetHeight() - aImageSize.Height())/2;
952         DrawImage( aImgTL, pItem->maTabImage, pItem->mbEnabled ? 0 : IMAGE_DRAW_DISABLE );
953     }
954 }
955 
956 // -----------------------------------------------------------------------
957 
958 long TabControl::ImplHandleKeyEvent( const KeyEvent& rKeyEvent )
959 {
960     long nRet = 0;
961 
962     if ( GetPageCount() > 1 )
963     {
964         KeyCode         aKeyCode = rKeyEvent.GetKeyCode();
965         sal_uInt16          nKeyCode = aKeyCode.GetCode();
966 
967         if ( aKeyCode.IsMod1() )
968         {
969             if ( aKeyCode.IsShift() || (nKeyCode == KEY_PAGEUP) )
970             {
971                 if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEUP) )
972                 {
973                     ImplActivateTabPage( sal_False );
974                     nRet = 1;
975                 }
976             }
977             else
978             {
979                 if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEDOWN) )
980                 {
981                     ImplActivateTabPage( sal_True );
982                     nRet = 1;
983                 }
984             }
985         }
986     }
987 
988     return nRet;
989 }
990 
991 
992 // -----------------------------------------------------------------------
993 
994 IMPL_LINK( TabControl, ImplListBoxSelectHdl, ListBox*, EMPTYARG )
995 {
996     SelectTabPage( GetPageId( mpTabCtrlData->mpListBox->GetSelectEntryPos() ) );
997     return 0;
998 }
999 
1000 // -----------------------------------------------------------------------
1001 
1002 IMPL_LINK( TabControl, ImplWindowEventListener, VclSimpleEvent*, pEvent )
1003 {
1004 	if ( pEvent && pEvent->ISA( VclWindowEvent ) && (pEvent->GetId() == VCLEVENT_WINDOW_KEYINPUT) )
1005 	{
1006 	    VclWindowEvent* pWindowEvent = static_cast< VclWindowEvent* >(pEvent);
1007 	    // Do not handle events from TabControl or it's children, which is done in Notify(), where the events can be consumed.
1008 	    if ( !IsWindowOrChild( pWindowEvent->GetWindow() ) )
1009 	    {
1010             KeyEvent* pKeyEvent = static_cast< KeyEvent* >(pWindowEvent->GetData());
1011 	        ImplHandleKeyEvent( *pKeyEvent );
1012 	    }
1013 	}
1014 	return 0;
1015 }
1016 
1017 
1018 // -----------------------------------------------------------------------
1019 
1020 void TabControl::MouseButtonDown( const MouseEvent& rMEvt )
1021 {
1022     if( mpTabCtrlData->mpListBox == NULL )
1023     {
1024         if( rMEvt.IsLeft() )
1025         {
1026             sal_uInt16 nPageId = GetPageId( rMEvt.GetPosPixel() );
1027             ImplTabItem* pItem = ImplGetItem( nPageId );
1028             if( pItem && pItem->mbEnabled )
1029                 SelectTabPage( nPageId );
1030         }
1031     }
1032 }
1033 
1034 // -----------------------------------------------------------------------
1035 
1036 void TabControl::KeyInput( const KeyEvent& rKEvt )
1037 {
1038     if( mpTabCtrlData->mpListBox )
1039         mpTabCtrlData->mpListBox->KeyInput( rKEvt );
1040     else if ( GetPageCount() > 1 )
1041     {
1042         KeyCode aKeyCode = rKEvt.GetKeyCode();
1043         sal_uInt16  nKeyCode = aKeyCode.GetCode();
1044 
1045         if ( (nKeyCode == KEY_LEFT) || (nKeyCode == KEY_RIGHT) )
1046         {
1047             sal_Bool bNext = (nKeyCode == KEY_RIGHT);
1048             ImplActivateTabPage( bNext );
1049         }
1050     }
1051 
1052     Control::KeyInput( rKEvt );
1053 }
1054 
1055 // -----------------------------------------------------------------------
1056 
1057 void TabControl::Paint( const Rectangle& rRect )
1058 {
1059     ImplPaint( rRect, false );
1060 }
1061 
1062 // -----------------------------------------------------------------------
1063 
1064 void TabControl::ImplPaint( const Rectangle& rRect, bool bLayout )
1065 {
1066     if( ! bLayout )
1067         HideFocus();
1068 
1069     // Hier wird gegebenenfalls auch neu formatiert
1070     Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
1071 
1072     // find current item
1073     ImplTabItem* pCurItem = NULL;
1074     for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1075          it != mpTabCtrlData->maItemList.end(); ++it )
1076     {
1077         if ( it->mnId == mnCurPageId )
1078         {
1079             pCurItem = &(*it);
1080             break;
1081         }
1082     }
1083 
1084     // Draw the TabPage border
1085     const StyleSettings&    rStyleSettings  = GetSettings().GetStyleSettings();
1086     Rectangle               aCurRect;
1087     long                    nTopOff = 1;
1088     aRect.Left()   -= TAB_OFFSET;
1089     aRect.Top()    -= TAB_OFFSET;
1090     aRect.Right()  += TAB_OFFSET;
1091     aRect.Bottom() += TAB_OFFSET;
1092 
1093     // if we have an invisible tabpage or no tabpage at all the tabpage rect should be
1094     // increased to avoid round corners that might be drawn by a theme
1095     // in this case we're only interested in the top border of the tabpage because the tabitems are used
1096     // standalone (eg impress)
1097     sal_Bool bNoTabPage = sal_False;
1098     TabPage*        pCurPage = (pCurItem) ? pCurItem->mpTabPage : NULL;
1099     if( !pCurPage || !pCurPage->IsVisible() )
1100     {
1101         bNoTabPage = sal_True;
1102         aRect.Left()-=10;
1103         aRect.Right()+=10;
1104     }
1105 
1106     sal_Bool bNativeOK = sal_False;
1107     if( ! bLayout && (bNativeOK = IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL) ) == sal_True )
1108     {
1109         const ImplControlValue aControlValue;
1110 
1111         ControlState nState = CTRL_STATE_ENABLED;
1112         int part = PART_ENTIRE_CONTROL;
1113         if ( !IsEnabled() )
1114             nState &= ~CTRL_STATE_ENABLED;
1115         if ( HasFocus() )
1116             nState |= CTRL_STATE_FOCUSED;
1117 
1118         Region aClipRgn( GetActiveClipRegion() );
1119         aClipRgn.Intersect( aRect );
1120         if( !rRect.IsEmpty() )
1121             aClipRgn.Intersect( rRect );
1122 
1123         if( !aClipRgn.IsEmpty() )
1124             bNativeOK = DrawNativeControl( CTRL_TAB_PANE, part, aRect, nState,
1125                 aControlValue, rtl::OUString() );
1126     }
1127     else
1128     {
1129         if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
1130             SetLineColor( rStyleSettings.GetLightColor() );
1131         else
1132             SetLineColor( Color( COL_BLACK ) );
1133         if ( pCurItem && !pCurItem->maRect.IsEmpty() )
1134         {
1135             aCurRect = pCurItem->maRect;
1136             if( ! bLayout )
1137                 DrawLine( aRect.TopLeft(), Point( aCurRect.Left()-2, aRect.Top() ) );
1138             if ( aCurRect.Right()+1 < aRect.Right() )
1139             {
1140                 if( ! bLayout )
1141                     DrawLine( Point( aCurRect.Right(), aRect.Top() ), aRect.TopRight() );
1142             }
1143             else
1144                 nTopOff = 0;
1145         }
1146         else
1147             if( ! bLayout )
1148                 DrawLine( aRect.TopLeft(), aRect.TopRight() );
1149 
1150         if( ! bLayout )
1151         {
1152             DrawLine( aRect.TopLeft(), aRect.BottomLeft() );
1153 
1154             if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
1155             {
1156                 // if we have not tab page the bottom line of the tab page
1157                 // directly touches the tab items, so choose a color that fits seamlessly
1158                 if( bNoTabPage )
1159                     SetLineColor( rStyleSettings.GetDialogColor() );
1160                 else
1161                     SetLineColor( rStyleSettings.GetShadowColor() );
1162                 DrawLine( Point( 1, aRect.Bottom()-1 ),
1163                         Point( aRect.Right()-1, aRect.Bottom()-1 ) );
1164                 DrawLine( Point( aRect.Right()-1, aRect.Top()+nTopOff ),
1165                         Point( aRect.Right()-1, aRect.Bottom()-1 ) );
1166                 if( bNoTabPage )
1167                     SetLineColor( rStyleSettings.GetDialogColor() );
1168                 else
1169                     SetLineColor( rStyleSettings.GetDarkShadowColor() );
1170                 DrawLine( Point( 0, aRect.Bottom() ),
1171                         Point( aRect.Right(), aRect.Bottom() ) );
1172                 DrawLine( Point( aRect.Right(), aRect.Top()+nTopOff ),
1173                         Point( aRect.Right(), aRect.Bottom() ) );
1174             }
1175             else
1176             {
1177                 DrawLine( aRect.TopRight(), aRect.BottomRight() );
1178                 DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
1179             }
1180         }
1181     }
1182 
1183     if ( !mpTabCtrlData->maItemList.empty() && mpTabCtrlData->mpListBox == NULL )
1184     {
1185         // Some native toolkits (GTK+) draw tabs right-to-left, with an
1186         // overlap between adjacent tabs
1187         bool			bDrawTabsRTL = IsNativeControlSupported( CTRL_TAB_ITEM, PART_TABS_DRAW_RTL );
1188         ImplTabItem *	pFirstTab = NULL;
1189         ImplTabItem *	pLastTab = NULL;
1190         size_t idx;
1191 
1192         // Event though there is a tab overlap with GTK+, the first tab is not
1193         // overlapped on the left side.  Other tookits ignore this option.
1194         if ( bDrawTabsRTL )
1195         {
1196             pFirstTab = &mpTabCtrlData->maItemList.front();
1197             pLastTab = &mpTabCtrlData->maItemList.back();
1198             idx = mpTabCtrlData->maItemList.size()-1;
1199         }
1200         else
1201         {
1202             pLastTab = &mpTabCtrlData->maItemList.back();
1203             pFirstTab = &mpTabCtrlData->maItemList.front();
1204             idx = 0;
1205         }
1206 
1207         while ( idx < mpTabCtrlData->maItemList.size() )
1208         {
1209             ImplTabItem* pItem = &mpTabCtrlData->maItemList[idx];
1210             if ( pItem != pCurItem )
1211             {
1212                 Region aClipRgn( GetActiveClipRegion() );
1213                 aClipRgn.Intersect( pItem->maRect );
1214                 if( !rRect.IsEmpty() )
1215                     aClipRgn.Intersect( rRect );
1216                 if( bLayout || !aClipRgn.IsEmpty() )
1217                     ImplDrawItem( pItem, aCurRect, bLayout, (pItem==pFirstTab), (pItem==pLastTab), sal_False );
1218             }
1219 
1220             if ( bDrawTabsRTL )
1221                 idx--;
1222             else
1223                 idx++;
1224         }
1225 
1226         if ( pCurItem )
1227         {
1228             Region aClipRgn( GetActiveClipRegion() );
1229             aClipRgn.Intersect( pCurItem->maRect );
1230             if( !rRect.IsEmpty() )
1231                 aClipRgn.Intersect( rRect );
1232             if( bLayout || !aClipRgn.IsEmpty() )
1233                 ImplDrawItem( pCurItem, aCurRect, bLayout, (pCurItem==pFirstTab), (pCurItem==pLastTab), sal_True );
1234         }
1235     }
1236 
1237     if ( !bLayout && HasFocus() )
1238         ImplShowFocus();
1239 
1240     if( ! bLayout )
1241         mbSmallInvalidate = sal_True;
1242 }
1243 
1244 // -----------------------------------------------------------------------
1245 
1246 void TabControl::Resize()
1247 {
1248     ImplFreeLayoutData();
1249 
1250     if ( !IsReallyShown() )
1251         return;
1252 
1253     if( mpTabCtrlData->mpListBox )
1254     {
1255         // get the listbox' preferred size
1256         Size aTabCtrlSize( GetSizePixel() );
1257         long nPrefWidth = mpTabCtrlData->mpListBox->GetOptimalSize( WINDOWSIZE_PREFERRED ).Width();
1258         if( nPrefWidth > aTabCtrlSize.Width() )
1259             nPrefWidth = aTabCtrlSize.Width();
1260         Size aNewSize( nPrefWidth, LogicToPixel( Size( 12, 12 ), MapMode( MAP_APPFONT ) ).Height() );
1261         Point aNewPos( (aTabCtrlSize.Width() - nPrefWidth) / 2, 0 );
1262         mpTabCtrlData->mpListBox->SetPosSizePixel( aNewPos, aNewSize );
1263     }
1264 
1265     mbFormat = sal_True;
1266 
1267     // Aktuelle TabPage resizen/positionieren
1268     sal_Bool bTabPage = ImplPosCurTabPage();
1269     // Feststellen, was invalidiert werden muss
1270     Size aNewSize = Control::GetOutputSizePixel();
1271     long nNewWidth = aNewSize.Width();
1272     for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1273          it != mpTabCtrlData->maItemList.end(); ++it )
1274     {
1275         if ( !it->mbFullVisible ||
1276              (it->maRect.Right()-2 >= nNewWidth) )
1277         {
1278             mbSmallInvalidate = sal_False;
1279             break;
1280         }
1281     }
1282 
1283     if ( mbSmallInvalidate )
1284     {
1285         Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
1286         aRect.Left()   -= TAB_OFFSET+TAB_BORDER_LEFT;
1287         aRect.Top()    -= TAB_OFFSET+TAB_BORDER_TOP;
1288         aRect.Right()  += TAB_OFFSET+TAB_BORDER_RIGHT;
1289         aRect.Bottom() += TAB_OFFSET+TAB_BORDER_BOTTOM;
1290         if ( bTabPage )
1291             Invalidate( aRect, INVALIDATE_NOCHILDREN );
1292         else
1293             Invalidate( aRect );
1294 
1295     }
1296     else
1297     {
1298         if ( bTabPage )
1299             Invalidate( INVALIDATE_NOCHILDREN );
1300         else
1301             Invalidate();
1302     }
1303 }
1304 
1305 // -----------------------------------------------------------------------
1306 
1307 void TabControl::GetFocus()
1308 {
1309     if( ! mpTabCtrlData->mpListBox )
1310     {
1311         ImplShowFocus();
1312         SetInputContext( InputContext( GetFont() ) );
1313     }
1314     else
1315     {
1316         if( mpTabCtrlData->mpListBox->IsReallyVisible() )
1317             mpTabCtrlData->mpListBox->GrabFocus();
1318     }
1319     Control::GetFocus();
1320 }
1321 
1322 // -----------------------------------------------------------------------
1323 
1324 void TabControl::LoseFocus()
1325 {
1326     if( ! mpTabCtrlData->mpListBox )
1327         HideFocus();
1328     Control::LoseFocus();
1329 }
1330 
1331 // -----------------------------------------------------------------------
1332 
1333 void TabControl::RequestHelp( const HelpEvent& rHEvt )
1334 {
1335     sal_uInt16 nItemId = rHEvt.KeyboardActivated() ? mnCurPageId : GetPageId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
1336 
1337     if ( nItemId )
1338     {
1339         if ( rHEvt.GetMode() & HELPMODE_BALLOON )
1340         {
1341             XubString aStr = GetHelpText( nItemId );
1342             if ( aStr.Len() )
1343             {
1344                 Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1345                 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1346                 aItemRect.Left()   = aPt.X();
1347                 aItemRect.Top()    = aPt.Y();
1348                 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1349                 aItemRect.Right()  = aPt.X();
1350                 aItemRect.Bottom() = aPt.Y();
1351                 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
1352                 return;
1353             }
1354         }
1355         else if ( rHEvt.GetMode() & HELPMODE_EXTENDED )
1356         {
1357             rtl::OUString aHelpId( rtl::OStringToOUString( GetHelpId( nItemId ), RTL_TEXTENCODING_UTF8 ) );
1358             if ( aHelpId.getLength() )
1359             {
1360                 // Wenn eine Hilfe existiert, dann ausloesen
1361                 Help* pHelp = Application::GetHelp();
1362                 if ( pHelp )
1363                     pHelp->Start( aHelpId, this );
1364                 return;
1365             }
1366         }
1367 
1368         // Bei Quick- oder Balloon-Help zeigen wir den Text an,
1369         // wenn dieser abgeschnitten ist
1370         if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) )
1371         {
1372             ImplTabItem* pItem = ImplGetItem( nItemId );
1373             const XubString& rStr = pItem->maText;
1374             if ( rStr != pItem->maFormatText )
1375             {
1376                 Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1377                 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1378                 aItemRect.Left()   = aPt.X();
1379                 aItemRect.Top()    = aPt.Y();
1380                 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1381                 aItemRect.Right()  = aPt.X();
1382                 aItemRect.Bottom() = aPt.Y();
1383                 if ( rStr.Len() )
1384                 {
1385                     if ( rHEvt.GetMode() & HELPMODE_BALLOON )
1386                         Help::ShowBalloon( this, aItemRect.Center(), aItemRect, rStr );
1387                     else
1388                         Help::ShowQuickHelp( this, aItemRect, rStr );
1389                     return;
1390                 }
1391             }
1392         }
1393 
1394         if ( rHEvt.GetMode() & HELPMODE_QUICK )
1395         {
1396             ImplTabItem* pItem = ImplGetItem( nItemId );
1397             const XubString& rHelpText = pItem->maHelpText;
1398             // show tooltip if not text but image is set and helptext is available
1399             if ( rHelpText.Len() > 0 && pItem->maText.Len() == 0 && !!pItem->maTabImage )
1400             {
1401                 Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1402                 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1403                 aItemRect.Left()   = aPt.X();
1404                 aItemRect.Top()    = aPt.Y();
1405                 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1406                 aItemRect.Right()  = aPt.X();
1407                 aItemRect.Bottom() = aPt.Y();
1408                 Help::ShowQuickHelp( this, aItemRect, rHelpText );
1409                 return;
1410             }
1411         }
1412     }
1413 
1414     Control::RequestHelp( rHEvt );
1415 }
1416 
1417 // -----------------------------------------------------------------------
1418 
1419 void TabControl::Command( const CommandEvent& rCEvt )
1420 {
1421     if( (mpTabCtrlData->mpListBox == NULL) && (rCEvt.GetCommand() == COMMAND_CONTEXTMENU) && (GetPageCount() > 1) )
1422     {
1423         Point   aMenuPos;
1424         sal_Bool    bMenu;
1425         if ( rCEvt.IsMouseEvent() )
1426         {
1427             aMenuPos = rCEvt.GetMousePosPixel();
1428             bMenu = GetPageId( aMenuPos ) != 0;
1429         }
1430         else
1431         {
1432             aMenuPos = ImplGetTabRect( GetPagePos( mnCurPageId ) ).Center();
1433             bMenu = sal_True;
1434         }
1435 
1436         if ( bMenu )
1437         {
1438             PopupMenu aMenu;
1439             for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1440                  it != mpTabCtrlData->maItemList.end(); ++it )
1441             {
1442                 aMenu.InsertItem( it->mnId, it->maText, MIB_CHECKABLE | MIB_RADIOCHECK );
1443                 if ( it->mnId == mnCurPageId )
1444                     aMenu.CheckItem( it->mnId );
1445                 aMenu.SetHelpId( it->mnId, it->maHelpId );
1446             }
1447 
1448             sal_uInt16 nId = aMenu.Execute( this, aMenuPos );
1449             if ( nId && (nId != mnCurPageId) )
1450                 SelectTabPage( nId );
1451             return;
1452         }
1453     }
1454 
1455     Control::Command( rCEvt );
1456 }
1457 
1458 // -----------------------------------------------------------------------
1459 
1460 void TabControl::StateChanged( StateChangedType nType )
1461 {
1462     Control::StateChanged( nType );
1463 
1464     if ( nType == STATE_CHANGE_INITSHOW )
1465     {
1466         ImplPosCurTabPage();
1467         if( mpTabCtrlData->mpListBox )
1468             Resize();
1469     }
1470     else if ( nType == STATE_CHANGE_UPDATEMODE )
1471     {
1472         if ( IsUpdateMode() )
1473             Invalidate();
1474     }
1475     else if ( (nType == STATE_CHANGE_ZOOM)  ||
1476               (nType == STATE_CHANGE_CONTROLFONT) )
1477     {
1478         ImplInitSettings( sal_True, sal_False, sal_False );
1479         Invalidate();
1480     }
1481     else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
1482     {
1483         ImplInitSettings( sal_False, sal_True, sal_False );
1484         Invalidate();
1485     }
1486     else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
1487     {
1488         ImplInitSettings( sal_False, sal_False, sal_True );
1489         Invalidate();
1490     }
1491 }
1492 
1493 // -----------------------------------------------------------------------
1494 
1495 void TabControl::DataChanged( const DataChangedEvent& rDCEvt )
1496 {
1497     Control::DataChanged( rDCEvt );
1498 
1499     if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
1500          (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
1501          ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
1502           (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
1503     {
1504         ImplInitSettings( sal_True, sal_True, sal_True );
1505         Invalidate();
1506     }
1507 }
1508 
1509 // -----------------------------------------------------------------------
1510 
1511 Rectangle* TabControl::ImplFindPartRect( const Point& rPt )
1512 {
1513     ImplTabItem* pFoundItem = NULL;
1514     int nFound = 0;
1515     for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1516          it != mpTabCtrlData->maItemList.end(); ++it )
1517     {
1518         if ( it->maRect.IsInside( rPt ) )
1519         {
1520             // assure that only one tab is highlighted at a time
1521             nFound++;
1522             pFoundItem = &(*it);
1523         }
1524     }
1525     // assure that only one tab is highlighted at a time
1526     return nFound == 1 ? &pFoundItem->maRect : NULL;
1527 }
1528 
1529 long TabControl::PreNotify( NotifyEvent& rNEvt )
1530 {
1531     long nDone = 0;
1532     const MouseEvent* pMouseEvt = NULL;
1533 
1534     if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
1535     {
1536         if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
1537         {
1538             // trigger redraw if mouse over state has changed
1539             if( IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) )
1540             {
1541                 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
1542                 Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
1543                 if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
1544                 {
1545                     Region aClipRgn;
1546                     if( pLastRect )
1547                     {
1548                         // allow for slightly bigger tabitems
1549                         // as used by gtk
1550                         // TODO: query for the correct sizes
1551                         Rectangle aRect(*pLastRect);
1552                         aRect.nLeft-=2;
1553                         aRect.nRight+=2;
1554                         aRect.nTop-=3;
1555                         aClipRgn.Union( aRect );
1556                     }
1557                     if( pRect )
1558                     {
1559                         // allow for slightly bigger tabitems
1560                         // as used by gtk
1561                         // TODO: query for the correct sizes
1562                         Rectangle aRect(*pRect);
1563                         aRect.nLeft-=2;
1564                         aRect.nRight+=2;
1565                         aRect.nTop-=3;
1566                         aClipRgn.Union( aRect );
1567                     }
1568                     if( !aClipRgn.IsEmpty() )
1569                         Invalidate( aClipRgn );
1570                 }
1571             }
1572         }
1573     }
1574 
1575     return nDone ? nDone : Control::PreNotify(rNEvt);
1576 }
1577 
1578 // -----------------------------------------------------------------------
1579 
1580 long TabControl::Notify( NotifyEvent& rNEvt )
1581 {
1582     long nRet = 0;
1583 
1584     if ( rNEvt.GetType() == EVENT_KEYINPUT )
1585         nRet = ImplHandleKeyEvent( *rNEvt.GetKeyEvent() );
1586 
1587     return nRet ? nRet : Control::Notify( rNEvt );
1588 }
1589 
1590 // -----------------------------------------------------------------------
1591 
1592 void TabControl::ActivatePage()
1593 {
1594     maActivateHdl.Call( this );
1595 }
1596 
1597 // -----------------------------------------------------------------------
1598 
1599 long TabControl::DeactivatePage()
1600 {
1601     if ( maDeactivateHdl.IsSet() )
1602         return maDeactivateHdl.Call( this );
1603     else
1604         return sal_True;
1605 }
1606 
1607 // -----------------------------------------------------------------------
1608 
1609 void TabControl::SetTabPageSizePixel( const Size& rSize )
1610 {
1611     ImplFreeLayoutData();
1612 
1613     Size aNewSize( rSize );
1614     aNewSize.Width() += TAB_OFFSET*2;
1615     Rectangle aRect = ImplGetTabRect( TAB_PAGERECT,
1616                                       aNewSize.Width(), aNewSize.Height() );
1617     aNewSize.Height() += aRect.Top()+TAB_OFFSET;
1618     Window::SetOutputSizePixel( aNewSize );
1619 }
1620 
1621 // -----------------------------------------------------------------------
1622 
1623 Size TabControl::GetTabPageSizePixel() const
1624 {
1625     Rectangle aRect = ((TabControl*)this)->ImplGetTabRect( TAB_PAGERECT );
1626     return aRect.GetSize();
1627 }
1628 
1629 // -----------------------------------------------------------------------
1630 
1631 void TabControl::InsertPage( const ResId& rResId, sal_uInt16 nPos )
1632 {
1633     GetRes( rResId.SetRT( RSC_TABCONTROLITEM ) );
1634 
1635     sal_uLong nObjMask = ReadLongRes();
1636     sal_uInt16 nItemId  = 1;
1637 
1638     // ID
1639     if ( nObjMask & RSC_TABCONTROLITEM_ID )
1640         nItemId = sal::static_int_cast<sal_uInt16>(ReadLongRes());
1641 
1642     // Text
1643     XubString aTmpStr;
1644     if( nObjMask & RSC_TABCONTROLITEM_TEXT )
1645         aTmpStr = ReadStringRes();
1646     InsertPage( nItemId, aTmpStr, nPos );
1647 
1648     // PageResID
1649     if ( nObjMask & RSC_TABCONTROLITEM_PAGERESID )
1650     {
1651         ImplTabItem& rItem = mpTabCtrlData->maItemList[ GetPagePos( nItemId ) ];
1652         rItem.mnTabPageResId = sal::static_int_cast<sal_uInt16>(ReadLongRes());
1653     }
1654 }
1655 
1656 // -----------------------------------------------------------------------
1657 
1658 void TabControl::InsertPage( sal_uInt16 nPageId, const XubString& rText,
1659                              sal_uInt16 nPos )
1660 {
1661     DBG_ASSERT( nPageId, "TabControl::InsertPage(): PageId == 0" );
1662     DBG_ASSERT( GetPagePos( nPageId ) == TAB_PAGE_NOTFOUND,
1663                 "TabControl::InsertPage(): PageId already exists" );
1664 
1665     // insert new page item
1666     ImplTabItem* pItem = NULL;
1667     if( nPos == TAB_APPEND || size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1668     {
1669         mpTabCtrlData->maItemList.push_back( ImplTabItem() );
1670         pItem = &mpTabCtrlData->maItemList.back();
1671         if( mpTabCtrlData->mpListBox )
1672             mpTabCtrlData->mpListBox->InsertEntry( rText );
1673     }
1674     else
1675     {
1676         std::vector< ImplTabItem >::iterator new_it =
1677             mpTabCtrlData->maItemList.insert( mpTabCtrlData->maItemList.begin() + nPos, ImplTabItem() );
1678         pItem = &(*new_it);
1679         if( mpTabCtrlData->mpListBox )
1680             mpTabCtrlData->mpListBox->InsertEntry( rText, nPos);
1681     }
1682     if( mpTabCtrlData->mpListBox )
1683     {
1684         if( ! mnCurPageId )
1685             mpTabCtrlData->mpListBox->SelectEntryPos( 0 );
1686         mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
1687     }
1688 
1689     // set current page id
1690     if ( !mnCurPageId )
1691         mnCurPageId = nPageId;
1692 
1693     // init new page item
1694     pItem->mnId             = nPageId;
1695     pItem->mpTabPage        = NULL;
1696     pItem->mnTabPageResId   = 0;
1697     pItem->maText           = rText;
1698     pItem->mbFullVisible    = sal_False;
1699 
1700     mbFormat = sal_True;
1701     if ( IsUpdateMode() )
1702         Invalidate();
1703 
1704     ImplFreeLayoutData();
1705     if( mpTabCtrlData->mpListBox ) // reposition/resize listbox
1706         Resize();
1707 
1708 	ImplCallEventListeners( VCLEVENT_TABPAGE_INSERTED, (void*) (sal_uLong)nPageId );
1709 }
1710 
1711 // -----------------------------------------------------------------------
1712 
1713 void TabControl::RemovePage( sal_uInt16 nPageId )
1714 {
1715     sal_uInt16 nPos = GetPagePos( nPageId );
1716 
1717     // does the item exist ?
1718     if ( nPos != TAB_PAGE_NOTFOUND )
1719     {
1720         //remove page item
1721         std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin() + nPos;
1722         bool bIsCurrentPage = (it->mnId == mnCurPageId);
1723         mpTabCtrlData->maItemList.erase( it );
1724         if( mpTabCtrlData->mpListBox )
1725         {
1726             mpTabCtrlData->mpListBox->RemoveEntry( nPos );
1727             mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
1728         }
1729 
1730         // If current page is removed, than first page gets the current page
1731         if ( bIsCurrentPage  )
1732         {
1733             mnCurPageId = 0;
1734 
1735             if( ! mpTabCtrlData->maItemList.empty() )
1736             {
1737                 // don't do this by simply setting mnCurPageId to pFirstItem->mnId
1738                 // this leaves a lot of stuff (such trivias as _showing_ the new current page) undone
1739                 // instead, call SetCurPageId
1740                 // without this, the next (outside) call to SetCurPageId with the id of the first page
1741                 // will result in doing nothing (as we assume that nothing changed, then), and the page
1742                 // will never be shown.
1743                 // 86875 - 05/11/2001 - frank.schoenheit@germany.sun.com
1744 
1745                 SetCurPageId( mpTabCtrlData->maItemList[0].mnId );
1746             }
1747         }
1748 
1749         mbFormat = sal_True;
1750         if ( IsUpdateMode() )
1751             Invalidate();
1752 
1753         ImplFreeLayoutData();
1754 
1755 		ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVED, (void*) (sal_uLong) nPageId );
1756     }
1757 }
1758 
1759 // -----------------------------------------------------------------------
1760 
1761 void TabControl::Clear()
1762 {
1763     // clear item list
1764     mpTabCtrlData->maItemList.clear();
1765     mnCurPageId = 0;
1766     if( mpTabCtrlData->mpListBox )
1767         mpTabCtrlData->mpListBox->Clear();
1768 
1769     ImplFreeLayoutData();
1770 
1771     mbFormat = sal_True;
1772     if ( IsUpdateMode() )
1773         Invalidate();
1774 
1775 	ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVEDALL );
1776 }
1777 
1778 // -----------------------------------------------------------------------
1779 
1780 void TabControl::EnablePage( sal_uInt16 i_nPageId, bool i_bEnable )
1781 {
1782     ImplTabItem* pItem = ImplGetItem( i_nPageId );
1783 
1784     if ( pItem && pItem->mbEnabled != i_bEnable )
1785     {
1786         pItem->mbEnabled = i_bEnable;
1787         mbFormat = sal_True;
1788         if( mpTabCtrlData->mpListBox )
1789             mpTabCtrlData->mpListBox->SetEntryFlags( GetPagePos( i_nPageId ),
1790                                                      i_bEnable ? 0 : (LISTBOX_ENTRY_FLAG_DISABLE_SELECTION | LISTBOX_ENTRY_FLAG_DRAW_DISABLED) );
1791         if( pItem->mnId == mnCurPageId )
1792         {
1793              // SetCurPageId will change to an enabled page
1794             SetCurPageId( mnCurPageId );
1795         }
1796         else if ( IsUpdateMode() )
1797             Invalidate();
1798     }
1799 }
1800 
1801 // -----------------------------------------------------------------------
1802 
1803 sal_uInt16 TabControl::GetPageCount() const
1804 {
1805     return (sal_uInt16)mpTabCtrlData->maItemList.size();
1806 }
1807 
1808 // -----------------------------------------------------------------------
1809 
1810 sal_uInt16 TabControl::GetPageId( sal_uInt16 nPos ) const
1811 {
1812     if( size_t(nPos) < mpTabCtrlData->maItemList.size() )
1813         return mpTabCtrlData->maItemList[ nPos ].mnId;
1814     return 0;
1815 }
1816 
1817 // -----------------------------------------------------------------------
1818 
1819 sal_uInt16 TabControl::GetPagePos( sal_uInt16 nPageId ) const
1820 {
1821     for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
1822          it != mpTabCtrlData->maItemList.end(); ++it )
1823     {
1824         if ( it->mnId == nPageId )
1825             return (sal_uInt16)(it - mpTabCtrlData->maItemList.begin());
1826     }
1827 
1828     return TAB_PAGE_NOTFOUND;
1829 }
1830 
1831 // -----------------------------------------------------------------------
1832 
1833 sal_uInt16 TabControl::GetPageId( const Point& rPos ) const
1834 {
1835     for( size_t i = 0; i < mpTabCtrlData->maItemList.size(); ++i )
1836     {
1837         if ( ((TabControl*)this)->ImplGetTabRect( static_cast<sal_uInt16>(i) ).IsInside( rPos ) )
1838             return mpTabCtrlData->maItemList[ i ].mnId;
1839     }
1840 
1841     return 0;
1842 }
1843 
1844 // -----------------------------------------------------------------------
1845 
1846 void TabControl::SetCurPageId( sal_uInt16 nPageId )
1847 {
1848     sal_uInt16 nPos = GetPagePos( nPageId );
1849     while( nPos != TAB_PAGE_NOTFOUND &&
1850            ! mpTabCtrlData->maItemList[nPos].mbEnabled )
1851     {
1852         nPos++;
1853         if( size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1854             nPos = 0;
1855         if( mpTabCtrlData->maItemList[nPos].mnId == nPageId )
1856             break;
1857     }
1858 
1859     if( nPos != TAB_PAGE_NOTFOUND )
1860     {
1861         nPageId = mpTabCtrlData->maItemList[nPos].mnId;
1862         if ( nPageId == mnCurPageId )
1863         {
1864             if ( mnActPageId )
1865                 mnActPageId = nPageId;
1866             return;
1867         }
1868 
1869         if ( mnActPageId )
1870             mnActPageId = nPageId;
1871         else
1872         {
1873             mbFormat = sal_True;
1874             sal_uInt16 nOldId = mnCurPageId;
1875             mnCurPageId = nPageId;
1876             ImplChangeTabPage( nPageId, nOldId );
1877         }
1878     }
1879 }
1880 
1881 // -----------------------------------------------------------------------
1882 
1883 sal_uInt16 TabControl::GetCurPageId() const
1884 {
1885     if ( mnActPageId )
1886         return mnActPageId;
1887     else
1888         return mnCurPageId;
1889 }
1890 
1891 // -----------------------------------------------------------------------
1892 
1893 void TabControl::SelectTabPage( sal_uInt16 nPageId )
1894 {
1895     if ( nPageId && (nPageId != mnCurPageId) )
1896     {
1897         ImplFreeLayoutData();
1898 
1899 		ImplCallEventListeners( VCLEVENT_TABPAGE_DEACTIVATE, (void*) (sal_uLong) mnCurPageId );
1900         if ( DeactivatePage() )
1901         {
1902             mnActPageId = nPageId;
1903             ActivatePage();
1904             // Page koennte im Activate-Handler umgeschaltet wurden sein
1905             nPageId = mnActPageId;
1906             mnActPageId = 0;
1907             SetCurPageId( nPageId );
1908             if( mpTabCtrlData->mpListBox )
1909                 mpTabCtrlData->mpListBox->SelectEntryPos( GetPagePos( nPageId ) );
1910 			ImplCallEventListeners( VCLEVENT_TABPAGE_ACTIVATE, (void*) (sal_uLong) nPageId );
1911         }
1912     }
1913 }
1914 
1915 // -----------------------------------------------------------------------
1916 
1917 void TabControl::SetTabPage( sal_uInt16 nPageId, TabPage* pTabPage )
1918 {
1919     ImplTabItem* pItem = ImplGetItem( nPageId );
1920 
1921     if ( pItem && (pItem->mpTabPage != pTabPage) )
1922     {
1923         if ( pTabPage )
1924         {
1925             DBG_ASSERT( !pTabPage->IsVisible(), "TabControl::SetTabPage() - Page is visible" );
1926 
1927             if ( IsDefaultSize() )
1928                 SetTabPageSizePixel( pTabPage->GetSizePixel() );
1929 
1930             // Erst hier setzen, damit Resize nicht TabPage umpositioniert
1931             pItem->mpTabPage = pTabPage;
1932             if ( pItem->mnId == mnCurPageId )
1933                 ImplChangeTabPage( pItem->mnId, 0 );
1934         }
1935         else
1936             pItem->mpTabPage = NULL;
1937     }
1938 }
1939 
1940 // -----------------------------------------------------------------------
1941 
1942 TabPage* TabControl::GetTabPage( sal_uInt16 nPageId ) const
1943 {
1944     ImplTabItem* pItem = ImplGetItem( nPageId );
1945 
1946     if ( pItem )
1947         return pItem->mpTabPage;
1948     else
1949         return NULL;
1950 }
1951 
1952 // -----------------------------------------------------------------------
1953 
1954 sal_uInt16 TabControl::GetTabPageResId( sal_uInt16 nPageId ) const
1955 {
1956     ImplTabItem* pItem = ImplGetItem( nPageId );
1957 
1958     if ( pItem )
1959         return pItem->mnTabPageResId;
1960     else
1961         return 0;
1962 }
1963 
1964 // -----------------------------------------------------------------------
1965 
1966 void TabControl::SetPageText( sal_uInt16 nPageId, const XubString& rText )
1967 {
1968     ImplTabItem* pItem = ImplGetItem( nPageId );
1969 
1970     if ( pItem && pItem->maText != rText )
1971     {
1972         pItem->maText = rText;
1973         mbFormat = sal_True;
1974         if( mpTabCtrlData->mpListBox )
1975         {
1976             sal_uInt16 nPos = GetPagePos( nPageId );
1977             mpTabCtrlData->mpListBox->RemoveEntry( nPos );
1978             mpTabCtrlData->mpListBox->InsertEntry( rText, nPos );
1979         }
1980         if ( IsUpdateMode() )
1981             Invalidate();
1982         ImplFreeLayoutData();
1983 		ImplCallEventListeners( VCLEVENT_TABPAGE_PAGETEXTCHANGED, (void*) (sal_uLong) nPageId );
1984     }
1985 }
1986 
1987 // -----------------------------------------------------------------------
1988 
1989 XubString TabControl::GetPageText( sal_uInt16 nPageId ) const
1990 {
1991     ImplTabItem* pItem = ImplGetItem( nPageId );
1992 
1993     if ( pItem )
1994         return pItem->maText;
1995     else
1996         return ImplGetSVEmptyStr();
1997 }
1998 
1999 // -----------------------------------------------------------------------
2000 
2001 void TabControl::SetHelpText( sal_uInt16 nPageId, const XubString& rText )
2002 {
2003     ImplTabItem* pItem = ImplGetItem( nPageId );
2004 
2005     if ( pItem )
2006         pItem->maHelpText = rText;
2007 }
2008 
2009 // -----------------------------------------------------------------------
2010 
2011 const XubString& TabControl::GetHelpText( sal_uInt16 nPageId ) const
2012 {
2013     ImplTabItem* pItem = ImplGetItem( nPageId );
2014 
2015     if ( pItem )
2016     {
2017         if ( !pItem->maHelpText.Len() && pItem->maHelpId.getLength() )
2018         {
2019             Help* pHelp = Application::GetHelp();
2020             if ( pHelp )
2021                 pItem->maHelpText = pHelp->GetHelpText( rtl::OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this );
2022         }
2023 
2024         return pItem->maHelpText;
2025     }
2026     else
2027         return ImplGetSVEmptyStr();
2028 }
2029 
2030 // -----------------------------------------------------------------------
2031 
2032 void TabControl::SetHelpId( sal_uInt16 nPageId, const rtl::OString& rHelpId )
2033 {
2034     ImplTabItem* pItem = ImplGetItem( nPageId );
2035 
2036     if ( pItem )
2037         pItem->maHelpId = rHelpId;
2038 }
2039 
2040 // -----------------------------------------------------------------------
2041 
2042 rtl::OString TabControl::GetHelpId( sal_uInt16 nPageId ) const
2043 {
2044     rtl::OString aRet;
2045     ImplTabItem* pItem = ImplGetItem( nPageId );
2046 
2047     if ( pItem )
2048         aRet = pItem->maHelpId;
2049 
2050     return aRet;
2051 }
2052 
2053 // -----------------------------------------------------------------------
2054 
2055 void TabControl::SetPageImage( sal_uInt16 i_nPageId, const Image& i_rImage )
2056 {
2057     ImplTabItem* pItem = ImplGetItem( i_nPageId );
2058 
2059     if ( pItem )
2060     {
2061         pItem->maTabImage = i_rImage;
2062         mbFormat = sal_True;
2063         if ( IsUpdateMode() )
2064             Invalidate();
2065     }
2066 }
2067 
2068 // -----------------------------------------------------------------------
2069 
2070 const Image* TabControl::GetPageImage( sal_uInt16 i_nPageId ) const
2071 {
2072     const ImplTabItem* pItem = ImplGetItem( i_nPageId );
2073     return pItem ? &pItem->maTabImage : NULL;
2074 }
2075 
2076 // -----------------------------------------------------------------------
2077 
2078 Rectangle TabControl::GetCharacterBounds( sal_uInt16 nPageId, long nIndex ) const
2079 {
2080     Rectangle aRet;
2081 
2082     if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
2083         FillLayoutData();
2084 
2085     if( HasLayoutData() )
2086     {
2087         std::hash_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( (int)nPageId );
2088         if( it != mpTabCtrlData->maLayoutPageIdToLine.end() )
2089         {
2090             Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( it->second );
2091             if( (aPair.B() - aPair.A()) >= nIndex )
2092                 aRet = mpControlData->mpLayoutData->GetCharacterBounds( aPair.A() + nIndex );
2093         }
2094     }
2095 
2096     return aRet;
2097 }
2098 
2099 // -----------------------------------------------------------------------
2100 
2101 long TabControl::GetIndexForPoint( const Point& rPoint, sal_uInt16& rPageId ) const
2102 {
2103     long nRet = -1;
2104 
2105     if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
2106         FillLayoutData();
2107 
2108     if( HasLayoutData() )
2109     {
2110         int nIndex = mpControlData->mpLayoutData->GetIndexForPoint( rPoint );
2111         if( nIndex != -1 )
2112         {
2113             // what line (->pageid) is this index in ?
2114             int nLines = mpControlData->mpLayoutData->GetLineCount();
2115             int nLine = -1;
2116             while( ++nLine < nLines )
2117             {
2118                 Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( nLine );
2119                 if( aPair.A() <= nIndex && aPair.B() >= nIndex )
2120                 {
2121                     nRet = nIndex - aPair.A();
2122                     rPageId = (sal_uInt16)mpTabCtrlData->maLayoutLineToPageId[ nLine ];
2123                     break;
2124                 }
2125             }
2126         }
2127     }
2128 
2129     return nRet;
2130 }
2131 
2132 // -----------------------------------------------------------------------
2133 
2134 void TabControl::FillLayoutData() const
2135 {
2136     mpTabCtrlData->maLayoutLineToPageId.clear();
2137     mpTabCtrlData->maLayoutPageIdToLine.clear();
2138     const_cast<TabControl*>(this)->ImplPaint( Rectangle(), true );
2139 }
2140 
2141 // -----------------------------------------------------------------------
2142 
2143 Rectangle TabControl::GetTabPageBounds( sal_uInt16 nPage ) const
2144 {
2145     Rectangle aRet;
2146 
2147     if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
2148         FillLayoutData();
2149 
2150     if( HasLayoutData() )
2151     {
2152         std::hash_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( (int)nPage );
2153         if( it != mpTabCtrlData->maLayoutPageIdToLine.end() )
2154         {
2155             if( it->second >= 0 && it->second < static_cast<int>(mpTabCtrlData->maTabRectangles.size()) )
2156             {
2157                 aRet = mpTabCtrlData->maTabRectangles[ it->second ];
2158                 aRet.Union( const_cast<TabControl*>(this)->ImplGetTabRect( TAB_PAGERECT ) );
2159             }
2160         }
2161     }
2162 
2163     return aRet;
2164 }
2165 
2166 // -----------------------------------------------------------------------
2167 
2168 Rectangle TabControl::GetTabBounds( sal_uInt16 nPageId ) const
2169 {
2170     Rectangle aRet;
2171 
2172     ImplTabItem* pItem = ImplGetItem( nPageId );
2173     if(pItem)
2174         aRet = pItem->maRect;
2175 
2176     return aRet;
2177 }
2178 
2179 // -----------------------------------------------------------------------
2180 
2181 void TabControl::SetItemsOffset( const Point& rOffs )
2182 {
2183     if( mpTabCtrlData )
2184         mpTabCtrlData->maItemsOffset = rOffs;
2185 }
2186 
2187 Point TabControl::GetItemsOffset() const
2188 {
2189     if( mpTabCtrlData )
2190         return mpTabCtrlData->maItemsOffset;
2191     else
2192         return Point();
2193 }
2194 
2195 // -----------------------------------------------------------------------
2196 
2197 Size TabControl::GetOptimalSize(WindowSizeType eType) const
2198 {
2199     switch (eType) {
2200     case WINDOWSIZE_MINIMUM:
2201         return mpTabCtrlData ? mpTabCtrlData->maMinSize : Size();
2202     default:
2203         return Control::GetOptimalSize( eType );
2204     }
2205 }
2206 
2207 // -----------------------------------------------------------------------
2208 
2209 void TabControl::SetMinimumSizePixel( const Size& i_rSize )
2210 {
2211     if( mpTabCtrlData )
2212         mpTabCtrlData->maMinSize = i_rSize;
2213 }
2214 
2215 // -----------------------------------------------------------------------
2216 
2217 
2218