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