Update ooo320-m1
[ooovba.git] / sw / source / core / text / txttab.cxx
blobb299cae9701d39774cba23834b59a79806f2481d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: txttab.cxx,v $
10 * $Revision: 1.33 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
34 #include "hintids.hxx"
35 #include <svx/lrspitem.hxx>
36 #ifndef _SVX_TSTPITEM_HXX //autogen
37 #include <svx/tstpitem.hxx>
38 #endif
39 #include <IDocumentSettingAccess.hxx>
40 #include <frmatr.hxx>
41 #include <SwPortionHandler.hxx>
43 #include "viewopt.hxx" // SwViewOptions
44 #include "txtcfg.hxx"
45 #include "portab.hxx"
46 #include "inftxt.hxx"
47 #include "itrform2.hxx"
48 #include "txtfrm.hxx"
49 #include <numrule.hxx>
50 // --> OD 2008-06-05 #i89179#
51 #include <porfld.hxx>
52 // <--
55 /*************************************************************************
56 * SwLineInfo::GetTabStop()
57 *************************************************************************/
59 //#i24363# tab stops relative to indent
60 /* Return the first tab stop that is > nSearchPos.
61 * If the tab stop is outside the print area, we
62 * return 0 if it is not the first tab stop.*/
63 const SvxTabStop *SwLineInfo::GetTabStop( const SwTwips nSearchPos,
64 const SwTwips nRight ) const
66 for( MSHORT i = 0; i < pRuler->Count(); ++i )
68 const SvxTabStop &rTabStop = pRuler->operator[](i);
69 if( rTabStop.GetTabPos() > SwTwips(nRight) )
70 return i ? 0 : &rTabStop;
72 if( rTabStop.GetTabPos() > nSearchPos )
73 return &rTabStop;
75 return 0;
78 /*************************************************************************
79 * SwLineInfo::NumberOfTabStops()
80 *************************************************************************/
82 USHORT SwLineInfo::NumberOfTabStops() const
84 return pRuler->Count();
87 /*************************************************************************
88 * SwTxtFormatter::NewTabPortion()
89 *************************************************************************/
91 SwTabPortion *SwTxtFormatter::NewTabPortion( SwTxtFormatInfo &rInf, bool bAuto ) const
93 SwTabPortion *pTabPor = 0;
94 SwTabPortion *pLastTab = rInf.GetLastTab();
95 if( pLastTab && ( pLastTab->IsTabCntPortion() || pLastTab->IsTabDecimalPortion() ) )
96 if( pLastTab->PostFormat( rInf ) )
97 return 0;
99 xub_Unicode cFill = 0;
100 xub_Unicode cDec = 0;
101 SvxTabAdjust eAdj;
103 KSHORT nNewTabPos;
105 const bool bRTL = pFrm->IsRightToLeft();
106 // #i24363# tab stops relative to indent
107 // nTabLeft: The absolute value, the tab stops are relative to: Tabs origin.
109 // --> OD 2008-07-01 #i91133#
110 const bool bTabsRelativeToIndent =
111 pFrm->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT);
112 const SwTwips nTabLeft = bRTL
113 ? pFrm->Frm().Right() -
114 ( bTabsRelativeToIndent ? GetTabLeft() : 0 )
115 : pFrm->Frm().Left() +
116 ( bTabsRelativeToIndent ? GetTabLeft() : 0 );
117 // <--
120 // nLinePos: The absolute position, where we started the line formatting.
122 SwTwips nLinePos = GetLeftMargin();
123 if ( bRTL )
125 Point aPoint( nLinePos, 0 );
126 pFrm->SwitchLTRtoRTL( aPoint );
127 nLinePos = aPoint.X();
131 // nTabPos: The current position, relative to the line start.
133 SwTwips nTabPos = rInf.GetLastTab() ? rInf.GetLastTab()->GetTabPos() : 0;
134 if( nTabPos < rInf.X() )
136 nTabPos = rInf.X();
140 // nCurrentAbsPos: The current position in absolute coordinates.
142 const SwTwips nCurrentAbsPos = bRTL ?
143 nLinePos - nTabPos :
144 nLinePos + nTabPos;
146 SwTwips nMyRight = Right();
148 if ( pFrm->IsVertical() )
150 Point aRightTop( nMyRight, pFrm->Frm().Top() );
151 pFrm->SwitchHorizontalToVertical( aRightTop );
152 nMyRight = aRightTop.Y();
155 SwTwips nNextPos;
157 // #i24363# tab stops relative to indent
158 // nSearchPos: The current position relative to the tabs origin.
160 const SwTwips nSearchPos = bRTL ?
161 nTabLeft - nCurrentAbsPos :
162 nCurrentAbsPos - nTabLeft;
165 // First, we examine the tab stops set at the paragraph style or
166 // any hard set tab stops:
167 // Note: If there are no user defined tab stops, there is always a
168 // default tab stop.
170 const SvxTabStop* pTabStop =
171 aLineInf.GetTabStop( nSearchPos, nMyRight );
172 if( pTabStop )
174 cFill = ' ' != pTabStop->GetFill() ? pTabStop->GetFill() : 0;
175 cDec = pTabStop->GetDecimal();
176 eAdj = pTabStop->GetAdjustment();
177 nNextPos = pTabStop->GetTabPos();
179 else
181 KSHORT nDefTabDist = aLineInf.GetDefTabStop();
182 if( KSHRT_MAX == nDefTabDist )
184 const SvxTabStopItem& rTab =
185 (const SvxTabStopItem &)pFrm->GetAttrSet()->
186 GetPool()->GetDefaultItem( RES_PARATR_TABSTOP );
187 if( rTab.Count() )
188 nDefTabDist = (KSHORT)rTab.GetStart()->GetTabPos();
189 else
190 nDefTabDist = SVX_TAB_DEFDIST;
191 aLineInf.SetDefTabStop( nDefTabDist );
193 SwTwips nCount = nSearchPos;
195 // Bei negativen Werten rundet "/" auf, "%" liefert negative Reste,
196 // bei positiven Werten rundet "/" ab, "%" liefert positvie Reste!
197 if ( nCount < 0 )
198 nCount = 0;
200 nCount /= nDefTabDist;
201 nNextPos = ( nCount + 1 ) * nDefTabDist ;
202 // --> FME 2004-09-21 #117919 Minimum tab stop width is 1 or 51 twips:
203 const SwTwips nMinimumTabWidth = pFrm->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) ? 0 : 50;
204 // <--
205 if( ( bRTL && nTabLeft - nNextPos >= nCurrentAbsPos - nMinimumTabWidth ) ||
206 ( !bRTL && nNextPos + nTabLeft <= nCurrentAbsPos + nMinimumTabWidth ) )
208 nNextPos += nDefTabDist;
210 cFill = 0;
211 eAdj = SVX_TAB_ADJUST_LEFT;
213 // --> OD 2008-02-07 #newlistlevelattrs#
214 long nForced = 0;
215 if ( !bTabsRelativeToIndent )
217 if ( bRTL )
219 Point aPoint( Left(), 0 );
220 pFrm->SwitchLTRtoRTL( aPoint );
221 nForced = pFrm->Frm().Right() - aPoint.X();
223 else
225 nForced = Left() - pFrm->Frm().Left();
228 if( pCurr->HasForcedLeftMargin() )
230 SwLinePortion* pPor = pCurr->GetPortion();
231 while( pPor && !pPor->IsFlyPortion() )
232 pPor = pPor->GetPortion();
233 if( pPor )
234 nForced += pPor->Width();
237 // <--
238 // --> OD 2009-04-03 #i100732#
239 // correction of condition, when a tab stop at the left margin can
240 // be applied:
241 // If the paragraph is not inside a list having a list tab stop following
242 // the list label or no further tab stop found in such a paragraph or
243 // the next tab stop position does not equal the list tab stop,
244 // a tab stop at the left margin can be applied. If this condition is
245 // not hold, it is overruled by compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST.
246 const bool bTabAtLeftMargin =
247 ( !aLineInf.IsListTabStopIncluded() ||
248 !pTabStop ||
249 nNextPos != aLineInf.GetListTabStopPosition() ) ||
250 // compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST:
251 pFrm->GetTxtNode()->getIDocumentSettingAccess()->
252 get(IDocumentSettingAccess::TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST);
253 if ( bTabAtLeftMargin &&
254 // <--
255 ( ( bRTL && nCurrentAbsPos > nTabLeft - nForced ) ||
256 ( !bRTL && nCurrentAbsPos < nTabLeft + nForced ) ) &&
257 // --> OD 2009-07-21 #i103685#
258 // adjust condition:
259 // - back to pre OOo 3.0 condition, if tab stops are relative to indent
260 // - further checks needed, if tab stops are not relative to indent
261 ( nNextPos > 0 &&
262 ( bTabsRelativeToIndent ||
263 ( !pTabStop || nNextPos > nForced ) ) ) )
264 // <--
266 eAdj = SVX_TAB_ADJUST_DEFAULT;
267 cFill = 0;
268 nNextPos = nForced;
270 nNextPos += bRTL ? nLinePos - nTabLeft : nTabLeft - nLinePos;
271 ASSERT( nNextPos >= 0, "GetTabStop: Don't go back!" );
272 nNewTabPos = KSHORT(nNextPos);
275 if ( bAuto )
277 if ( SVX_TAB_ADJUST_DECIMAL == eAdj &&
278 // --> FME 2005-12-19 #127428#
279 1 == aLineInf.NumberOfTabStops() )
280 // <--
281 pTabPor = new SwAutoTabDecimalPortion( nNewTabPos, cDec, cFill );
283 else
285 switch( eAdj )
287 case SVX_TAB_ADJUST_RIGHT :
289 pTabPor = new SwTabRightPortion( nNewTabPos, cFill );
290 break;
292 case SVX_TAB_ADJUST_CENTER :
294 pTabPor = new SwTabCenterPortion( nNewTabPos, cFill );
295 break;
297 case SVX_TAB_ADJUST_DECIMAL :
299 pTabPor = new SwTabDecimalPortion( nNewTabPos, cDec, cFill );
300 break;
302 default:
304 ASSERT( SVX_TAB_ADJUST_LEFT == eAdj || SVX_TAB_ADJUST_DEFAULT == eAdj,
305 "+SwTxtFormatter::NewTabPortion: unknown adjustment" );
306 pTabPor = new SwTabLeftPortion( nNewTabPos, cFill );
307 break;
312 // Vorhandensein von Tabulatoren anzeigen ... ist nicht mehr noetig
313 // pCurr->SetTabulation();
314 // Aus Sicherheitsgruenden lassen wir uns die Daten errechnen
315 // pTabPor->Height( pLast->Height() );
316 // pTabPor->SetAscent( pLast->GetAscent() );
317 return pTabPor;
320 /*************************************************************************
321 * SwTabPortion::SwTabPortion()
322 *************************************************************************/
324 // Die Basisklasse wird erstmal ohne alles initialisiert.
327 SwTabPortion::SwTabPortion( const KSHORT nTabPosition, const xub_Unicode cFillChar )
328 : SwFixPortion( 0, 0 ), nTabPos(nTabPosition), cFill(cFillChar)
330 nLineLength = 1;
331 #ifndef PRODUCT
332 if( IsFilled() )
334 ASSERT( ' ' != cFill, "SwTabPortion::CTOR: blanks ?!" );
336 #endif
337 SetWhichPor( POR_TAB );
340 /*************************************************************************
341 * virtual SwTabPortion::Format()
342 *************************************************************************/
346 sal_Bool SwTabPortion::Format( SwTxtFormatInfo &rInf )
348 SwTabPortion *pLastTab = rInf.GetLastTab();
349 if( pLastTab == this )
350 return PostFormat( rInf );
351 if( pLastTab )
352 pLastTab->PostFormat( rInf );
353 return PreFormat( rInf );
356 /*************************************************************************
357 * virtual SwTabPortion::FormatEOL()
358 *************************************************************************/
362 void SwTabPortion::FormatEOL( SwTxtFormatInfo &rInf )
364 if( rInf.GetLastTab() == this && !IsTabLeftPortion() )
365 PostFormat( rInf );
368 /*************************************************************************
369 * SwTabPortion::PreFormat()
370 *************************************************************************/
374 sal_Bool SwTabPortion::PreFormat( SwTxtFormatInfo &rInf )
376 ASSERT( rInf.X() <= GetTabPos(), "SwTabPortion::PreFormat: rush hour" );
378 // Hier lassen wir uns nieder...
379 Fix( static_cast<USHORT>(rInf.X()) );
381 const bool bTabCompat = rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT);
383 // Die Mindestbreite eines Tabs ist immer mindestens ein Blank
384 // --> FME 2004-11-25 #i37686# In compatibility mode, the minimum width
385 // should be 1, even for non-left tab stops.
386 USHORT nMinimumTabWidth = 1;
387 // <--
388 if ( !bTabCompat )
390 // --> OD 2008-06-05 #i89179#
391 // tab portion representing the list tab of a list label gets the
392 // same font as the corresponding number portion
393 std::auto_ptr< SwFontSave > pSave( 0 );
394 if ( GetLen() == 0 &&
395 rInf.GetLast() && rInf.GetLast()->InNumberGrp() &&
396 static_cast<SwNumberPortion*>(rInf.GetLast())->HasFont() )
398 const SwFont* pNumberPortionFont =
399 static_cast<SwNumberPortion*>(rInf.GetLast())->GetFont();
400 pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) );
402 // <--
403 XubString aTmp( ' ' );
404 SwTxtSizeInfo aInf( rInf, aTmp );
405 nMinimumTabWidth = aInf.GetTxtSize().Width();
407 PrtWidth( nMinimumTabWidth );
409 // Break tab stop to next line if:
410 // 1. Minmal width does not fit to line anymore.
411 // 2. An underflow event was called for the tab portion.
412 sal_Bool bFull = ( bTabCompat && rInf.IsUnderFlow() ) ||
413 rInf.Width() <= rInf.X() + PrtWidth();
415 // #95477# Rotated tab stops get the width of one blank
416 const USHORT nDir = rInf.GetFont()->GetOrientation( rInf.GetTxtFrm()->IsVertical() );
418 if( ! bFull && 0 == nDir )
420 const MSHORT nWhich = GetWhichPor();
421 switch( nWhich )
423 case POR_TABRIGHT:
424 case POR_TABDECIMAL:
425 case POR_TABCENTER:
427 if( POR_TABDECIMAL == nWhich )
428 rInf.SetTabDecimal(
429 ((SwTabDecimalPortion*)this)->GetTabDecimal());
430 rInf.SetLastTab( this );
431 break;
433 case POR_TABLEFT:
435 PrtWidth( static_cast<USHORT>(GetTabPos() - rInf.X()) );
436 bFull = rInf.Width() <= rInf.X() + PrtWidth();
438 // In tabulator compatibility mode, we reset the bFull flag
439 // if the tabulator is at the end of the paragraph and the
440 // tab stop position is outside the frame:
441 if ( bFull && bTabCompat &&
442 rInf.GetIdx() + GetLen() == rInf.GetTxt().Len() &&
443 GetTabPos() >= rInf.GetTxtFrm()->Frm().Width() )
444 bFull = sal_False;
446 break;
448 default: ASSERT( !this, "SwTabPortion::PreFormat: unknown adjustment" );
452 if( bFull )
454 // Wir muessen aufpassen, dass wir nicht endlos schleifen,
455 // wenn die Breite kleiner ist, als ein Blank ...
456 if( rInf.GetIdx() == rInf.GetLineStart() &&
457 // --> FME 2005-01-19 #119175# TabStop should be forced to current
458 // line if there is a fly reducing the line width:
459 !rInf.GetFly() )
460 // <--
462 PrtWidth( static_cast<USHORT>(rInf.Width() - rInf.X()) );
463 SetFixWidth( PrtWidth() );
465 else
467 Height( 0 );
468 Width( 0 );
469 SetLen( 0 );
470 SetAscent( 0 );
471 SetPortion( NULL ); //?????
473 return sal_True;
475 else
477 // Ein Kunstgriff mit Effekt: Die neuen Tabportions verhalten sich nun
478 // so, wie FlyFrms, die in der Zeile stehen - inklusive Adjustment !
479 SetFixWidth( PrtWidth() );
480 return sal_False;
484 /*************************************************************************
485 * SwTabPortion::PostFormat()
486 *************************************************************************/
490 sal_Bool SwTabPortion::PostFormat( SwTxtFormatInfo &rInf )
492 const KSHORT nRight = Min( GetTabPos(), rInf.Width() );
493 const SwLinePortion *pPor = GetPortion();
495 KSHORT nPorWidth = 0;
496 while( pPor )
498 DBG_LOOP;
499 nPorWidth = nPorWidth + pPor->Width();
500 pPor = pPor->GetPortion();
503 const MSHORT nWhich = GetWhichPor();
504 ASSERT( POR_TABLEFT != nWhich, "SwTabPortion::PostFormat: already formatted" );
505 const bool bTabCompat = rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT);
507 // --> FME 2005-12-19 #127428# Abandon dec. tab position if line is full:
508 if ( bTabCompat && POR_TABDECIMAL == nWhich )
510 KSHORT nPrePorWidth = static_cast<const SwTabDecimalPortion*>(this)->GetWidthOfPortionsUpToDecimalPosition();
512 // no value was set => no decimal character was found
513 if ( USHRT_MAX != nPrePorWidth )
515 if ( nPrePorWidth && nPorWidth - nPrePorWidth > rInf.Width() - nRight )
517 nPrePorWidth += nPorWidth - nPrePorWidth - ( rInf.Width() - nRight );
520 nPorWidth = nPrePorWidth - 1;
523 // <--
525 if( POR_TABCENTER == nWhich )
527 // zentrierte Tabs bereiten Probleme:
528 // Wir muessen den Anteil herausfinden, der noch auf die Zeile passt.
529 KSHORT nNewWidth = nPorWidth /2;
530 if( nNewWidth > rInf.Width() - nRight )
531 nNewWidth = nPorWidth - (rInf.Width() - nRight);
532 nPorWidth = nNewWidth;
535 const KSHORT nDiffWidth = nRight - Fix();
537 if( nDiffWidth > nPorWidth )
539 const KSHORT nOldWidth = GetFixWidth();
540 const KSHORT nAdjDiff = nDiffWidth - nPorWidth;
541 if( nAdjDiff > GetFixWidth() )
542 PrtWidth( nAdjDiff );
543 // Nicht erschrecken: wir muessen rInf weiterschieben.
544 // Immerhin waren wir als Rechtstab bislang nur ein Blank breit.
545 // Da wir uns jetzt aufgespannt haben, muss der Differenzbetrag
546 // auf rInf.X() addiert werden !
547 rInf.X( rInf.X() + PrtWidth() - nOldWidth );
549 SetFixWidth( PrtWidth() );
550 // letzte Werte zuruecksetzen
551 rInf.SetLastTab(0);
552 if( POR_TABDECIMAL == nWhich )
553 rInf.SetTabDecimal(0);
555 return rInf.Width() <= rInf.X();
558 /*************************************************************************
559 * virtual SwTabPortion::Paint()
561 * Ex: LineIter::DrawTab()
562 *************************************************************************/
564 void SwTabPortion::Paint( const SwTxtPaintInfo &rInf ) const
566 #ifndef PRODUCT
567 // Wir wollen uns die Fixbreite anzeigen
568 if( rInf.OnWin() && OPTDBG( rInf ) &&
569 !rInf.GetOpt().IsPagePreview() && \
570 !rInf.GetOpt().IsReadonly() && \
571 SwViewOption::IsFieldShadings() )
573 const KSHORT nTmpWidth = PrtWidth();
574 ((SwTabPortion*)this)->PrtWidth( GetFixWidth() );
575 rInf.DrawViewOpt( *this, POR_TAB );
576 ((SwTabPortion*)this)->PrtWidth( nTmpWidth );
578 #endif
580 // --> OD 2008-06-05 #i89179#
581 // tab portion representing the list tab of a list label gets the
582 // same font as the corresponding number portion
583 std::auto_ptr< SwFontSave > pSave( 0 );
584 if ( GetLen() == 0 )
586 const SwLinePortion* pPrevPortion =
587 const_cast<SwTabPortion*>(this)->FindPrevPortion( rInf.GetParaPortion() );
588 if ( pPrevPortion &&
589 pPrevPortion->InNumberGrp() &&
590 static_cast<const SwNumberPortion*>(pPrevPortion)->HasFont() )
592 const SwFont* pNumberPortionFont =
593 static_cast<const SwNumberPortion*>(pPrevPortion)->GetFont();
594 pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) );
597 // <--
598 rInf.DrawBackBrush( *this );
600 // do we have to repaint a post it portion?
601 if( rInf.OnWin() && pPortion && !pPortion->Width() )
602 pPortion->PrePaint( rInf, this );
604 // Darstellung von Sonderzeichen
605 if( rInf.OnWin() && rInf.GetOpt().IsTab() )
607 // gefuellte Tabs werden grau hinterlegt.
608 if( IsFilled() )
609 rInf.DrawViewOpt( *this, POR_TAB );
610 else
611 rInf.DrawTab( *this );
614 // 6842: Tabs sollen auf einmal wieder unterstrichen werden.
615 if( rInf.GetFont()->IsPaintBlank() )
617 // Tabs mit Fuellung
618 XubString aTxt( ' ' );
619 const KSHORT nCharWidth = rInf.GetTxtSize( aTxt ).Width();
620 // robust:
621 if( nCharWidth )
623 // 6864: immer mit Kerning, auch auf dem Drucker!
624 KSHORT nChar = Width() / nCharWidth;
625 rInf.DrawText( aTxt.Fill( nChar, ' ' ), *this, 0, nChar, sal_True );
629 // Ausgabe von Fuellzeichen
630 if( IsFilled() )
632 // Tabs mit Fuellung
633 XubString aTxt( cFill );
634 const KSHORT nCharWidth = rInf.GetTxtSize( aTxt ).Width();
635 #if OSL_DEBUG_LEVEL > 1
636 ASSERT( nCharWidth, "!SwTabPortion::Paint: sophisticated tabchar" );
637 #endif
638 // robust:
639 if( nCharWidth )
641 // 6864: immer mit Kerning, auch auf dem Drucker!
642 KSHORT nChar = Width() / nCharWidth;
643 if ( cFill == '_' )
644 ++nChar; // damit keine Luecken entstehen (Bug 13430)
645 rInf.DrawText( aTxt.Fill( nChar, cFill ), *this, 0, nChar, sal_True );
650 /*************************************************************************
651 * virtual SwAutoTabDecimalPortion::Paint()
652 *************************************************************************/
654 void SwAutoTabDecimalPortion::Paint( const SwTxtPaintInfo & ) const
658 /*************************************************************************
659 * virtual SwTabPortion::HandlePortion()
660 *************************************************************************/
662 void SwTabPortion::HandlePortion( SwPortionHandler& rPH ) const
664 rPH.Text( GetLen(), GetWhichPor() );