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