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