ITEM: Refactor ItemType
[LibreOffice.git] / sw / source / core / text / txttab.cxx
blob14d8b9072693bac799d38aa814b76c9db43edf0e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <hintids.hxx>
21 #include <comphelper/string.hxx>
22 #include <editeng/tstpitem.hxx>
23 #include <rtl/ustrbuf.hxx>
24 #include <IDocumentSettingAccess.hxx>
25 #include <doc.hxx>
26 #include <SwPortionHandler.hxx>
28 #include <viewopt.hxx>
29 #include "portab.hxx"
30 #include "inftxt.hxx"
31 #include "itrform2.hxx"
32 #include <txtfrm.hxx>
33 #include "porfld.hxx"
34 #include <memory>
36 /**
37 * #i24363# tab stops relative to indent
39 * Return the first tab stop that is > nSearchPos.
40 * If the tab stop is outside the print area, we
41 * return 0 if it is not the first tab stop.
43 const SvxTabStop* SwLineInfo::GetTabStop(const SwTwips nSearchPos, SwTwips& nRight) const
45 for( sal_uInt16 i = 0; i < m_oRuler->Count(); ++i )
47 const SvxTabStop &rTabStop = m_oRuler->operator[](i);
48 if (nRight && rTabStop.GetTabPos() > nRight)
50 // Consider the first tabstop to always be in-bounds.
51 if (!i)
52 nRight = rTabStop.GetTabPos();
53 return i ? nullptr : &rTabStop;
55 if( rTabStop.GetTabPos() > nSearchPos )
57 if (!i && !nRight)
58 nRight = rTabStop.GetTabPos();
59 return &rTabStop;
62 return nullptr;
65 sal_uInt16 SwLineInfo::NumberOfTabStops() const
67 return m_oRuler->Count();
70 SwTabPortion *SwTextFormatter::NewTabPortion( SwTextFormatInfo &rInf, bool bAuto ) const
72 IDocumentSettingAccess const& rIDSA(rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess());
73 const bool bTabOverMargin = rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN);
74 const bool bTabOverSpacing = rIDSA.get(DocumentSettingId::TAB_OVER_SPACING);
75 const bool bTabsRelativeToIndent = rIDSA.get(DocumentSettingId::TABS_RELATIVE_TO_INDENT);
77 // Update search location - since Center/Decimal tabstops' width is dependent on the following text.
78 SwTabPortion* pTmpLastTab = rInf.GetLastTab();
79 if (pTmpLastTab && (pTmpLastTab->IsTabCenterPortion() || pTmpLastTab->IsTabDecimalPortion()))
80 pTmpLastTab->PostFormat(rInf);
82 sal_Unicode cFill = 0;
83 sal_Unicode cDec = 0;
84 SvxTabAdjust eAdj;
86 SwTwips nNewTabPos;
87 bool bAutoTabStop = true;
89 const bool bRTL = m_pFrame->IsRightToLeft();
90 // #i24363# tab stops relative to indent
91 // nTabLeft: The absolute value, the tab stops are relative to: Tabs origin.
93 // #i91133#
94 const SwTwips nTabLeft = bRTL
95 ? m_pFrame->getFrameArea().Right() -
96 ( bTabsRelativeToIndent ? GetTabLeft() : 0 )
97 : m_pFrame->getFrameArea().Left() +
98 ( bTabsRelativeToIndent ? GetTabLeft() : 0 );
100 // The absolute position, where we started the line formatting
101 SwTwips nLinePos = GetLeftMargin();
102 if ( bRTL )
104 Point aPoint( nLinePos, 0 );
105 m_pFrame->SwitchLTRtoRTL( aPoint );
106 nLinePos = aPoint.X();
109 // The current position, relative to the line start
110 SwTwips nTabPos = rInf.GetLastTab() ? rInf.GetLastTab()->GetTabPos() : 0;
111 if( nTabPos < rInf.X() )
113 nTabPos = rInf.X();
116 // The current position in absolute coordinates
117 const SwTwips nCurrentAbsPos = bRTL ?
118 nLinePos - nTabPos :
119 nLinePos + nTabPos;
121 SwTwips nMyRight;
122 if ( m_pFrame->IsVertLR() )
123 nMyRight = Left();
124 else
125 nMyRight = Right();
127 if ( m_pFrame->IsVertical() )
129 Point aRightTop( nMyRight, m_pFrame->getFrameArea().Top() );
130 m_pFrame->SwitchHorizontalToVertical( aRightTop );
131 nMyRight = aRightTop.Y();
134 SwTwips nNextPos = 0;
135 bool bAbsoluteNextPos = false;
137 // #i24363# tab stops relative to indent
138 // nSearchPos: The current position relative to the tabs origin
139 const SwTwips nSearchPos = bRTL ?
140 nTabLeft - nCurrentAbsPos :
141 nCurrentAbsPos - nTabLeft;
143 // First, we examine the tab stops set at the paragraph style or
144 // any hard set tab stops:
145 // Note: If there are no user defined tab stops, there is always a
146 // default tab stop.
147 const SwTwips nOldRight = nMyRight;
148 // Accept left-tabstops beyond the paragraph margin for bTabOverSpacing
149 if (bTabOverSpacing || bTabOverMargin)
150 nMyRight = 0;
151 const SvxTabStop* pTabStop = m_aLineInf.GetTabStop( nSearchPos, nMyRight );
152 if (!nMyRight)
153 nMyRight = nOldRight;
154 if (pTabStop)
156 cFill = ' ' != pTabStop->GetFill() ? pTabStop->GetFill() : 0;
157 cDec = pTabStop->GetDecimal();
158 eAdj = pTabStop->GetAdjustment();
159 nNextPos = pTabStop->GetTabPos();
160 if(!bTabsRelativeToIndent && eAdj == SvxTabAdjust::Default && nSearchPos < 0)
162 //calculate default tab position of default tabs in negative indent
163 nNextPos = ( nSearchPos / nNextPos ) * nNextPos;
165 else if (pTabStop->GetTabPos() > nMyRight
166 && pTabStop->GetAdjustment() != SvxTabAdjust::Left)
168 // A rather special situation. The tabstop found is:
169 // 1.) in a document compatible with MS formats
170 // 2.) not a left tabstop.
171 // 3.) not the first tabstop (in that case nMyRight was adjusted to match tabPos).
172 // 4.) beyond the end of the text area
173 // Therefore, they act like right-tabstops at the edge of the para area.
174 // This benefits DOCX 2013+, and doesn't hurt the earlier formats,
175 // since up till now these were just treated as automatic tabstops.
176 eAdj = SvxTabAdjust::Right;
177 bAbsoluteNextPos = true;
178 // TODO: unclear if old Word has an upper limit for center/right
179 // tabs, UI allows setting 55.87cm max which is still one line
180 if (!bTabOverMargin || o3tl::toTwips(558, o3tl::Length::mm) < nNextPos)
182 nNextPos = rInf.Width();
185 bAutoTabStop = false;
187 else
189 SwTwips nDefTabDist = m_aLineInf.GetDefTabStop();
190 if (std::numeric_limits<SwTwips>::max() == nDefTabDist)
192 const SvxTabStopItem& rTab =
193 m_pFrame->GetAttrSet()->GetPool()->GetUserOrPoolDefaultItem( RES_PARATR_TABSTOP );
194 if( rTab.Count() )
195 nDefTabDist = rTab[0].GetTabPos();
196 else
197 nDefTabDist = SVX_TAB_DEFDIST;
198 m_aLineInf.SetDefTabStop( nDefTabDist );
200 SwTwips nCount = nSearchPos;
202 // Minimum tab stop width is 1
203 if (nDefTabDist <= 0)
204 nDefTabDist = 1;
206 nCount /= nDefTabDist;
207 nNextPos = ( nCount < 0 || ( !nCount && nSearchPos <= 0 ) )
208 ? ( nCount * nDefTabDist )
209 : ( ( nCount + 1 ) * nDefTabDist );
211 // --> FME 2004-09-21 #117919 Minimum tab stop width is 1 or 51 twips:
212 const SwTwips nMinimumTabWidth = m_pFrame->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_COMPAT) ? 0 : 50;
213 if( ( bRTL && nTabLeft - nNextPos >= nCurrentAbsPos - nMinimumTabWidth ) ||
214 ( !bRTL && nNextPos + nTabLeft <= nCurrentAbsPos + nMinimumTabWidth ) )
216 nNextPos += nDefTabDist;
218 cFill = 0;
219 eAdj = SvxTabAdjust::Left;
222 // #i115705# - correction and refactoring:
223 // overrule determined next tab stop position in order to apply
224 // a tab stop at the left margin under the following conditions:
225 // - the new tab portion is inside the hanging indent
226 // - a tab stop at the left margin is allowed
227 // - the determined next tab stop is a default tab stop position OR
228 // the determined next tab stop is beyond the left margin
230 tools::Long nLeftMarginTabPos = 0;
232 if ( !bTabsRelativeToIndent )
234 if ( bRTL )
236 Point aPoint( Left(), 0 );
237 m_pFrame->SwitchLTRtoRTL( aPoint );
238 nLeftMarginTabPos = m_pFrame->getFrameArea().Right() - aPoint.X();
240 else
242 nLeftMarginTabPos = Left() - m_pFrame->getFrameArea().Left();
245 if( m_pCurr->HasForcedLeftMargin() )
247 SwLinePortion* pPor = m_pCurr->GetNextPortion();
248 while( pPor && !pPor->IsFlyPortion() )
250 pPor = pPor->GetNextPortion();
252 if ( pPor )
254 nLeftMarginTabPos += pPor->Width();
258 const bool bNewTabPortionInsideHangingIndent =
259 bRTL ? nCurrentAbsPos > nTabLeft - nLeftMarginTabPos
260 : nCurrentAbsPos < nTabLeft + nLeftMarginTabPos;
261 if ( bNewTabPortionInsideHangingIndent )
263 // If the paragraph is not inside a list having a list tab stop following
264 // the list label or no further tab stop found in such a paragraph or
265 // the next tab stop position does not equal the list tab stop,
266 // a tab stop at the left margin can be applied. If this condition is
267 // not hold, it is overruled by compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST.
268 const bool bTabAtLeftMarginAllowed =
269 ( !m_aLineInf.IsListTabStopIncluded() ||
270 !pTabStop ||
271 nNextPos != m_aLineInf.GetListTabStopPosition() ) ||
272 // compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST:
273 m_pFrame->GetDoc().getIDocumentSettingAccess().
274 get(DocumentSettingId::TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST);
275 if ( bTabAtLeftMarginAllowed )
277 if ( !pTabStop || eAdj == SvxTabAdjust::Default ||
278 ( nNextPos > nLeftMarginTabPos ) )
280 eAdj = SvxTabAdjust::Default;
281 cFill = 0;
282 nNextPos = nLeftMarginTabPos;
288 if (!bAbsoluteNextPos)
289 nNextPos += bRTL ? nLinePos - nTabLeft : nTabLeft - nLinePos;
290 OSL_ENSURE( nNextPos >= 0, "GetTabStop: Don't go back!" );
291 nNewTabPos = nNextPos;
294 SwTabPortion *pTabPor = nullptr;
295 if ( bAuto )
297 if ( SvxTabAdjust::Decimal == eAdj &&
298 1 == m_aLineInf.NumberOfTabStops() )
299 pTabPor = new SwAutoTabDecimalPortion( nNewTabPos, cDec, cFill );
301 else
303 switch( eAdj )
305 case SvxTabAdjust::Right :
307 pTabPor = new SwTabRightPortion( nNewTabPos, cFill );
308 break;
310 case SvxTabAdjust::Center :
312 pTabPor = new SwTabCenterPortion( nNewTabPos, cFill );
313 break;
315 case SvxTabAdjust::Decimal :
317 pTabPor = new SwTabDecimalPortion( nNewTabPos, cDec, cFill );
318 break;
320 default:
322 OSL_ENSURE( SvxTabAdjust::Left == eAdj || SvxTabAdjust::Default == eAdj,
323 "+SwTextFormatter::NewTabPortion: unknown adjustment" );
324 pTabPor = new SwTabLeftPortion( nNewTabPos, cFill, bAutoTabStop );
325 break;
329 if (pTabPor)
330 rInf.UpdateTabSeen(pTabPor->GetWhichPor());
332 return pTabPor;
336 * The base class is initialized without setting anything
338 SwTabPortion::SwTabPortion( const SwTwips nTabPosition, const sal_Unicode cFillChar, const bool bAutoTab )
339 : m_nTabPos(nTabPosition), m_cFill(cFillChar), m_bAutoTabStop( bAutoTab )
341 mnLineLength = TextFrameIndex(1);
342 OSL_ENSURE(!IsFilled() || ' ' != m_cFill, "SwTabPortion::CTOR: blanks ?!");
343 SetWhichPor( PortionType::Tab );
346 bool SwTabPortion::Format( SwTextFormatInfo &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, pLastTab);
356 void SwTabPortion::FormatEOL( SwTextFormatInfo &rInf )
358 if( rInf.GetLastTab() == this )
359 PostFormat( rInf );
362 bool SwTabPortion::PreFormat(SwTextFormatInfo &rInf, SwTabPortion const*const pLastTab)
364 OSL_ENSURE( rInf.X() <= GetTabPos(), "SwTabPortion::PreFormat: rush hour" );
366 // Here we settle down ...
367 SetFix(rInf.X());
369 IDocumentSettingAccess const& rIDSA(rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess());
370 const bool bTabCompat = rIDSA.get(DocumentSettingId::TAB_COMPAT);
371 const bool bTabOverflow = rIDSA.get(DocumentSettingId::TAB_OVERFLOW);
372 const bool bTabOverMargin = rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN);
373 const bool bTabOverSpacing = rIDSA.get(DocumentSettingId::TAB_OVER_SPACING);
374 const tools::Long nTextFrameWidth = rInf.GetTextFrame()->getFrameArea().Width();
376 // The minimal width of a tab is one blank at least.
377 // #i37686# In compatibility mode, the minimum width
378 // should be 1, even for non-left tab stops.
379 SwTwips nMinimumTabWidth = 1;
380 if ( !bTabCompat )
382 // #i89179#
383 // tab portion representing the list tab of a list label gets the
384 // same font as the corresponding number portion
385 std::optional< SwFontSave > oSave;
386 if ( GetLen() == TextFrameIndex(0) &&
387 rInf.GetLast() && rInf.GetLast()->InNumberGrp() &&
388 static_cast<SwNumberPortion*>(rInf.GetLast())->HasFont() )
390 const SwFont* pNumberPortionFont =
391 static_cast<SwNumberPortion*>(rInf.GetLast())->GetFont();
392 oSave.emplace( rInf, const_cast<SwFont*>(pNumberPortionFont) );
394 OUString aTmp( ' ' );
395 SwTextSizeInfo aInf( rInf, &aTmp );
396 nMinimumTabWidth = aInf.GetTextSize().Width();
398 PrtWidth( nMinimumTabWidth );
400 // Break tab stop to next line if:
401 // 1. Minimal width does not fit to line anymore.
402 // 2. An underflow event was called for the tab portion.
403 bool bFull = ( bTabCompat && rInf.IsUnderflow() ) ||
404 (rInf.Width() <= rInf.X() + PrtWidth() && rInf.X() <= rInf.Width()
405 && (!bTabOverMargin || !pLastTab));
407 // #95477# Rotated tab stops get the width of one blank
408 const Degree10 nDir = rInf.GetFont()->GetOrientation( rInf.GetTextFrame()->IsVertical() );
410 if( ! bFull && 0_deg10 == nDir )
412 const PortionType nWhich = GetWhichPor();
413 switch( nWhich )
415 case PortionType::TabRight:
416 case PortionType::TabDecimal:
417 case PortionType::TabCenter:
419 if( PortionType::TabDecimal == nWhich )
420 rInf.SetTabDecimal(
421 static_cast<SwTabDecimalPortion*>(this)->GetTabDecimal());
422 rInf.SetLastTab( this );
423 break;
425 case PortionType::TabLeft:
427 // handle this case in PostFormat
428 if ((bTabOverMargin || bTabOverSpacing) && GetTabPos() > rInf.Width()
429 && (!m_bAutoTabStop || rInf.Width() <= rInf.X()))
431 if (bTabOverMargin || GetTabPos() < nTextFrameWidth)
433 rInf.SetLastTab(this);
434 break;
436 else
438 assert(!bTabOverMargin && bTabOverSpacing && GetTabPos() >= nTextFrameWidth);
439 bFull = true;
440 break;
444 PrtWidth(GetTabPos() - rInf.X());
445 bFull = rInf.Width() <= rInf.X() + PrtWidth();
447 // In tabulator compatibility mode, we reset the bFull flag
448 // if the tabulator is at the end of the paragraph and the
449 // tab stop position is outside the frame:
450 bool bAtParaEnd = rInf.GetIdx() + GetLen() == TextFrameIndex(rInf.GetText().getLength());
451 if ( bFull && bTabCompat &&
452 ( ( bTabOverflow && ( rInf.IsTabOverflow() || !m_bAutoTabStop ) ) || bAtParaEnd ) &&
453 GetTabPos() >= nTextFrameWidth)
455 bFull = false;
456 if ( bTabOverflow && !m_bAutoTabStop )
457 rInf.SetTabOverflow( true );
460 break;
462 default: OSL_ENSURE( false, "SwTabPortion::PreFormat: unknown adjustment" );
466 if( bFull )
468 // We have to look for endless loops, if the width is smaller than one blank
469 if( rInf.GetIdx() == rInf.GetLineStart() &&
470 // #119175# TabStop should be forced to current
471 // line if there is a fly reducing the line width:
472 !rInf.GetFly() )
474 PrtWidth(rInf.Width() - rInf.X());
475 SetFixWidth( PrtWidth() );
477 else
479 Height( 0 );
480 Width( 0 );
481 SetLen( TextFrameIndex(0) );
482 SetAscent( 0 );
483 SetNextPortion( nullptr ); //?????
485 return true;
487 else
489 // A trick with impact: The new Tabportions now behave like
490 // FlyFrames, located in the line - including adjustment !
491 SetFixWidth( PrtWidth() );
492 return false;
496 bool SwTabPortion::PostFormat( SwTextFormatInfo &rInf )
498 bool bTabOverMargin = rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
499 DocumentSettingId::TAB_OVER_MARGIN);
500 bool bTabOverSpacing = rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
501 DocumentSettingId::TAB_OVER_SPACING);
502 if (rInf.GetTextFrame()->IsInSct())
503 bTabOverMargin = false;
505 // If the tab position is larger than the right margin, it gets scaled down by default.
506 // However, if compat mode enabled, we allow tabs to go over the margin: the rest of the paragraph is not broken into lines.
507 const SwTwips nRight
508 = bTabOverMargin
509 ? GetTabPos()
510 : bTabOverSpacing
511 ? std::min(GetTabPos(), rInf.GetTextFrame()->getFrameArea().Right())
512 : std::min(GetTabPos(), rInf.Width());
513 const SwLinePortion *pPor = GetNextPortion();
515 SwTwips nPorWidth = 0;
516 while( pPor )
518 nPorWidth = nPorWidth + pPor->Width();
519 pPor = pPor->GetNextPortion();
522 const PortionType nWhich = GetWhichPor();
523 const bool bTabCompat = rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_COMPAT);
525 if ((bTabOverMargin || bTabOverSpacing) && PortionType::TabLeft == nWhich)
527 nPorWidth = 0;
530 // #127428# Abandon dec. tab position if line is full
531 if ( bTabCompat && PortionType::TabDecimal == nWhich )
533 SwTwips nPrePorWidth = static_cast<const SwTabDecimalPortion*>(this)->GetWidthOfPortionsUpToDecimalPosition();
535 // no value was set => no decimal character was found
536 if (std::numeric_limits<SwTwips>::max() != nPrePorWidth)
538 if ( !bTabOverMargin && nPrePorWidth && nPorWidth - nPrePorWidth > rInf.Width() - nRight )
540 nPrePorWidth += nPorWidth - nPrePorWidth - ( rInf.Width() - nRight );
543 nPorWidth = nPrePorWidth - 1;
547 if( PortionType::TabCenter == nWhich )
549 // centered tabs are problematic:
550 // We have to detect how much fits into the line.
551 SwTwips nNewWidth = nPorWidth / 2;
552 if (!bTabOverMargin && !bTabOverSpacing && nNewWidth > rInf.Width() - nRight)
553 nNewWidth = nPorWidth - (rInf.Width() - nRight);
554 nPorWidth = nNewWidth;
557 const SwTwips nDiffWidth = nRight - GetFix();
559 if( nDiffWidth > nPorWidth )
561 const SwTwips nOldWidth = GetFixWidth();
562 const SwTwips nAdjDiff = nDiffWidth - nPorWidth;
563 if( nAdjDiff > GetFixWidth() )
564 PrtWidth( nAdjDiff );
565 // Don't be afraid: we have to move rInf further.
566 // The right-tab till now only had the width of one blank.
567 // Now that we stretched, the difference had to be added to rInf.X() !
568 rInf.X( rInf.X() + PrtWidth() - nOldWidth );
570 SetFixWidth( PrtWidth() );
571 // reset last values
572 rInf.SetLastTab(nullptr);
573 if( PortionType::TabDecimal == nWhich )
574 rInf.SetTabDecimal(0);
576 return rInf.Width() <= rInf.X();
580 * Ex: LineIter::DrawTab()
582 void SwTabPortion::Paint( const SwTextPaintInfo &rInf ) const
584 // #i89179#
585 // tab portion representing the list tab of a list label gets the
586 // same font as the corresponding number portion
587 std::optional< SwFontSave > oSave;
588 bool bAfterNumbering = false;
589 if (GetLen() == TextFrameIndex(0))
591 const SwLinePortion* pPrevPortion =
592 const_cast<SwTabPortion*>(this)->FindPrevPortion( rInf.GetParaPortion() );
593 if ( pPrevPortion &&
594 pPrevPortion->InNumberGrp() &&
595 static_cast<const SwNumberPortion*>(pPrevPortion)->HasFont() )
597 const SwFont* pNumberPortionFont =
598 static_cast<const SwNumberPortion*>(pPrevPortion)->GetFont();
599 oSave.emplace( rInf, const_cast<SwFont*>(pNumberPortionFont) );
600 bAfterNumbering = true;
603 rInf.DrawBackBrush( *this );
604 if( !bAfterNumbering )
605 rInf.DrawBorder( *this );
607 // do we have to repaint a post it portion?
608 if( rInf.OnWin() && mpNextPortion && !mpNextPortion->Width() )
609 mpNextPortion->PrePaint( rInf, this );
611 // display special characters
612 if( rInf.OnWin() && rInf.GetOpt().IsTab() )
614 // filled tabs are shaded in gray
615 if( IsFilled() )
616 rInf.DrawViewOpt( *this, PortionType::Tab );
617 else
618 rInf.DrawTab( *this );
621 // Tabs should be underlined at once
622 if( rInf.GetFont()->IsPaintBlank() )
624 // Tabs with filling/filled tabs
625 const SwTwips nCharWidth = rInf.GetTextSize(OUString(' ')).Width();
627 // Robust:
628 if( nCharWidth )
630 // Always with kerning, also on printer!
631 sal_Int32 nChar = Width() / nCharWidth;
632 OUStringBuffer aBuf(nChar);
633 comphelper::string::padToLength(aBuf, nChar, ' ');
634 rInf.DrawText(aBuf.makeStringAndClear(), *this, TextFrameIndex(0),
635 TextFrameIndex(nChar), true);
639 // Display fill characters
640 if( !IsFilled() )
641 return;
643 // Tabs with filling/filled tabs
644 const SwTwips nCharWidth = rInf.GetTextSize(OUString(m_cFill)).Width();
645 OSL_ENSURE( nCharWidth, "!SwTabPortion::Paint: sophisticated tabchar" );
647 // Robust:
648 if( nCharWidth )
650 // Always with kerning, also on printer!
651 sal_Int32 nChar = Width() / nCharWidth;
652 if ( m_cFill == '_' )
653 ++nChar; // to avoid gaps
654 OUStringBuffer aBuf(nChar);
655 comphelper::string::padToLength(aBuf, nChar, m_cFill);
656 rInf.DrawText(aBuf.makeStringAndClear(), *this, TextFrameIndex(0),
657 TextFrameIndex(nChar), true);
661 void SwAutoTabDecimalPortion::Paint( const SwTextPaintInfo & ) const
665 void SwTabPortion::HandlePortion( SwPortionHandler& rPH ) const
667 rPH.Text( GetLen(), GetWhichPor() );
670 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */