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 $
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>
39 #include <IDocumentSettingAccess.hxx>
41 #include <SwPortionHandler.hxx>
43 #include "viewopt.hxx" // SwViewOptions
47 #include "itrform2.hxx"
49 #include <numrule.hxx>
50 // --> OD 2008-06-05 #i89179#
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
)
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
) )
99 xub_Unicode cFill
= 0;
100 xub_Unicode cDec
= 0;
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 );
120 // nLinePos: The absolute position, where we started the line formatting.
122 SwTwips nLinePos
= GetLeftMargin();
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() )
140 // nCurrentAbsPos: The current position in absolute coordinates.
142 const SwTwips nCurrentAbsPos
= bRTL
?
146 SwTwips nMyRight
= Right();
148 if ( pFrm
->IsVertical() )
150 Point
aRightTop( nMyRight
, pFrm
->Frm().Top() );
151 pFrm
->SwitchHorizontalToVertical( aRightTop
);
152 nMyRight
= aRightTop
.Y();
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
170 const SvxTabStop
* pTabStop
=
171 aLineInf
.GetTabStop( nSearchPos
, nMyRight
);
174 cFill
= ' ' != pTabStop
->GetFill() ? pTabStop
->GetFill() : 0;
175 cDec
= pTabStop
->GetDecimal();
176 eAdj
= pTabStop
->GetAdjustment();
177 nNextPos
= pTabStop
->GetTabPos();
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
);
188 nDefTabDist
= (KSHORT
)rTab
.GetStart()->GetTabPos();
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!
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;
205 if( ( bRTL
&& nTabLeft
- nNextPos
>= nCurrentAbsPos
- nMinimumTabWidth
) ||
206 ( !bRTL
&& nNextPos
+ nTabLeft
<= nCurrentAbsPos
+ nMinimumTabWidth
) )
208 nNextPos
+= nDefTabDist
;
211 eAdj
= SVX_TAB_ADJUST_LEFT
;
213 // --> OD 2008-02-07 #newlistlevelattrs#
215 if ( !bTabsRelativeToIndent
)
219 Point
aPoint( Left(), 0 );
220 pFrm
->SwitchLTRtoRTL( aPoint
);
221 nForced
= pFrm
->Frm().Right() - aPoint
.X();
225 nForced
= Left() - pFrm
->Frm().Left();
228 if( pCurr
->HasForcedLeftMargin() )
230 SwLinePortion
* pPor
= pCurr
->GetPortion();
231 while( pPor
&& !pPor
->IsFlyPortion() )
232 pPor
= pPor
->GetPortion();
234 nForced
+= pPor
->Width();
238 // --> OD 2009-04-03 #i100732#
239 // correction of condition, when a tab stop at the left margin can
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() ||
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
&&
255 ( ( bRTL
&& nCurrentAbsPos
> nTabLeft
- nForced
) ||
256 ( !bRTL
&& nCurrentAbsPos
< nTabLeft
+ nForced
) ) &&
257 // --> OD 2009-07-21 #i103685#
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
262 ( bTabsRelativeToIndent
||
263 ( !pTabStop
|| nNextPos
> nForced
) ) ) )
266 eAdj
= SVX_TAB_ADJUST_DEFAULT
;
270 nNextPos
+= bRTL
? nLinePos
- nTabLeft
: nTabLeft
- nLinePos
;
271 ASSERT( nNextPos
>= 0, "GetTabStop: Don't go back!" );
272 nNewTabPos
= KSHORT(nNextPos
);
277 if ( SVX_TAB_ADJUST_DECIMAL
== eAdj
&&
278 // --> FME 2005-12-19 #127428#
279 1 == aLineInf
.NumberOfTabStops() )
281 pTabPor
= new SwAutoTabDecimalPortion( nNewTabPos
, cDec
, cFill
);
287 case SVX_TAB_ADJUST_RIGHT
:
289 pTabPor
= new SwTabRightPortion( nNewTabPos
, cFill
);
292 case SVX_TAB_ADJUST_CENTER
:
294 pTabPor
= new SwTabCenterPortion( nNewTabPos
, cFill
);
297 case SVX_TAB_ADJUST_DECIMAL
:
299 pTabPor
= new SwTabDecimalPortion( nNewTabPos
, cDec
, cFill
);
304 ASSERT( SVX_TAB_ADJUST_LEFT
== eAdj
|| SVX_TAB_ADJUST_DEFAULT
== eAdj
,
305 "+SwTxtFormatter::NewTabPortion: unknown adjustment" );
306 pTabPor
= new SwTabLeftPortion( nNewTabPos
, cFill
);
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() );
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
)
334 ASSERT( ' ' != cFill
, "SwTabPortion::CTOR: blanks ?!" );
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
);
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() )
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;
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
) ) );
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();
427 if( POR_TABDECIMAL
== nWhich
)
429 ((SwTabDecimalPortion
*)this)->GetTabDecimal());
430 rInf
.SetLastTab( this );
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() )
448 default: ASSERT( !this, "SwTabPortion::PreFormat: unknown adjustment" );
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:
462 PrtWidth( static_cast<USHORT
>(rInf
.Width() - rInf
.X()) );
463 SetFixWidth( PrtWidth() );
471 SetPortion( NULL
); //?????
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() );
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;
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;
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
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
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
);
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 );
586 const SwLinePortion
* pPrevPortion
=
587 const_cast<SwTabPortion
*>(this)->FindPrevPortion( rInf
.GetParaPortion() );
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
) ) );
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.
609 rInf
.DrawViewOpt( *this, POR_TAB
);
611 rInf
.DrawTab( *this );
614 // 6842: Tabs sollen auf einmal wieder unterstrichen werden.
615 if( rInf
.GetFont()->IsPaintBlank() )
618 XubString
aTxt( ' ' );
619 const KSHORT nCharWidth
= rInf
.GetTxtSize( aTxt
).Width();
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
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" );
641 // 6864: immer mit Kerning, auch auf dem Drucker!
642 KSHORT nChar
= Width() / nCharWidth
;
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() );