xref: /aoo42x/main/sw/source/core/text/txttab.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include "hintids.hxx"
32 #include <editeng/lrspitem.hxx>
33 #ifndef _SVX_TSTPITEM_HXX //autogen
34 #include <editeng/tstpitem.hxx>
35 #endif
36 #include <IDocumentSettingAccess.hxx>
37 #include <frmatr.hxx>
38 #include <SwPortionHandler.hxx>
39 
40 #include "viewopt.hxx"	// SwViewOptions
41 #include "txtcfg.hxx"
42 #include "portab.hxx"
43 #include "inftxt.hxx"
44 #include "itrform2.hxx"
45 #include "txtfrm.hxx"
46 #include <numrule.hxx>
47 // --> OD 2008-06-05 #i89179#
48 #include <porfld.hxx>
49 // <--
50 
51 
52 /*************************************************************************
53  *                    SwLineInfo::GetTabStop()
54  *************************************************************************/
55 
56 //#i24363# tab stops relative to indent
57 /* Return the first tab stop that is > nSearchPos.
58  * If the tab stop is outside the print area, we
59  * return 0 if it is not the first tab stop.*/
60 const SvxTabStop *SwLineInfo::GetTabStop( const SwTwips nSearchPos,
61                                          const SwTwips nRight ) const
62 {
63 	for( MSHORT i = 0; i < pRuler->Count(); ++i )
64 	{
65 		const SvxTabStop &rTabStop = pRuler->operator[](i);
66 		if( rTabStop.GetTabPos() > SwTwips(nRight) )
67             return i ? 0 : &rTabStop;
68 
69         if( rTabStop.GetTabPos() > nSearchPos )
70 			return &rTabStop;
71 	}
72 	return 0;
73 }
74 
75 /*************************************************************************
76  *                    SwLineInfo::NumberOfTabStops()
77  *************************************************************************/
78 
79 sal_uInt16 SwLineInfo::NumberOfTabStops() const
80 {
81     return pRuler->Count();
82 }
83 
84 /*************************************************************************
85  *                      SwTxtFormatter::NewTabPortion()
86  *************************************************************************/
87 SwTabPortion *SwTxtFormatter::NewTabPortion( SwTxtFormatInfo &rInf, bool bAuto ) const
88 {
89 	SwTabPortion *pTabPor = 0;
90 	SwTabPortion  *pLastTab = rInf.GetLastTab();
91     if( pLastTab && ( pLastTab->IsTabCntPortion() || pLastTab->IsTabDecimalPortion() ) )
92 		if( pLastTab->PostFormat( rInf ) )
93 			return 0;
94 
95     xub_Unicode cFill = 0;
96     xub_Unicode cDec = 0;
97 	SvxTabAdjust eAdj;
98 
99 	KSHORT nNewTabPos;
100 	{
101         const bool bRTL = pFrm->IsRightToLeft();
102         // #i24363# tab stops relative to indent
103         // nTabLeft: The absolute value, the tab stops are relative to: Tabs origin.
104         //
105         // --> OD 2008-07-01 #i91133#
106         const bool bTabsRelativeToIndent =
107             pFrm->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT);
108         const SwTwips nTabLeft = bRTL
109                                  ? pFrm->Frm().Right() -
110                                    ( bTabsRelativeToIndent ? GetTabLeft() : 0 )
111                                  : pFrm->Frm().Left() +
112                                    ( bTabsRelativeToIndent ? GetTabLeft() : 0 );
113         // <--
114 
115         //
116         // nLinePos: The absolute position, where we started the line formatting.
117         //
118         SwTwips nLinePos = GetLeftMargin();
119         if ( bRTL )
120         {
121             Point aPoint( nLinePos, 0 );
122             pFrm->SwitchLTRtoRTL( aPoint );
123             nLinePos = aPoint.X();
124         }
125 
126         //
127         // nTabPos: The current position, relative to the line start.
128         //
129         SwTwips nTabPos = rInf.GetLastTab() ? rInf.GetLastTab()->GetTabPos() : 0;
130         if( nTabPos < rInf.X() )
131         {
132             nTabPos = rInf.X();
133         }
134 
135         //
136         // nCurrentAbsPos: The current position in absolute coordinates.
137         //
138         const SwTwips nCurrentAbsPos = bRTL ?
139                                        nLinePos - nTabPos :
140                                        nLinePos + nTabPos;
141 
142        //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
143         SwTwips nMyRight;
144         if ( pFrm->IsVertLR() )
145            nMyRight = Left();
146         else
147            nMyRight = Right();
148 
149         if ( pFrm->IsVertical() )
150         {
151             Point aRightTop( nMyRight, pFrm->Frm().Top() );
152             pFrm->SwitchHorizontalToVertical( aRightTop );
153             nMyRight = aRightTop.Y();
154         }
155 
156 		SwTwips nNextPos;
157 
158         // #i24363# tab stops relative to indent
159         // nSearchPos: The current position relative to the tabs origin.
160         //
161         const SwTwips nSearchPos = bRTL ?
162                                    nTabLeft - nCurrentAbsPos :
163                                    nCurrentAbsPos - nTabLeft;
164 
165         //
166         // First, we examine the tab stops set at the paragraph style or
167         // any hard set tab stops:
168         // Note: If there are no user defined tab stops, there is always a
169         // default tab stop.
170         //
171 		const SvxTabStop* pTabStop =
172             aLineInf.GetTabStop( nSearchPos, nMyRight );
173 		if( pTabStop )
174 		{
175 			cFill = ' ' != pTabStop->GetFill() ? pTabStop->GetFill() : 0;
176 			cDec = pTabStop->GetDecimal();
177 			eAdj = pTabStop->GetAdjustment();
178             nNextPos = pTabStop->GetTabPos();
179             if(!bTabsRelativeToIndent && eAdj == SVX_TAB_ADJUST_DEFAULT && nSearchPos < 0)
180             {
181                 //calculate default tab position of default tabs in negative indent
182                 nNextPos = ( nSearchPos / nNextPos ) * nNextPos;
183             }
184 		}
185 		else
186 		{
187 			KSHORT nDefTabDist = aLineInf.GetDefTabStop();
188 			if( KSHRT_MAX == nDefTabDist )
189 			{
190 				const SvxTabStopItem& rTab =
191 					(const SvxTabStopItem &)pFrm->GetAttrSet()->
192 					GetPool()->GetDefaultItem( RES_PARATR_TABSTOP );
193 				if( rTab.Count() )
194 					nDefTabDist = (KSHORT)rTab.GetStart()->GetTabPos();
195 				else
196 					nDefTabDist = SVX_TAB_DEFDIST;
197 				aLineInf.SetDefTabStop( nDefTabDist );
198 			}
199             SwTwips nCount = nSearchPos;
200 
201 			//Minimum tab stop width is 1
202 			if (nDefTabDist <= 0)
203 			    nDefTabDist = 1;
204 
205 			nCount /= nDefTabDist;
206             nNextPos = nCount < 0 || (!nCount && nSearchPos <= 0)? nCount * nDefTabDist :( nCount + 1 ) * nDefTabDist ;
207             // --> FME 2004-09-21 #117919 Minimum tab stop width is 1 or 51 twips:
208             const SwTwips nMinimumTabWidth = pFrm->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) ? 0 : 50;
209             // <--
210             if( (  bRTL && nTabLeft - nNextPos >= nCurrentAbsPos - nMinimumTabWidth ) ||
211                  ( !bRTL && nNextPos + nTabLeft <= nCurrentAbsPos + nMinimumTabWidth  ) )
212             {
213                 nNextPos += nDefTabDist;
214             }
215 			cFill = 0;
216 			eAdj = SVX_TAB_ADJUST_LEFT;
217 		}
218 
219         // --> OD #i115705# - correction and refactoring:
220         // overrule determined next tab stop position in order to apply
221         // a tab stop at the left margin under the following conditions:
222         // - the new tab portion is inside the hanging indent
223         // - a tab stop at the left margin is allowed
224         // - the determined next tab stop is a default tab stop position OR
225         //   the determined next tab stop is beyond the left margin
226         {
227             long nLeftMarginTabPos = 0;
228             {
229                 if ( !bTabsRelativeToIndent )
230                 {
231                     if ( bRTL )
232                     {
233                         Point aPoint( Left(), 0 );
234                         pFrm->SwitchLTRtoRTL( aPoint );
235                         nLeftMarginTabPos = pFrm->Frm().Right() - aPoint.X();
236                     }
237                     else
238                     {
239                         nLeftMarginTabPos = Left() - pFrm->Frm().Left();
240                     }
241                 }
242                 if( pCurr->HasForcedLeftMargin() )
243                 {
244                     SwLinePortion* pPor = pCurr->GetPortion();
245                     while( pPor && !pPor->IsFlyPortion() )
246                     {
247                         pPor = pPor->GetPortion();
248                     }
249                     if ( pPor )
250                     {
251                         nLeftMarginTabPos += pPor->Width();
252                     }
253                 }
254             }
255             const bool bNewTabPortionInsideHangingIndent =
256                         bRTL ? nCurrentAbsPos > nTabLeft - nLeftMarginTabPos
257                              : nCurrentAbsPos < nTabLeft + nLeftMarginTabPos;
258             if ( bNewTabPortionInsideHangingIndent )
259             {
260                 // If the paragraph is not inside a list having a list tab stop following
261                 // the list label or no further tab stop found in such a paragraph or
262                 // the next tab stop position does not equal the list tab stop,
263                 // a tab stop at the left margin can be applied. If this condition is
264                 // not hold, it is overruled by compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST.
265                 const bool bTabAtLeftMarginAllowed =
266                     ( !aLineInf.IsListTabStopIncluded() ||
267                       !pTabStop ||
268                       nNextPos != aLineInf.GetListTabStopPosition() ) ||
269                     // compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST:
270                     pFrm->GetTxtNode()->getIDocumentSettingAccess()->
271                         get(IDocumentSettingAccess::TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST);
272                 if ( bTabAtLeftMarginAllowed )
273                 {
274                     if ( !pTabStop || eAdj == SVX_TAB_ADJUST_DEFAULT ||
275                          ( nNextPos > nLeftMarginTabPos ) )
276                     {
277                         eAdj = SVX_TAB_ADJUST_DEFAULT;
278                         cFill = 0;
279                         nNextPos = nLeftMarginTabPos;
280                     }
281                 }
282             }
283         }
284         // <--
285 
286         nNextPos += bRTL ? nLinePos - nTabLeft : nTabLeft - nLinePos;
287 		ASSERT( nNextPos >= 0, "GetTabStop: Don't go back!" );
288 		nNewTabPos = KSHORT(nNextPos);
289 	}
290 
291     if ( bAuto )
292     {
293         if ( SVX_TAB_ADJUST_DECIMAL == eAdj &&
294              // --> FME 2005-12-19 #127428#
295              1 == aLineInf.NumberOfTabStops() )
296              // <--
297             pTabPor = new SwAutoTabDecimalPortion( nNewTabPos, cDec, cFill );
298     }
299     else
300     {
301         switch( eAdj )
302         {
303 	        case SVX_TAB_ADJUST_RIGHT :
304    		    {
305     		    pTabPor = new SwTabRightPortion( nNewTabPos, cFill );
306 		        break;
307 	        }
308 	        case SVX_TAB_ADJUST_CENTER :
309 	        {
310        			pTabPor = new SwTabCenterPortion( nNewTabPos, cFill );
311 		        break;
312 	        }
313 	        case SVX_TAB_ADJUST_DECIMAL :
314 	        {
315        			pTabPor = new SwTabDecimalPortion( nNewTabPos, cDec, cFill );
316 		        break;
317 	        }
318 	        default:
319 	        {
320        			ASSERT( SVX_TAB_ADJUST_LEFT == eAdj || SVX_TAB_ADJUST_DEFAULT == eAdj,
321 				        "+SwTxtFormatter::NewTabPortion: unknown adjustment" );
322 		        pTabPor = new SwTabLeftPortion( nNewTabPos, cFill );
323 		        break;
324 	        }
325         }
326     }
327 
328 	// Vorhandensein von Tabulatoren anzeigen ... ist nicht mehr noetig
329 	// pCurr->SetTabulation();
330 	// Aus Sicherheitsgruenden lassen wir uns die Daten errechnen
331 	// pTabPor->Height( pLast->Height() );
332 	// pTabPor->SetAscent( pLast->GetAscent() );
333 	return pTabPor;
334 }
335 
336 /*************************************************************************
337  *                SwTabPortion::SwTabPortion()
338  *************************************************************************/
339 
340 // Die Basisklasse wird erstmal ohne alles initialisiert.
341 
342 
343 SwTabPortion::SwTabPortion( const KSHORT nTabPosition, const xub_Unicode cFillChar )
344     : SwFixPortion( 0, 0 ), nTabPos(nTabPosition), cFill(cFillChar)
345 {
346 	nLineLength = 1;
347 #ifdef DBG_UTIL
348 	if( IsFilled() )
349 	{
350 		ASSERT( ' ' != cFill, "SwTabPortion::CTOR: blanks ?!" );
351 	}
352 #endif
353 	SetWhichPor( POR_TAB );
354 }
355 
356 /*************************************************************************
357  *                 virtual SwTabPortion::Format()
358  *************************************************************************/
359 
360 
361 
362 sal_Bool SwTabPortion::Format( SwTxtFormatInfo &rInf )
363 {
364 	SwTabPortion *pLastTab = rInf.GetLastTab();
365 	if( pLastTab == this )
366 		return PostFormat( rInf );
367 	if( pLastTab )
368 		pLastTab->PostFormat( rInf );
369 	return PreFormat( rInf );
370 }
371 
372 /*************************************************************************
373  *                 virtual SwTabPortion::FormatEOL()
374  *************************************************************************/
375 
376 
377 
378 void SwTabPortion::FormatEOL( SwTxtFormatInfo &rInf )
379 {
380 	if( rInf.GetLastTab() == this && !IsTabLeftPortion() )
381 		PostFormat( rInf );
382 }
383 
384 /*************************************************************************
385  *                    SwTabPortion::PreFormat()
386  *************************************************************************/
387 
388 
389 
390 sal_Bool SwTabPortion::PreFormat( SwTxtFormatInfo &rInf )
391 {
392 	ASSERT( rInf.X() <= GetTabPos(), "SwTabPortion::PreFormat: rush hour" );
393 
394 	// Hier lassen wir uns nieder...
395     Fix( static_cast<sal_uInt16>(rInf.X()) );
396 
397     const bool bTabCompat = rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT);
398 
399     // Die Mindestbreite eines Tabs ist immer mindestens ein Blank
400     // --> FME 2004-11-25 #i37686# In compatibility mode, the minimum width
401     // should be 1, even for non-left tab stops.
402     sal_uInt16 nMinimumTabWidth = 1;
403     // <--
404     if ( !bTabCompat )
405     {
406         // --> OD 2008-06-05 #i89179#
407         // tab portion representing the list tab of a list label gets the
408         // same font as the corresponding number portion
409         std::auto_ptr< SwFontSave > pSave( 0 );
410         if ( GetLen() == 0 &&
411              rInf.GetLast() && rInf.GetLast()->InNumberGrp() &&
412              static_cast<SwNumberPortion*>(rInf.GetLast())->HasFont() )
413         {
414             const SwFont* pNumberPortionFont =
415                     static_cast<SwNumberPortion*>(rInf.GetLast())->GetFont();
416             pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) );
417         }
418         // <--
419         XubString aTmp( ' ' );
420         SwTxtSizeInfo aInf( rInf, aTmp );
421         nMinimumTabWidth = aInf.GetTxtSize().Width();
422     }
423     PrtWidth( nMinimumTabWidth );
424 
425     // Break tab stop to next line if:
426     // 1. Minmal width does not fit to line anymore.
427     // 2. An underflow event was called for the tab portion.
428 	sal_Bool bFull = ( bTabCompat && rInf.IsUnderFlow() ) ||
429                        rInf.Width() <= rInf.X() + PrtWidth();
430 
431     // #95477# Rotated tab stops get the width of one blank
432     const sal_uInt16 nDir = rInf.GetFont()->GetOrientation( rInf.GetTxtFrm()->IsVertical() );
433 
434     if( ! bFull && 0 == nDir )
435 	{
436 		const MSHORT nWhich = GetWhichPor();
437 		switch( nWhich )
438 		{
439 			case POR_TABRIGHT:
440 			case POR_TABDECIMAL:
441 			case POR_TABCENTER:
442 			{
443 				if( POR_TABDECIMAL == nWhich )
444 					rInf.SetTabDecimal(
445 						((SwTabDecimalPortion*)this)->GetTabDecimal());
446 				rInf.SetLastTab( this );
447 				break;
448 			}
449 			case POR_TABLEFT:
450 			{
451                 PrtWidth( static_cast<sal_uInt16>(GetTabPos() - rInf.X()) );
452                 bFull = rInf.Width() <= rInf.X() + PrtWidth();
453 
454                 // In tabulator compatibility mode, we reset the bFull flag
455                 // if the tabulator is at the end of the paragraph and the
456                 // tab stop position is outside the frame:
457                 if ( bFull && bTabCompat &&
458                      rInf.GetIdx() + GetLen() == rInf.GetTxt().Len() &&
459                      GetTabPos() >= rInf.GetTxtFrm()->Frm().Width() )
460                     bFull = sal_False;
461 
462 				break;
463 			}
464 			default: ASSERT( !this, "SwTabPortion::PreFormat: unknown adjustment" );
465 		}
466 	}
467 
468 	if( bFull )
469 	{
470 		// Wir muessen aufpassen, dass wir nicht endlos schleifen,
471 		// wenn die Breite kleiner ist, als ein Blank ...
472 		if( rInf.GetIdx() == rInf.GetLineStart() &&
473             // --> FME 2005-01-19 #119175# TabStop should be forced to current
474             // line if there is a fly reducing the line width:
475             !rInf.GetFly() )
476             // <--
477 		{
478             PrtWidth( static_cast<sal_uInt16>(rInf.Width() - rInf.X()) );
479 			SetFixWidth( PrtWidth() );
480 		}
481 		else
482 		{
483 			Height( 0 );
484 			Width( 0 );
485 			SetLen( 0 );
486 			SetAscent( 0 );
487 			SetPortion( NULL ); //?????
488 		}
489 		return sal_True;
490 	}
491 	else
492 	{
493 		// Ein Kunstgriff mit Effekt: Die neuen Tabportions verhalten sich nun
494 		// so, wie FlyFrms, die in der Zeile stehen - inklusive Adjustment !
495 		SetFixWidth( PrtWidth() );
496 		return sal_False;
497 	}
498 }
499 
500 /*************************************************************************
501  *                      SwTabPortion::PostFormat()
502  *************************************************************************/
503 
504 
505 
506 sal_Bool SwTabPortion::PostFormat( SwTxtFormatInfo &rInf )
507 {
508 	const KSHORT nRight = Min( GetTabPos(), rInf.Width() );
509 	const SwLinePortion *pPor = GetPortion();
510 
511     KSHORT nPorWidth = 0;
512     while( pPor )
513     {
514    		DBG_LOOP;
515 	    nPorWidth = nPorWidth + pPor->Width();
516 	    pPor = pPor->GetPortion();
517     }
518 
519 	const MSHORT nWhich = GetWhichPor();
520 	ASSERT( POR_TABLEFT != nWhich, "SwTabPortion::PostFormat: already formatted" );
521     const bool bTabCompat = rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT);
522 
523     // --> FME 2005-12-19 #127428# Abandon dec. tab position if line is full:
524     if ( bTabCompat && POR_TABDECIMAL == nWhich )
525     {
526         KSHORT nPrePorWidth = static_cast<const SwTabDecimalPortion*>(this)->GetWidthOfPortionsUpToDecimalPosition();
527 
528         // no value was set => no decimal character was found
529         if ( USHRT_MAX != nPrePorWidth )
530         {
531             if ( nPrePorWidth && nPorWidth - nPrePorWidth > rInf.Width() - nRight )
532             {
533                 nPrePorWidth += nPorWidth - nPrePorWidth - ( rInf.Width() - nRight );
534             }
535 
536             nPorWidth = nPrePorWidth - 1;
537         }
538     }
539     // <--
540 
541     if( POR_TABCENTER == nWhich )
542 	{
543 		// zentrierte Tabs bereiten Probleme:
544 		// Wir muessen den Anteil herausfinden, der noch auf die Zeile passt.
545 		KSHORT nNewWidth = nPorWidth /2;
546 		if( nNewWidth > rInf.Width() - nRight )
547 			nNewWidth = nPorWidth - (rInf.Width() - nRight);
548 		nPorWidth = nNewWidth;
549 	}
550 
551 	const KSHORT nDiffWidth = nRight - Fix();
552 
553 	if( nDiffWidth > nPorWidth )
554 	{
555 		const KSHORT nOldWidth = GetFixWidth();
556 		const KSHORT nAdjDiff = nDiffWidth - nPorWidth;
557 		if( nAdjDiff > GetFixWidth() )
558 			PrtWidth( nAdjDiff );
559 		// Nicht erschrecken: wir muessen rInf weiterschieben.
560 		// Immerhin waren wir als Rechtstab bislang nur ein Blank breit.
561 		// Da wir uns jetzt aufgespannt haben, muss der Differenzbetrag
562 		// auf rInf.X() addiert werden !
563 		rInf.X( rInf.X() + PrtWidth() - nOldWidth );
564 	}
565 	SetFixWidth( PrtWidth() );
566 	// letzte Werte zuruecksetzen
567 	rInf.SetLastTab(0);
568 	if( POR_TABDECIMAL == nWhich )
569 		rInf.SetTabDecimal(0);
570 
571 	return rInf.Width() <= rInf.X();
572 }
573 
574 /*************************************************************************
575  *                virtual SwTabPortion::Paint()
576  *
577  * Ex: LineIter::DrawTab()
578  *************************************************************************/
579 
580 void SwTabPortion::Paint( const SwTxtPaintInfo &rInf ) const
581 {
582 #ifdef DBG_UTIL
583 	// Wir wollen uns die Fixbreite anzeigen
584     if( rInf.OnWin() && OPTDBG( rInf ) &&
585         !rInf.GetOpt().IsPagePreview() && \
586         !rInf.GetOpt().IsReadonly() && \
587         SwViewOption::IsFieldShadings()    )
588 	{
589 		const KSHORT nTmpWidth = PrtWidth();
590 		((SwTabPortion*)this)->PrtWidth( GetFixWidth() );
591 		rInf.DrawViewOpt( *this, POR_TAB );
592 		((SwTabPortion*)this)->PrtWidth( nTmpWidth );
593 	}
594 #endif
595 
596     // --> OD 2008-06-05 #i89179#
597     // tab portion representing the list tab of a list label gets the
598     // same font as the corresponding number portion
599     std::auto_ptr< SwFontSave > pSave( 0 );
600     if ( GetLen() == 0 )
601     {
602         const SwLinePortion* pPrevPortion =
603             const_cast<SwTabPortion*>(this)->FindPrevPortion( rInf.GetParaPortion() );
604         if ( pPrevPortion &&
605              pPrevPortion->InNumberGrp() &&
606              static_cast<const SwNumberPortion*>(pPrevPortion)->HasFont() )
607         {
608             const SwFont* pNumberPortionFont =
609                     static_cast<const SwNumberPortion*>(pPrevPortion)->GetFont();
610             pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) );
611         }
612     }
613     // <--
614 	rInf.DrawBackBrush( *this );
615 
616     // do we have to repaint a post it portion?
617     if( rInf.OnWin() && pPortion && !pPortion->Width() )
618         pPortion->PrePaint( rInf, this );
619 
620     // Darstellung von Sonderzeichen
621 	if( rInf.OnWin() && rInf.GetOpt().IsTab() )
622 	{
623 		// gefuellte Tabs werden grau hinterlegt.
624 		if( IsFilled() )
625 			rInf.DrawViewOpt( *this, POR_TAB );
626 		else
627 			rInf.DrawTab( *this );
628 	}
629 
630 	// 6842: Tabs sollen auf einmal wieder unterstrichen werden.
631 	if( rInf.GetFont()->IsPaintBlank() )
632 	{
633 		// Tabs mit Fuellung
634 		XubString aTxt( ' ' );
635 		const KSHORT nCharWidth = rInf.GetTxtSize( aTxt ).Width();
636 		// robust:
637 		if( nCharWidth )
638 		{
639 			// 6864: immer mit Kerning, auch auf dem Drucker!
640 			KSHORT nChar = Width() / nCharWidth;
641 			rInf.DrawText( aTxt.Fill( nChar, ' ' ), *this, 0, nChar, sal_True );
642 		}
643 	}
644 
645 	// Ausgabe von Fuellzeichen
646 	if( IsFilled() )
647 	{
648 		// Tabs mit Fuellung
649 		XubString aTxt( cFill );
650 		const KSHORT nCharWidth = rInf.GetTxtSize( aTxt ).Width();
651 #if OSL_DEBUG_LEVEL > 1
652 		ASSERT( nCharWidth, "!SwTabPortion::Paint: sophisticated tabchar" );
653 #endif
654 		// robust:
655 		if( nCharWidth )
656 		{
657 			// 6864: immer mit Kerning, auch auf dem Drucker!
658 			KSHORT nChar = Width() / nCharWidth;
659 			if ( cFill == '_' )
660 				++nChar; // damit keine Luecken entstehen (Bug 13430)
661 			rInf.DrawText( aTxt.Fill( nChar, cFill ), *this, 0, nChar, sal_True );
662 		}
663 	}
664 }
665 
666 /*************************************************************************
667  *                virtual SwAutoTabDecimalPortion::Paint()
668  *************************************************************************/
669 
670 void SwAutoTabDecimalPortion::Paint( const SwTxtPaintInfo & ) const
671 {
672 }
673 
674 /*************************************************************************
675  *              virtual SwTabPortion::HandlePortion()
676  *************************************************************************/
677 
678 void SwTabPortion::HandlePortion( SwPortionHandler& rPH ) const
679 {
680     rPH.Text( GetLen(), GetWhichPor() );
681 }
682 
683