| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sw.hxx" |
| |
| |
| #include <ctype.h> |
| |
| #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_ |
| #include <com/sun/star/i18n/ScriptType.hdl> |
| #endif |
| #include <hintids.hxx> // CH_TXTATR |
| #include <errhdl.hxx> // ASSERT |
| #include <SwPortionHandler.hxx> |
| #include <txtcfg.hxx> |
| #include <porlay.hxx> |
| #include <inftxt.hxx> |
| #include <guess.hxx> // SwTxtGuess, Zeilenumbruch |
| #include <porglue.hxx> |
| #include <portab.hxx> // pLastTab-> |
| #include <porfld.hxx> // SwFldPortion |
| #include <wrong.hxx> |
| #include <viewsh.hxx> |
| #include <IDocumentSettingAccess.hxx> |
| #include <viewopt.hxx> // SwViewOptions |
| |
| #include <IMark.hxx> |
| #include <pam.hxx> |
| #include <doc.hxx> |
| #include <xmloff/odffields.hxx> |
| #include <vcl/pdfextoutdevdata.hxx> |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| const sal_Char *GetLangName( const MSHORT nLang ); |
| #endif |
| |
| using namespace ::sw::mark; |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::i18n::ScriptType; |
| |
| /************************************************************************* |
| * lcl_AddSpace |
| * Returns for how many characters an extra space has to be added |
| * (for justified alignment). |
| *************************************************************************/ |
| |
| sal_uInt16 lcl_AddSpace( const SwTxtSizeInfo &rInf, const XubString* pStr, |
| const SwLinePortion& rPor ) |
| { |
| xub_StrLen nPos, nEnd; |
| const SwScriptInfo* pSI = 0; |
| |
| if ( pStr ) |
| { |
| // passing a string means we are inside a field |
| nPos = 0; |
| nEnd = pStr->Len(); |
| } |
| else |
| { |
| nPos = rInf.GetIdx(); |
| nEnd = rInf.GetIdx() + rPor.GetLen(); |
| pStr = &rInf.GetTxt(); |
| pSI = &((SwParaPortion*)rInf.GetParaPortion())->GetScriptInfo(); |
| } |
| |
| sal_uInt16 nCnt = 0; |
| sal_uInt8 nScript = 0; |
| |
| // If portion consists of Asian characters and language is not |
| // Korean, we add extra space to each character. |
| // first we get the script type |
| if ( pSI ) |
| nScript = pSI->ScriptType( nPos ); |
| else if ( pBreakIt->GetBreakIter().is() ) |
| nScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( *pStr, nPos ); |
| |
| // Note: rInf.GetIdx() can differ from nPos, |
| // e.g., when rPor is a field portion. nPos referes to the string passed |
| // to the function, rInf.GetIdx() referes to the original string. |
| |
| // We try to find out which justification mode is required. This is done by |
| // evaluating the script type and the language attribute set for this portion |
| |
| // Asian Justification: Each character get some extra space |
| if ( nEnd > nPos && ASIAN == nScript ) |
| { |
| LanguageType aLang = |
| rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript ); |
| |
| if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang ) |
| { |
| const SwLinePortion* pPor = rPor.GetPortion(); |
| if ( pPor && ( pPor->IsKernPortion() || |
| pPor->IsControlCharPortion() || |
| pPor->IsPostItsPortion() ) ) |
| pPor = pPor->GetPortion(); |
| |
| nCnt += nEnd - nPos; |
| |
| if ( !pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() || |
| pPor->IsBreakPortion() ) |
| --nCnt; |
| |
| return nCnt; |
| } |
| } |
| |
| // Kashida Justification: Insert Kashidas |
| if ( nEnd > nPos && pSI && COMPLEX == nScript ) |
| { |
| if ( SwScriptInfo::IsArabicText( *pStr, nPos, nEnd - nPos ) && pSI->CountKashida() ) |
| { |
| const sal_uInt16 nKashRes = pSI->KashidaJustify( 0, 0, nPos, nEnd - nPos ); |
| // i60591: need to check result of KashidaJustify |
| // determine if kashida justification is applicable |
| if( nKashRes != STRING_LEN ) |
| return nKashRes; |
| } |
| } |
| |
| // Thai Justification: Each character cell gets some extra space |
| if ( nEnd > nPos && COMPLEX == nScript ) |
| { |
| LanguageType aLang = |
| rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript ); |
| |
| if ( LANGUAGE_THAI == aLang ) |
| { |
| nCnt = SwScriptInfo::ThaiJustify( *pStr, 0, 0, nPos, nEnd - nPos ); |
| |
| const SwLinePortion* pPor = rPor.GetPortion(); |
| if ( pPor && ( pPor->IsKernPortion() || |
| pPor->IsControlCharPortion() || |
| pPor->IsPostItsPortion() ) ) |
| pPor = pPor->GetPortion(); |
| |
| if ( nCnt && ( ! pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() ) ) |
| --nCnt; |
| |
| return nCnt; |
| } |
| } |
| |
| // Here starts the good old "Look for blanks and add space to them" part. |
| // Note: We do not want to add space to an isolated latin blank in front |
| // of some complex characters in RTL environment |
| const sal_Bool bDoNotAddSpace = |
| LATIN == nScript && ( nEnd == nPos + 1 ) && pSI && |
| ( i18n::ScriptType::COMPLEX == |
| pSI->ScriptType( nPos + 1 ) ) && |
| rInf.GetTxtFrm() && rInf.GetTxtFrm()->IsRightToLeft(); |
| |
| if ( bDoNotAddSpace ) |
| return nCnt; |
| |
| for ( ; nPos < nEnd; ++nPos ) |
| { |
| if( CH_BLANK == pStr->GetChar( nPos ) ) |
| ++nCnt; |
| } |
| |
| // We still have to examine the next character: |
| // If the next character is ASIAN and not KOREAN we have |
| // to add an extra space |
| // nPos referes to the original string, even if a field string has |
| // been passed to this function |
| nPos = rInf.GetIdx() + rPor.GetLen(); |
| if ( nPos < rInf.GetTxt().Len() ) |
| { |
| sal_uInt8 nNextScript = 0; |
| const SwLinePortion* pPor = rPor.GetPortion(); |
| if ( pPor && pPor->IsKernPortion() ) |
| pPor = pPor->GetPortion(); |
| |
| if ( ! pBreakIt->GetBreakIter().is() || ! pPor || pPor->InFixMargGrp() ) |
| return nCnt; |
| |
| // next character is inside a field? |
| if ( CH_TXTATR_BREAKWORD == rInf.GetChar( nPos ) && pPor->InExpGrp() ) |
| { |
| sal_Bool bOldOnWin = rInf.OnWin(); |
| ((SwTxtSizeInfo &)rInf).SetOnWin( sal_False ); |
| |
| XubString aStr( aEmptyStr ); |
| pPor->GetExpTxt( rInf, aStr ); |
| ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin ); |
| |
| nNextScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( aStr, 0 ); |
| } |
| else |
| nNextScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( rInf.GetTxt(), nPos ); |
| |
| if( ASIAN == nNextScript ) |
| { |
| LanguageType aLang = |
| rInf.GetTxtFrm()->GetTxtNode()->GetLang( nPos, 1, nNextScript ); |
| |
| if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang ) |
| ++nCnt; |
| } |
| } |
| |
| return nCnt; |
| } |
| |
| /************************************************************************* |
| * class SwTxtPortion |
| *************************************************************************/ |
| |
| SwTxtPortion::SwTxtPortion( const SwLinePortion &rPortion ) |
| : SwLinePortion( rPortion ) |
| { |
| SetWhichPor( POR_TXT ); |
| } |
| |
| /************************************************************************* |
| * SwTxtPortion::BreakCut() |
| *************************************************************************/ |
| |
| void SwTxtPortion::BreakCut( SwTxtFormatInfo &rInf, const SwTxtGuess &rGuess ) |
| { |
| // Das Wort/Zeichen ist groesser als die Zeile |
| // Sonderfall Nr.1: Das Wort ist groesser als die Zeile |
| // Wir kappen... |
| const KSHORT nLineWidth = (KSHORT)(rInf.Width() - rInf.X()); |
| xub_StrLen nLen = rGuess.CutPos() - rInf.GetIdx(); |
| if( nLen ) |
| { |
| // special case: guess does not always provide the correct |
| // width, only in common cases. |
| if ( !rGuess.BreakWidth() ) |
| { |
| rInf.SetLen( nLen ); |
| SetLen( nLen ); |
| CalcTxtSize( rInf ); |
| |
| // changing these values requires also changing them in |
| // guess.cxx |
| KSHORT nItalic = 0; |
| if( ITALIC_NONE != rInf.GetFont()->GetItalic() && !rInf.NotEOL() ) |
| { |
| nItalic = Height() / 12; |
| } |
| Width( Width() + nItalic ); |
| } |
| else |
| { |
| Width( rGuess.BreakWidth() ); |
| SetLen( nLen ); |
| } |
| } |
| // special case: first character does not fit to line |
| else if ( rGuess.CutPos() == rInf.GetLineStart() ) |
| { |
| SetLen( 1 ); |
| Width( nLineWidth ); |
| } |
| else |
| { |
| SetLen( 0 ); |
| Width( 0 ); |
| } |
| } |
| |
| /************************************************************************* |
| * SwTxtPortion::BreakUnderflow() |
| *************************************************************************/ |
| |
| void SwTxtPortion::BreakUnderflow( SwTxtFormatInfo &rInf ) |
| { |
| Truncate(); |
| Height( 0 ); |
| Width( 0 ); |
| SetLen( 0 ); |
| SetAscent( 0 ); |
| rInf.SetUnderFlow( this ); |
| } |
| |
| /************************************************************************* |
| * SwTxtPortion::_Format() |
| *************************************************************************/ |
| |
| sal_Bool lcl_HasContent( const SwFldPortion& rFld, SwTxtFormatInfo &rInf ) |
| { |
| String aTxt; |
| return rFld.GetExpTxt( rInf, aTxt ) && aTxt.Len(); |
| } |
| |
| sal_Bool SwTxtPortion::_Format( SwTxtFormatInfo &rInf ) |
| { |
| // 5744: wenn nur der Trennstrich nicht mehr passt, |
| // muss trotzdem das Wort umgebrochen werden, ansonsten return sal_True! |
| if( rInf.IsUnderFlow() && rInf.GetSoftHyphPos() ) |
| { |
| // soft hyphen portion has triggered an underflow event because |
| // of an alternative spelling position |
| sal_Bool bFull = sal_False; |
| const sal_Bool bHyph = rInf.ChgHyph( sal_True ); |
| if( rInf.IsHyphenate() ) |
| { |
| SwTxtGuess aGuess; |
| // check for alternative spelling left from the soft hyphen |
| // this should usually be true but |
| aGuess.AlternativeSpelling( rInf, rInf.GetSoftHyphPos() - 1 ); |
| bFull = CreateHyphen( rInf, aGuess ); |
| ASSERT( bFull, "Problem with hyphenation!!!" ); |
| } |
| rInf.ChgHyph( bHyph ); |
| rInf.SetSoftHyphPos( 0 ); |
| return bFull; |
| } |
| |
| SwTxtGuess aGuess; |
| const sal_Bool bFull = !aGuess.Guess( *this, rInf, Height() ); |
| |
| // these are the possible cases: |
| // A Portion fits to current line |
| // B Portion does not fit to current line but a possible line break |
| // within the portion has been found by the break iterator, 2 subcases |
| // B1 break is hyphen |
| // B2 break is word end |
| // C Portion does not fit to current line and no possible line break |
| // has been found by break iterator, 2 subcases: |
| // C1 break iterator found a possible line break in portion before us |
| // ==> this break is used (underflow) |
| // C2 break iterator does not found a possible line break at all: |
| // ==> line break |
| |
| // case A: line not yet full |
| if ( !bFull ) |
| { |
| Width( aGuess.BreakWidth() ); |
| // Vorsicht ! |
| if( !InExpGrp() || InFldGrp() ) |
| SetLen( rInf.GetLen() ); |
| |
| short nKern = rInf.GetFont()->CheckKerning(); |
| if( nKern > 0 && rInf.Width() < rInf.X() + Width() + nKern ) |
| { |
| nKern = (short)(rInf.Width() - rInf.X() - Width() - 1); |
| if( nKern < 0 ) |
| nKern = 0; |
| } |
| if( nKern ) |
| new SwKernPortion( *this, nKern ); |
| } |
| // special case: hanging portion |
| else if( bFull && aGuess.GetHangingPortion() ) |
| { |
| Width( aGuess.BreakWidth() ); |
| SetLen( aGuess.BreakPos() - rInf.GetIdx() ); |
| Insert( aGuess.GetHangingPortion() ); |
| aGuess.GetHangingPortion()->SetAscent( GetAscent() ); |
| aGuess.ClearHangingPortion(); |
| } |
| // breakPos >= index |
| else if ( aGuess.BreakPos() >= rInf.GetIdx() && aGuess.BreakPos() != STRING_LEN ) |
| { |
| // case B1 |
| if( aGuess.HyphWord().is() && aGuess.BreakPos() > rInf.GetLineStart() |
| && ( aGuess.BreakPos() > rInf.GetIdx() || |
| ( rInf.GetLast() && ! rInf.GetLast()->IsFlyPortion() ) ) ) |
| { |
| CreateHyphen( rInf, aGuess ); |
| if ( rInf.GetFly() ) |
| rInf.GetRoot()->SetMidHyph( sal_True ); |
| else |
| rInf.GetRoot()->SetEndHyph( sal_True ); |
| } |
| // case C1 |
| // - Footnote portions with fake line start (i.e., not at beginning of line) |
| // should keep together with the text portion. (Note: no keep together |
| // with only footnote portions. |
| // - TabPortions not at beginning of line should keep together with the |
| // text portion, if they are not followed by a blank |
| // (work around different definition of tab stop character - breaking or |
| // non breaking character - in compatibility mode) |
| else if ( ( IsFtnPortion() && rInf.IsFakeLineStart() && |
| // --> OD 2010-01-29 #b6921213# |
| rInf.IsOtherThanFtnInside() ) || |
| // <-- |
| ( rInf.GetLast() && |
| rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) && |
| rInf.GetLast()->InTabGrp() && |
| rInf.GetLineStart() + rInf.GetLast()->GetLen() < rInf.GetIdx() && |
| aGuess.BreakPos() == rInf.GetIdx() && |
| CH_BLANK != rInf.GetChar( rInf.GetIdx() ) && |
| 0x3000 != rInf.GetChar( rInf.GetIdx() ) ) ) |
| BreakUnderflow( rInf ); |
| // case B2 |
| else if( rInf.GetIdx() > rInf.GetLineStart() || |
| aGuess.BreakPos() > rInf.GetIdx() || |
| // this is weird: during formatting the follow of a field |
| // the values rInf.GetIdx and rInf.GetLineStart are replaced |
| // IsFakeLineStart indicates GetIdx > GetLineStart |
| rInf.IsFakeLineStart() || |
| rInf.GetFly() || |
| rInf.IsFirstMulti() || |
| ( rInf.GetLast() && |
| ( rInf.GetLast()->IsFlyPortion() || |
| ( rInf.GetLast()->InFldGrp() && |
| ! rInf.GetLast()->InNumberGrp() && |
| ! rInf.GetLast()->IsErgoSumPortion() && |
| lcl_HasContent(*((SwFldPortion*)rInf.GetLast()),rInf ) ) ) ) ) |
| { |
| if ( rInf.X() + aGuess.BreakWidth() <= rInf.Width() ) |
| Width( aGuess.BreakWidth() ); |
| else |
| // this actually should not happen |
| Width( KSHORT(rInf.Width() - rInf.X()) ); |
| |
| SetLen( aGuess.BreakPos() - rInf.GetIdx() ); |
| |
| ASSERT( aGuess.BreakStart() >= aGuess.FieldDiff(), |
| "Trouble with expanded field portions during line break" ); |
| const xub_StrLen nRealStart = aGuess.BreakStart() - aGuess.FieldDiff(); |
| if( aGuess.BreakPos() < nRealStart && !InExpGrp() ) |
| { |
| SwHolePortion *pNew = new SwHolePortion( *this ); |
| pNew->SetLen( nRealStart - aGuess.BreakPos() ); |
| Insert( pNew ); |
| } |
| } |
| else // case C2, last exit |
| BreakCut( rInf, aGuess ); |
| } |
| // breakPos < index or no breakpos at all |
| else |
| { |
| sal_Bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx(); |
| if( aGuess.BreakPos() != STRING_LEN && |
| aGuess.BreakPos() != rInf.GetLineStart() && |
| ( !bFirstPor || rInf.GetFly() || rInf.GetLast()->IsFlyPortion() || |
| rInf.IsFirstMulti() ) && |
| ( !rInf.GetLast()->IsBlankPortion() || ((SwBlankPortion*) |
| rInf.GetLast())->MayUnderFlow( rInf, rInf.GetIdx()-1, sal_True ))) |
| { // case C1 (former BreakUnderflow()) |
| BreakUnderflow( rInf ); |
| } |
| else |
| // case C2, last exit |
| BreakCut( rInf, aGuess ); |
| } |
| |
| return bFull; |
| } |
| |
| /************************************************************************* |
| * virtual SwTxtPortion::Format() |
| *************************************************************************/ |
| |
| |
| |
| sal_Bool SwTxtPortion::Format( SwTxtFormatInfo &rInf ) |
| { |
| #if OSL_DEBUG_LEVEL > 1 |
| const XubString aDbgTxt( rInf.GetTxt().Copy( rInf.GetIdx(), rInf.GetLen() ) ); |
| #endif |
| |
| if( rInf.X() > rInf.Width() || (!GetLen() && !InExpGrp()) ) |
| { |
| Height( 0 ); |
| Width( 0 ); |
| SetLen( 0 ); |
| SetAscent( 0 ); |
| SetPortion( NULL ); // ???? |
| return sal_True; |
| } |
| |
| ASSERT( rInf.RealWidth() || (rInf.X() == rInf.Width()), |
| "SwTxtPortion::Format: missing real width" ); |
| ASSERT( Height(), "SwTxtPortion::Format: missing height" ); |
| |
| return _Format( rInf ); |
| } |
| |
| /************************************************************************* |
| * virtual SwTxtPortion::FormatEOL() |
| *************************************************************************/ |
| |
| // Format end of line |
| // 5083: Es kann schon manchmal unguenstige Faelle geben... |
| // "vom {Nikolaus}", Nikolaus bricht um "vom " wird im Blocksatz |
| // zu "vom" und " ", wobei der Glue expandiert wird, statt in die |
| // MarginPortion aufzugehen. |
| // rInf.nIdx steht auf dem naechsten Wort, nIdx-1 ist der letzte |
| // Buchstabe der Portion. |
| |
| |
| |
| void SwTxtPortion::FormatEOL( SwTxtFormatInfo &rInf ) |
| { |
| if( ( !GetPortion() || ( GetPortion()->IsKernPortion() && |
| !GetPortion()->GetPortion() ) ) && GetLen() && |
| rInf.GetIdx() < rInf.GetTxt().Len() && |
| 1 < rInf.GetIdx() && ' ' == rInf.GetChar( rInf.GetIdx() - 1 ) |
| && !rInf.GetLast()->IsHolePortion() ) |
| { |
| // calculate number of blanks |
| xub_StrLen nX = rInf.GetIdx() - 1; |
| sal_uInt16 nHoleLen = 1; |
| while( nX && nHoleLen < GetLen() && CH_BLANK == rInf.GetChar( --nX ) ) |
| nHoleLen++; |
| |
| // Erst uns einstellen und dann Inserten, weil wir ja auch ein |
| // SwLineLayout sein koennten. |
| KSHORT nBlankSize; |
| if( nHoleLen == GetLen() ) |
| nBlankSize = Width(); |
| else |
| nBlankSize = nHoleLen * rInf.GetTxtSize( ' ' ).Width(); |
| Width( Width() - nBlankSize ); |
| rInf.X( rInf.X() - nBlankSize ); |
| SetLen( GetLen() - nHoleLen ); |
| SwLinePortion *pHole = new SwHolePortion( *this ); |
| ( (SwHolePortion *)pHole )->SetBlankWidth( nBlankSize ); |
| ( (SwHolePortion *)pHole )->SetLen( nHoleLen ); |
| Insert( pHole ); |
| } |
| } |
| |
| /************************************************************************* |
| * virtual SwTxtPortion::GetCrsrOfst() |
| *************************************************************************/ |
| |
| |
| |
| xub_StrLen SwTxtPortion::GetCrsrOfst( const KSHORT nOfst ) const |
| { |
| ASSERT( !this, "SwTxtPortion::GetCrsrOfst: don't use this method!" ); |
| return SwLinePortion::GetCrsrOfst( nOfst ); |
| } |
| |
| /************************************************************************* |
| * virtual SwTxtPortion::GetTxtSize() |
| *************************************************************************/ |
| // Das GetTxtSize() geht davon aus, dass die eigene Laenge korrekt ist |
| |
| SwPosSize SwTxtPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const |
| { |
| return rInf.GetTxtSize(); |
| } |
| |
| /************************************************************************* |
| * virtual SwTxtPortion::Paint() |
| *************************************************************************/ |
| |
| |
| |
| void SwTxtPortion::Paint( const SwTxtPaintInfo &rInf ) const |
| { |
| if (rInf.OnWin() && 1==rInf.GetLen() && CH_TXT_ATR_FIELDEND==rInf.GetTxt().GetChar(rInf.GetIdx())) |
| { |
| rInf.DrawBackBrush( *this ); |
| const XubString aTxt = XubString::CreateFromAscii(CH_TXT_ATR_SUBST_FIELDEND); |
| rInf.DrawText( aTxt, *this, 0, aTxt.Len(), false ); |
| } |
| else if (rInf.OnWin() && 1==rInf.GetLen() && CH_TXT_ATR_FIELDSTART==rInf.GetTxt().GetChar(rInf.GetIdx())) |
| { |
| rInf.DrawBackBrush( *this ); |
| const XubString aTxt = XubString::CreateFromAscii(CH_TXT_ATR_SUBST_FIELDSTART); |
| rInf.DrawText( aTxt, *this, 0, aTxt.Len(), false ); |
| } |
| else if( GetLen() ) |
| { |
| rInf.DrawBackBrush( *this ); |
| |
| // do we have to repaint a post it portion? |
| if( rInf.OnWin() && pPortion && !pPortion->Width() ) |
| pPortion->PrePaint( rInf, this ); |
| |
| const SwWrongList *pWrongList = rInf.GetpWrongList(); |
| const SwWrongList *pGrammarCheckList = rInf.GetGrammarCheckList(); |
| // SMARTTAGS |
| const SwWrongList *pSmarttags = rInf.GetSmartTags(); |
| |
| const bool bWrong = 0 != pWrongList; |
| const bool bGrammarCheck = 0 != pGrammarCheckList; |
| const bool bSmartTags = 0 != pSmarttags; |
| |
| if ( bWrong || bSmartTags || bGrammarCheck ) |
| rInf.DrawMarkedText( *this, rInf.GetLen(), sal_False, bWrong, bSmartTags, bGrammarCheck ); |
| else |
| rInf.DrawText( *this, rInf.GetLen(), sal_False ); |
| } |
| } |
| |
| /************************************************************************* |
| * virtual SwTxtPortion::GetExpTxt() |
| *************************************************************************/ |
| |
| |
| |
| sal_Bool SwTxtPortion::GetExpTxt( const SwTxtSizeInfo &, XubString & ) const |
| { |
| return sal_False; |
| } |
| |
| /************************************************************************* |
| * xub_StrLen SwTxtPortion::GetSpaceCnt() |
| * long SwTxtPortion::CalcSpacing() |
| * sind fuer den Blocksatz zustaendig und ermitteln die Anzahl der Blanks |
| * und den daraus resultierenden zusaetzlichen Zwischenraum |
| *************************************************************************/ |
| |
| xub_StrLen SwTxtPortion::GetSpaceCnt( const SwTxtSizeInfo &rInf, |
| xub_StrLen& rCharCnt ) const |
| { |
| xub_StrLen nCnt = 0; |
| xub_StrLen nPos = 0; |
| if ( InExpGrp() ) |
| { |
| if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() ) |
| { |
| // Bei OnWin() wird anstatt eines Leerstrings gern mal ein Blank |
| // zurueckgeliefert, das koennen wir hier aber gar nicht gebrauchen |
| sal_Bool bOldOnWin = rInf.OnWin(); |
| ((SwTxtSizeInfo &)rInf).SetOnWin( sal_False ); |
| |
| XubString aStr( aEmptyStr ); |
| GetExpTxt( rInf, aStr ); |
| ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin ); |
| |
| nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this ); |
| nPos = aStr.Len(); |
| } |
| } |
| else if( !IsDropPortion() ) |
| { |
| nCnt = nCnt + lcl_AddSpace( rInf, 0, *this ); |
| nPos = GetLen(); |
| } |
| rCharCnt = rCharCnt + nPos; |
| return nCnt; |
| } |
| |
| long SwTxtPortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo &rInf ) const |
| { |
| xub_StrLen nCnt = 0; |
| |
| if ( InExpGrp() ) |
| { |
| if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() ) |
| { |
| // Bei OnWin() wird anstatt eines Leerstrings gern mal ein Blank |
| // zurueckgeliefert, das koennen wir hier aber gar nicht gebrauchen |
| sal_Bool bOldOnWin = rInf.OnWin(); |
| ((SwTxtSizeInfo &)rInf).SetOnWin( sal_False ); |
| |
| XubString aStr( aEmptyStr ); |
| GetExpTxt( rInf, aStr ); |
| ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin ); |
| if( nSpaceAdd > 0 ) |
| nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this ); |
| else |
| { |
| nSpaceAdd = -nSpaceAdd; |
| nCnt = aStr.Len(); |
| } |
| } |
| } |
| else if( !IsDropPortion() ) |
| { |
| if( nSpaceAdd > 0 ) |
| nCnt = nCnt + lcl_AddSpace( rInf, 0, *this ); |
| else |
| { |
| nSpaceAdd = -nSpaceAdd; |
| nCnt = GetLen(); |
| SwLinePortion* pPor = GetPortion(); |
| |
| // we do not want an extra space in front of margin portions |
| if ( nCnt ) |
| { |
| while ( pPor && !pPor->Width() && ! pPor->IsHolePortion() ) |
| pPor = pPor->GetPortion(); |
| |
| if ( !pPor || pPor->InFixMargGrp() || pPor->IsHolePortion() ) |
| --nCnt; |
| } |
| } |
| } |
| |
| return nCnt * nSpaceAdd / SPACING_PRECISION_FACTOR; |
| } |
| |
| /************************************************************************* |
| * virtual SwTxtPortion::HandlePortion() |
| *************************************************************************/ |
| |
| void SwTxtPortion::HandlePortion( SwPortionHandler& rPH ) const |
| { |
| rPH.Text( GetLen(), GetWhichPor() ); |
| } |
| |
| |
| SwTxtInputFldPortion::SwTxtInputFldPortion() |
| : SwTxtPortion() |
| , mbContainsInputFieldStart( false ) |
| , mbContainsInputFieldEnd( false ) |
| { |
| SetWhichPor( POR_INPUTFLD ); |
| } |
| |
| |
| sal_Bool SwTxtInputFldPortion::Format( SwTxtFormatInfo &rInf ) |
| { |
| mbContainsInputFieldStart = |
| rInf.GetChar( rInf.GetIdx() ) == CH_TXT_ATR_INPUTFIELDSTART; |
| mbContainsInputFieldEnd = |
| rInf.GetChar( rInf.GetIdx() + rInf.GetLen() - 1 ) == CH_TXT_ATR_INPUTFIELDEND; |
| |
| sal_Bool bRet = sal_False; |
| if ( rInf.GetLen() == 1 |
| && ( mbContainsInputFieldStart || mbContainsInputFieldEnd ) ) |
| { |
| Width( 0 ); |
| } |
| else |
| { |
| SwTxtSlot aFormatTxt( &rInf, this, true, true, 0 ); |
| if ( rInf.GetLen() == 0 ) |
| { |
| Width( 0 ); |
| } |
| else |
| { |
| const xub_StrLen nFormerLineStart = rInf.GetLineStart(); |
| if ( !mbContainsInputFieldStart ) |
| { |
| rInf.SetLineStart( 0 ); |
| } |
| |
| bRet = SwTxtPortion::Format( rInf ); |
| |
| if ( mbContainsInputFieldEnd ) |
| { |
| // adjust portion length accordingly, if complete text fits into the portion |
| if ( GetLen() == rInf.GetLen() ) |
| { |
| SetLen( GetLen() + 1 ); |
| } |
| } |
| |
| if ( mbContainsInputFieldStart ) |
| { |
| // adjust portion length accordingly |
| SetLen( GetLen() + 1 ); |
| } |
| else |
| { |
| rInf.SetLineStart( nFormerLineStart ); |
| } |
| } |
| } |
| |
| return bRet; |
| } |
| |
| void SwTxtInputFldPortion::Paint( const SwTxtPaintInfo &rInf ) const |
| { |
| if ( Width() ) |
| { |
| rInf.DrawViewOpt( *this, POR_INPUTFLD ); |
| static sal_Char sSpace = ' '; |
| SwTxtSlot aPaintTxt( &rInf, this, true, true, |
| ContainsOnlyDummyChars() ? &sSpace : 0 ); |
| SwTxtPortion::Paint( rInf ); |
| } |
| } |
| |
| sal_Bool SwTxtInputFldPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const |
| { |
| xub_StrLen nIdx = rInf.GetIdx(); |
| xub_StrLen nLen = rInf.GetLen(); |
| if ( rInf.GetChar( rInf.GetIdx() ) == CH_TXT_ATR_INPUTFIELDSTART ) |
| { |
| ++nIdx; |
| --nLen; |
| } |
| if ( rInf.GetChar( rInf.GetIdx() + rInf.GetLen() - 1 ) == CH_TXT_ATR_INPUTFIELDEND ) |
| { |
| --nLen; |
| } |
| rTxt = rInf.GetTxt().Copy( nIdx, nLen ); |
| |
| return sal_True; |
| } |
| |
| |
| SwPosSize SwTxtInputFldPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const |
| { |
| SwTxtSlot aFormatTxt( &rInf, this, true, false, 0 ); |
| if ( rInf.GetLen() == 0 ) |
| { |
| return SwPosSize( 0, 0 ); |
| } |
| |
| return rInf.GetTxtSize(); |
| } |
| |
| |
| KSHORT SwTxtInputFldPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const |
| { |
| if( !Width() |
| && ContainsOnlyDummyChars() |
| && !rInf.GetOpt().IsPagePreview() |
| && !rInf.GetOpt().IsReadonly() |
| && SwViewOption::IsFieldShadings() ) |
| { |
| return rInf.GetTxtSize( ' ' ).Width(); |
| } |
| |
| return SwTxtPortion::GetViewWidth( rInf ); |
| } |
| |
| bool SwTxtInputFldPortion::ContainsOnlyDummyChars() const |
| { |
| return GetLen() <= 2 |
| && mbContainsInputFieldStart |
| && mbContainsInputFieldEnd; |
| } |
| |
| /************************************************************************* |
| * class SwHolePortion |
| *************************************************************************/ |
| |
| |
| |
| SwHolePortion::SwHolePortion( const SwTxtPortion &rPor ) |
| : nBlankWidth( 0 ) |
| { |
| SetLen( 1 ); |
| Height( rPor.Height() ); |
| SetAscent( rPor.GetAscent() ); |
| SetWhichPor( POR_HOLE ); |
| } |
| |
| SwLinePortion *SwHolePortion::Compress() { return this; } |
| |
| /************************************************************************* |
| * virtual SwHolePortion::Paint() |
| *************************************************************************/ |
| |
| |
| |
| void SwHolePortion::Paint( const SwTxtPaintInfo &rInf ) const |
| { |
| if( !rInf.GetOut() ) |
| return; |
| |
| // #i16816# export stuff only needed for tagged pdf support |
| const vcl::PDFExtOutDevData* pPDFExt = dynamic_cast<const vcl::PDFExtOutDevData*>( rInf.GetOut()->GetExtOutDevData() ); |
| if( !pPDFExt || !pPDFExt->GetIsExportTaggedPDF()) |
| return; |
| |
| // #i68503# the hole must have no decoration for a consistent visual appearance |
| const SwFont* pOrigFont = rInf.GetFont(); |
| SwFont* pHoleFont = NULL; |
| SwFontSave* pFontSave = NULL; |
| if( pOrigFont->GetUnderline() != UNDERLINE_NONE |
| || pOrigFont->GetOverline() != UNDERLINE_NONE |
| || pOrigFont->GetStrikeout() != STRIKEOUT_NONE ) |
| { |
| pHoleFont = new SwFont( *pOrigFont ); |
| pHoleFont->SetUnderline( UNDERLINE_NONE ); |
| pHoleFont->SetOverline( UNDERLINE_NONE ); |
| pHoleFont->SetStrikeout( STRIKEOUT_NONE ); |
| pFontSave = new SwFontSave( rInf, pHoleFont ); |
| } |
| |
| const XubString aTxt( ' ' ); |
| rInf.DrawText( aTxt, *this, 0, 1, false ); |
| |
| delete pFontSave; |
| delete pHoleFont; |
| } |
| |
| /************************************************************************* |
| * virtual SwHolePortion::Format() |
| *************************************************************************/ |
| |
| |
| |
| sal_Bool SwHolePortion::Format( SwTxtFormatInfo &rInf ) |
| { |
| return rInf.IsFull() || rInf.X() >= rInf.Width(); |
| } |
| |
| /************************************************************************* |
| * virtual SwHolePortion::HandlePortion() |
| *************************************************************************/ |
| |
| void SwHolePortion::HandlePortion( SwPortionHandler& rPH ) const |
| { |
| rPH.Text( GetLen(), GetWhichPor() ); |
| } |
| |
| void SwFieldMarkPortion::Paint( const SwTxtPaintInfo & /*rInf*/) const |
| { |
| // These shouldn't be painted! |
| //SwTxtPortion::Paint(rInf); |
| } |
| |
| sal_Bool SwFieldMarkPortion::Format( SwTxtFormatInfo & ) |
| { |
| sal_Bool ret=0; |
| Width(0); |
| return ret; |
| } |
| |
| namespace { |
| static sal_Int32 getCurrentListIndex( IFieldmark* pBM, |
| ::rtl::OUString* io_pCurrentText = NULL ) |
| { |
| const IFieldmark::parameter_map_t* const pParameters = pBM->GetParameters(); |
| sal_Int32 nCurrentIdx = 0; |
| const IFieldmark::parameter_map_t::const_iterator pResult = pParameters->find(::rtl::OUString::createFromAscii(ODF_FORMDROPDOWN_RESULT)); |
| if(pResult != pParameters->end()) |
| pResult->second >>= nCurrentIdx; |
| if(io_pCurrentText) |
| { |
| const IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find(::rtl::OUString::createFromAscii(ODF_FORMDROPDOWN_LISTENTRY)); |
| if(pListEntries != pParameters->end()) |
| { |
| uno::Sequence< ::rtl::OUString > vListEntries; |
| pListEntries->second >>= vListEntries; |
| if(nCurrentIdx < vListEntries.getLength()) |
| *io_pCurrentText = vListEntries[nCurrentIdx]; |
| } |
| } |
| return nCurrentIdx; |
| } |
| } |
| |
| //FIXME Fieldbk |
| void SwFieldFormPortion::Paint( const SwTxtPaintInfo& rInf ) const |
| { |
| SwTxtNode* pNd = const_cast<SwTxtNode*>(rInf.GetTxtFrm()->GetTxtNode()); |
| const SwDoc *doc=pNd->GetDoc(); |
| SwIndex aIndex( pNd, rInf.GetIdx() ); |
| SwPosition aPosition(*pNd, aIndex); |
| |
| IFieldmark* pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition ); |
| |
| OSL_ENSURE( pBM, |
| "SwFieldFormPortion::Paint(..)" |
| " - Where is my form field bookmark???"); |
| |
| if ( pBM != NULL ) |
| { |
| if ( pBM->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ) ) |
| { // a checkbox... |
| ICheckboxFieldmark* pCheckboxFm = dynamic_cast< ICheckboxFieldmark* >(pBM); |
| bool checked = pCheckboxFm->IsChecked(); |
| rInf.DrawCheckBox(*this, checked); |
| } |
| else if ( pBM->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) ) |
| { // a list... |
| rtl::OUString aTxt; |
| rInf.DrawViewOpt( *this, POR_FLD ); |
| rInf.DrawText( aTxt, *this, 0, 0/*aTxt.getLength()*/, false ); |
| } |
| else |
| { |
| assert(0); // unknown type... |
| } |
| } |
| } |
| |
| sal_Bool SwFieldFormPortion::Format( SwTxtFormatInfo & rInf ) |
| { |
| sal_Bool ret = 0; |
| SwTxtNode *pNd = const_cast < SwTxtNode * >( rInf.GetTxtFrm( )->GetTxtNode( ) ); |
| const SwDoc *doc = pNd->GetDoc( ); |
| SwIndex aIndex( pNd, rInf.GetIdx( ) ); |
| SwPosition aPosition( *pNd, aIndex ); |
| IFieldmark *pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition ); |
| ASSERT( pBM != NULL, "Where is my form field bookmark???" ); |
| if ( pBM != NULL ) |
| { |
| if ( pBM->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ) ) |
| { |
| Width( rInf.GetTxtHeight( ) ); |
| Height( rInf.GetTxtHeight( ) ); |
| SetAscent( rInf.GetAscent( ) ); |
| } |
| else if ( pBM->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) ) |
| { |
| ::rtl::OUString aTxt; |
| getCurrentListIndex( pBM, &aTxt ); |
| SwPosSize aPosSize = rInf.GetTxtSize( aTxt ); |
| Width( aPosSize.Width( ) ); |
| Height( aPosSize.Height( ) ); |
| SetAscent( rInf.GetAscent( ) ); |
| } |
| else |
| { |
| assert( 0 ); // unknown type... |
| } |
| } |
| return ret; |
| } |
| |
| |