diff options
Diffstat (limited to 'sw/source/core/text/txttab.cxx')
-rw-r--r-- | sw/source/core/text/txttab.cxx | 666 |
1 files changed, 666 insertions, 0 deletions
diff --git a/sw/source/core/text/txttab.cxx b/sw/source/core/text/txttab.cxx new file mode 100644 index 000000000000..64bb8be5fc12 --- /dev/null +++ b/sw/source/core/text/txttab.cxx @@ -0,0 +1,666 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: txttab.cxx,v $ + * $Revision: 1.33 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include "hintids.hxx" +#include <svx/lrspitem.hxx> +#ifndef _SVX_TSTPITEM_HXX //autogen +#include <svx/tstpitem.hxx> +#endif +#include <IDocumentSettingAccess.hxx> +#include <frmatr.hxx> +#include <SwPortionHandler.hxx> + +#include "viewopt.hxx" // SwViewOptions +#include "txtcfg.hxx" +#include "portab.hxx" +#include "inftxt.hxx" +#include "itrform2.hxx" +#include "txtfrm.hxx" +#include <numrule.hxx> +// --> OD 2008-06-05 #i89179# +#include <porfld.hxx> +// <-- + + +/************************************************************************* + * SwLineInfo::GetTabStop() + *************************************************************************/ + +//#i24363# tab stops relative to indent +/* Return the first tab stop that is > nSearchPos. + * If the tab stop is outside the print area, we + * return 0 if it is not the first tab stop.*/ +const SvxTabStop *SwLineInfo::GetTabStop( const SwTwips nSearchPos, + const SwTwips nRight ) const +{ + for( MSHORT i = 0; i < pRuler->Count(); ++i ) + { + const SvxTabStop &rTabStop = pRuler->operator[](i); + if( rTabStop.GetTabPos() > SwTwips(nRight) ) + return i ? 0 : &rTabStop; + + if( rTabStop.GetTabPos() > nSearchPos ) + return &rTabStop; + } + return 0; +} + +/************************************************************************* + * SwLineInfo::NumberOfTabStops() + *************************************************************************/ + +USHORT SwLineInfo::NumberOfTabStops() const +{ + return pRuler->Count(); +} + +/************************************************************************* + * SwTxtFormatter::NewTabPortion() + *************************************************************************/ + +SwTabPortion *SwTxtFormatter::NewTabPortion( SwTxtFormatInfo &rInf, bool bAuto ) const +{ + SwTabPortion *pTabPor = 0; + SwTabPortion *pLastTab = rInf.GetLastTab(); + if( pLastTab && ( pLastTab->IsTabCntPortion() || pLastTab->IsTabDecimalPortion() ) ) + if( pLastTab->PostFormat( rInf ) ) + return 0; + + xub_Unicode cFill = 0; + xub_Unicode cDec = 0; + SvxTabAdjust eAdj; + + KSHORT nNewTabPos; + { + const bool bRTL = pFrm->IsRightToLeft(); + // #i24363# tab stops relative to indent + // nTabLeft: The absolute value, the tab stops are relative to: Tabs origin. + // + // --> OD 2008-07-01 #i91133# + const bool bTabsRelativeToIndent = + pFrm->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT); + const SwTwips nTabLeft = bRTL + ? pFrm->Frm().Right() - + ( bTabsRelativeToIndent ? GetTabLeft() : 0 ) + : pFrm->Frm().Left() + + ( bTabsRelativeToIndent ? GetTabLeft() : 0 ); + // <-- + + // + // nLinePos: The absolute position, where we started the line formatting. + // + SwTwips nLinePos = GetLeftMargin(); + if ( bRTL ) + { + Point aPoint( nLinePos, 0 ); + pFrm->SwitchLTRtoRTL( aPoint ); + nLinePos = aPoint.X(); + } + + // + // nTabPos: The current position, relative to the line start. + // + SwTwips nTabPos = rInf.GetLastTab() ? rInf.GetLastTab()->GetTabPos() : 0; + if( nTabPos < rInf.X() ) + { + nTabPos = rInf.X(); + } + + // + // nCurrentAbsPos: The current position in absolute coordinates. + // + const SwTwips nCurrentAbsPos = bRTL ? + nLinePos - nTabPos : + nLinePos + nTabPos; + + SwTwips nMyRight = Right(); + + if ( pFrm->IsVertical() ) + { + Point aRightTop( nMyRight, pFrm->Frm().Top() ); + pFrm->SwitchHorizontalToVertical( aRightTop ); + nMyRight = aRightTop.Y(); + } + + SwTwips nNextPos; + + // #i24363# tab stops relative to indent + // nSearchPos: The current position relative to the tabs origin. + // + const SwTwips nSearchPos = bRTL ? + nTabLeft - nCurrentAbsPos : + nCurrentAbsPos - nTabLeft; + + // + // First, we examine the tab stops set at the paragraph style or + // any hard set tab stops: + // Note: If there are no user defined tab stops, there is always a + // default tab stop. + // + const SvxTabStop* pTabStop = + aLineInf.GetTabStop( nSearchPos, nMyRight ); + if( pTabStop ) + { + cFill = ' ' != pTabStop->GetFill() ? pTabStop->GetFill() : 0; + cDec = pTabStop->GetDecimal(); + eAdj = pTabStop->GetAdjustment(); + nNextPos = pTabStop->GetTabPos(); + } + else + { + KSHORT nDefTabDist = aLineInf.GetDefTabStop(); + if( KSHRT_MAX == nDefTabDist ) + { + const SvxTabStopItem& rTab = + (const SvxTabStopItem &)pFrm->GetAttrSet()-> + GetPool()->GetDefaultItem( RES_PARATR_TABSTOP ); + if( rTab.Count() ) + nDefTabDist = (KSHORT)rTab.GetStart()->GetTabPos(); + else + nDefTabDist = SVX_TAB_DEFDIST; + aLineInf.SetDefTabStop( nDefTabDist ); + } + SwTwips nCount = nSearchPos; + + // Bei negativen Werten rundet "/" auf, "%" liefert negative Reste, + // bei positiven Werten rundet "/" ab, "%" liefert positvie Reste! + if ( nCount < 0 ) + nCount = 0; + + nCount /= nDefTabDist; + nNextPos = ( nCount + 1 ) * nDefTabDist ; + // --> FME 2004-09-21 #117919 Minimum tab stop width is 1 or 51 twips: + const SwTwips nMinimumTabWidth = pFrm->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) ? 0 : 50; + // <-- + if( ( bRTL && nTabLeft - nNextPos >= nCurrentAbsPos - nMinimumTabWidth ) || + ( !bRTL && nNextPos + nTabLeft <= nCurrentAbsPos + nMinimumTabWidth ) ) + { + nNextPos += nDefTabDist; + } + cFill = 0; + eAdj = SVX_TAB_ADJUST_LEFT; + } + // --> OD 2008-02-07 #newlistlevelattrs# + long nForced = 0; + if ( !bTabsRelativeToIndent ) + { + if ( bRTL ) + { + Point aPoint( Left(), 0 ); + pFrm->SwitchLTRtoRTL( aPoint ); + nForced = pFrm->Frm().Right() - aPoint.X(); + } + else + { + nForced = Left() - pFrm->Frm().Left(); + } + } + if( pCurr->HasForcedLeftMargin() ) + { + SwLinePortion* pPor = pCurr->GetPortion(); + while( pPor && !pPor->IsFlyPortion() ) + pPor = pPor->GetPortion(); + if( pPor ) + nForced += pPor->Width(); + } + + // <-- + // --> OD 2009-04-03 #i100732# + // correction of condition, when a tab stop at the left margin can + // be applied: + // If the paragraph is not inside a list having a list tab stop following + // the list label or no further tab stop found in such a paragraph or + // the next tab stop position does not equal the list tab stop, + // a tab stop at the left margin can be applied. If this condition is + // not hold, it is overruled by compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST. + const bool bTabAtLeftMargin = + ( !aLineInf.IsListTabStopIncluded() || + !pTabStop || + nNextPos != aLineInf.GetListTabStopPosition() ) || + // compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST: + pFrm->GetTxtNode()->getIDocumentSettingAccess()-> + get(IDocumentSettingAccess::TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST); + if ( bTabAtLeftMargin && + // <-- + ( ( bRTL && nCurrentAbsPos > nTabLeft - nForced ) || + ( !bRTL && nCurrentAbsPos < nTabLeft + nForced ) ) && + // --> OD 2009-07-21 #i103685# + // adjust condition: + // - back to pre OOo 3.0 condition, if tab stops are relative to indent + // - further checks needed, if tab stops are not relative to indent + ( nNextPos > 0 && + ( bTabsRelativeToIndent || + ( !pTabStop || nNextPos > nForced ) ) ) ) + // <-- + { + eAdj = SVX_TAB_ADJUST_DEFAULT; + cFill = 0; + nNextPos = nForced; + } + nNextPos += bRTL ? nLinePos - nTabLeft : nTabLeft - nLinePos; + ASSERT( nNextPos >= 0, "GetTabStop: Don't go back!" ); + nNewTabPos = KSHORT(nNextPos); + } + + if ( bAuto ) + { + if ( SVX_TAB_ADJUST_DECIMAL == eAdj && + // --> FME 2005-12-19 #127428# + 1 == aLineInf.NumberOfTabStops() ) + // <-- + pTabPor = new SwAutoTabDecimalPortion( nNewTabPos, cDec, cFill ); + } + else + { + switch( eAdj ) + { + case SVX_TAB_ADJUST_RIGHT : + { + pTabPor = new SwTabRightPortion( nNewTabPos, cFill ); + break; + } + case SVX_TAB_ADJUST_CENTER : + { + pTabPor = new SwTabCenterPortion( nNewTabPos, cFill ); + break; + } + case SVX_TAB_ADJUST_DECIMAL : + { + pTabPor = new SwTabDecimalPortion( nNewTabPos, cDec, cFill ); + break; + } + default: + { + ASSERT( SVX_TAB_ADJUST_LEFT == eAdj || SVX_TAB_ADJUST_DEFAULT == eAdj, + "+SwTxtFormatter::NewTabPortion: unknown adjustment" ); + pTabPor = new SwTabLeftPortion( nNewTabPos, cFill ); + break; + } + } + } + + // Vorhandensein von Tabulatoren anzeigen ... ist nicht mehr noetig + // pCurr->SetTabulation(); + // Aus Sicherheitsgruenden lassen wir uns die Daten errechnen + // pTabPor->Height( pLast->Height() ); + // pTabPor->SetAscent( pLast->GetAscent() ); + return pTabPor; +} + +/************************************************************************* + * SwTabPortion::SwTabPortion() + *************************************************************************/ + +// Die Basisklasse wird erstmal ohne alles initialisiert. + + +SwTabPortion::SwTabPortion( const KSHORT nTabPosition, const xub_Unicode cFillChar ) + : SwFixPortion( 0, 0 ), nTabPos(nTabPosition), cFill(cFillChar) +{ + nLineLength = 1; +#ifndef PRODUCT + if( IsFilled() ) + { + ASSERT( ' ' != cFill, "SwTabPortion::CTOR: blanks ?!" ); + } +#endif + SetWhichPor( POR_TAB ); +} + +/************************************************************************* + * virtual SwTabPortion::Format() + *************************************************************************/ + + + +sal_Bool SwTabPortion::Format( SwTxtFormatInfo &rInf ) +{ + SwTabPortion *pLastTab = rInf.GetLastTab(); + if( pLastTab == this ) + return PostFormat( rInf ); + if( pLastTab ) + pLastTab->PostFormat( rInf ); + return PreFormat( rInf ); +} + +/************************************************************************* + * virtual SwTabPortion::FormatEOL() + *************************************************************************/ + + + +void SwTabPortion::FormatEOL( SwTxtFormatInfo &rInf ) +{ + if( rInf.GetLastTab() == this && !IsTabLeftPortion() ) + PostFormat( rInf ); +} + +/************************************************************************* + * SwTabPortion::PreFormat() + *************************************************************************/ + + + +sal_Bool SwTabPortion::PreFormat( SwTxtFormatInfo &rInf ) +{ + ASSERT( rInf.X() <= GetTabPos(), "SwTabPortion::PreFormat: rush hour" ); + + // Hier lassen wir uns nieder... + Fix( static_cast<USHORT>(rInf.X()) ); + + const bool bTabCompat = rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT); + + // Die Mindestbreite eines Tabs ist immer mindestens ein Blank + // --> FME 2004-11-25 #i37686# In compatibility mode, the minimum width + // should be 1, even for non-left tab stops. + USHORT nMinimumTabWidth = 1; + // <-- + if ( !bTabCompat ) + { + // --> OD 2008-06-05 #i89179# + // tab portion representing the list tab of a list label gets the + // same font as the corresponding number portion + std::auto_ptr< SwFontSave > pSave( 0 ); + if ( GetLen() == 0 && + rInf.GetLast() && rInf.GetLast()->InNumberGrp() && + static_cast<SwNumberPortion*>(rInf.GetLast())->HasFont() ) + { + const SwFont* pNumberPortionFont = + static_cast<SwNumberPortion*>(rInf.GetLast())->GetFont(); + pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) ); + } + // <-- + XubString aTmp( ' ' ); + SwTxtSizeInfo aInf( rInf, aTmp ); + nMinimumTabWidth = aInf.GetTxtSize().Width(); + } + PrtWidth( nMinimumTabWidth ); + + // Break tab stop to next line if: + // 1. Minmal width does not fit to line anymore. + // 2. An underflow event was called for the tab portion. + sal_Bool bFull = ( bTabCompat && rInf.IsUnderFlow() ) || + rInf.Width() <= rInf.X() + PrtWidth(); + + // #95477# Rotated tab stops get the width of one blank + const USHORT nDir = rInf.GetFont()->GetOrientation( rInf.GetTxtFrm()->IsVertical() ); + + if( ! bFull && 0 == nDir ) + { + const MSHORT nWhich = GetWhichPor(); + switch( nWhich ) + { + case POR_TABRIGHT: + case POR_TABDECIMAL: + case POR_TABCENTER: + { + if( POR_TABDECIMAL == nWhich ) + rInf.SetTabDecimal( + ((SwTabDecimalPortion*)this)->GetTabDecimal()); + rInf.SetLastTab( this ); + break; + } + case POR_TABLEFT: + { + PrtWidth( static_cast<USHORT>(GetTabPos() - rInf.X()) ); + bFull = rInf.Width() <= rInf.X() + PrtWidth(); + + // In tabulator compatibility mode, we reset the bFull flag + // if the tabulator is at the end of the paragraph and the + // tab stop position is outside the frame: + if ( bFull && bTabCompat && + rInf.GetIdx() + GetLen() == rInf.GetTxt().Len() && + GetTabPos() >= rInf.GetTxtFrm()->Frm().Width() ) + bFull = sal_False; + + break; + } + default: ASSERT( !this, "SwTabPortion::PreFormat: unknown adjustment" ); + } + } + + if( bFull ) + { + // Wir muessen aufpassen, dass wir nicht endlos schleifen, + // wenn die Breite kleiner ist, als ein Blank ... + if( rInf.GetIdx() == rInf.GetLineStart() && + // --> FME 2005-01-19 #119175# TabStop should be forced to current + // line if there is a fly reducing the line width: + !rInf.GetFly() ) + // <-- + { + PrtWidth( static_cast<USHORT>(rInf.Width() - rInf.X()) ); + SetFixWidth( PrtWidth() ); + } + else + { + Height( 0 ); + Width( 0 ); + SetLen( 0 ); + SetAscent( 0 ); + SetPortion( NULL ); //????? + } + return sal_True; + } + else + { + // Ein Kunstgriff mit Effekt: Die neuen Tabportions verhalten sich nun + // so, wie FlyFrms, die in der Zeile stehen - inklusive Adjustment ! + SetFixWidth( PrtWidth() ); + return sal_False; + } +} + +/************************************************************************* + * SwTabPortion::PostFormat() + *************************************************************************/ + + + +sal_Bool SwTabPortion::PostFormat( SwTxtFormatInfo &rInf ) +{ + const KSHORT nRight = Min( GetTabPos(), rInf.Width() ); + const SwLinePortion *pPor = GetPortion(); + + KSHORT nPorWidth = 0; + while( pPor ) + { + DBG_LOOP; + nPorWidth = nPorWidth + pPor->Width(); + pPor = pPor->GetPortion(); + } + + const MSHORT nWhich = GetWhichPor(); + ASSERT( POR_TABLEFT != nWhich, "SwTabPortion::PostFormat: already formatted" ); + const bool bTabCompat = rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT); + + // --> FME 2005-12-19 #127428# Abandon dec. tab position if line is full: + if ( bTabCompat && POR_TABDECIMAL == nWhich ) + { + KSHORT nPrePorWidth = static_cast<const SwTabDecimalPortion*>(this)->GetWidthOfPortionsUpToDecimalPosition(); + + // no value was set => no decimal character was found + if ( USHRT_MAX != nPrePorWidth ) + { + if ( nPrePorWidth && nPorWidth - nPrePorWidth > rInf.Width() - nRight ) + { + nPrePorWidth += nPorWidth - nPrePorWidth - ( rInf.Width() - nRight ); + } + + nPorWidth = nPrePorWidth - 1; + } + } + // <-- + + if( POR_TABCENTER == nWhich ) + { + // zentrierte Tabs bereiten Probleme: + // Wir muessen den Anteil herausfinden, der noch auf die Zeile passt. + KSHORT nNewWidth = nPorWidth /2; + if( nNewWidth > rInf.Width() - nRight ) + nNewWidth = nPorWidth - (rInf.Width() - nRight); + nPorWidth = nNewWidth; + } + + const KSHORT nDiffWidth = nRight - Fix(); + + if( nDiffWidth > nPorWidth ) + { + const KSHORT nOldWidth = GetFixWidth(); + const KSHORT nAdjDiff = nDiffWidth - nPorWidth; + if( nAdjDiff > GetFixWidth() ) + PrtWidth( nAdjDiff ); + // Nicht erschrecken: wir muessen rInf weiterschieben. + // Immerhin waren wir als Rechtstab bislang nur ein Blank breit. + // Da wir uns jetzt aufgespannt haben, muss der Differenzbetrag + // auf rInf.X() addiert werden ! + rInf.X( rInf.X() + PrtWidth() - nOldWidth ); + } + SetFixWidth( PrtWidth() ); + // letzte Werte zuruecksetzen + rInf.SetLastTab(0); + if( POR_TABDECIMAL == nWhich ) + rInf.SetTabDecimal(0); + + return rInf.Width() <= rInf.X(); +} + +/************************************************************************* + * virtual SwTabPortion::Paint() + * + * Ex: LineIter::DrawTab() + *************************************************************************/ + +void SwTabPortion::Paint( const SwTxtPaintInfo &rInf ) const +{ +#ifndef PRODUCT + // Wir wollen uns die Fixbreite anzeigen + if( rInf.OnWin() && OPTDBG( rInf ) && + !rInf.GetOpt().IsPagePreview() && \ + !rInf.GetOpt().IsReadonly() && \ + SwViewOption::IsFieldShadings() ) + { + const KSHORT nTmpWidth = PrtWidth(); + ((SwTabPortion*)this)->PrtWidth( GetFixWidth() ); + rInf.DrawViewOpt( *this, POR_TAB ); + ((SwTabPortion*)this)->PrtWidth( nTmpWidth ); + } +#endif + + // --> OD 2008-06-05 #i89179# + // tab portion representing the list tab of a list label gets the + // same font as the corresponding number portion + std::auto_ptr< SwFontSave > pSave( 0 ); + if ( GetLen() == 0 ) + { + const SwLinePortion* pPrevPortion = + const_cast<SwTabPortion*>(this)->FindPrevPortion( rInf.GetParaPortion() ); + if ( pPrevPortion && + pPrevPortion->InNumberGrp() && + static_cast<const SwNumberPortion*>(pPrevPortion)->HasFont() ) + { + const SwFont* pNumberPortionFont = + static_cast<const SwNumberPortion*>(pPrevPortion)->GetFont(); + pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) ); + } + } + // <-- + rInf.DrawBackBrush( *this ); + + // do we have to repaint a post it portion? + if( rInf.OnWin() && pPortion && !pPortion->Width() ) + pPortion->PrePaint( rInf, this ); + + // Darstellung von Sonderzeichen + if( rInf.OnWin() && rInf.GetOpt().IsTab() ) + { + // gefuellte Tabs werden grau hinterlegt. + if( IsFilled() ) + rInf.DrawViewOpt( *this, POR_TAB ); + else + rInf.DrawTab( *this ); + } + + // 6842: Tabs sollen auf einmal wieder unterstrichen werden. + if( rInf.GetFont()->IsPaintBlank() ) + { + // Tabs mit Fuellung + XubString aTxt( ' ' ); + const KSHORT nCharWidth = rInf.GetTxtSize( aTxt ).Width(); + // robust: + if( nCharWidth ) + { + // 6864: immer mit Kerning, auch auf dem Drucker! + KSHORT nChar = Width() / nCharWidth; + rInf.DrawText( aTxt.Fill( nChar, ' ' ), *this, 0, nChar, sal_True ); + } + } + + // Ausgabe von Fuellzeichen + if( IsFilled() ) + { + // Tabs mit Fuellung + XubString aTxt( cFill ); + const KSHORT nCharWidth = rInf.GetTxtSize( aTxt ).Width(); +#if OSL_DEBUG_LEVEL > 1 + ASSERT( nCharWidth, "!SwTabPortion::Paint: sophisticated tabchar" ); +#endif + // robust: + if( nCharWidth ) + { + // 6864: immer mit Kerning, auch auf dem Drucker! + KSHORT nChar = Width() / nCharWidth; + if ( cFill == '_' ) + ++nChar; // damit keine Luecken entstehen (Bug 13430) + rInf.DrawText( aTxt.Fill( nChar, cFill ), *this, 0, nChar, sal_True ); + } + } +} + +/************************************************************************* + * virtual SwAutoTabDecimalPortion::Paint() + *************************************************************************/ + +void SwAutoTabDecimalPortion::Paint( const SwTxtPaintInfo & ) const +{ +} + +/************************************************************************* + * virtual SwTabPortion::HandlePortion() + *************************************************************************/ + +void SwTabPortion::HandlePortion( SwPortionHandler& rPH ) const +{ + rPH.Text( GetLen(), GetWhichPor() ); +} + |