diff options
Diffstat (limited to 'sw/source/core/text/itratr.cxx')
-rw-r--r-- | sw/source/core/text/itratr.cxx | 1078 |
1 files changed, 1078 insertions, 0 deletions
diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx new file mode 100644 index 000000000000..60b476839705 --- /dev/null +++ b/sw/source/core/text/itratr.cxx @@ -0,0 +1,1078 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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 <editeng/charscaleitem.hxx> +#include <txtatr.hxx> +#include <sfx2/printer.hxx> +#include <editeng/lrspitem.hxx> +#include <vcl/window.hxx> +#include <vcl/svapp.hxx> +#include <fmtanchr.hxx> +#include <fmtfsize.hxx> +#include <fmtornt.hxx> +#include <fmtflcnt.hxx> +#include <fmtcntnt.hxx> +#include <fmtftn.hxx> +#include <frmatr.hxx> +#include <frmfmt.hxx> +#include <fmtfld.hxx> +#include <doc.hxx> +#include <viewsh.hxx> // ViewShell +#include <rootfrm.hxx> +#include <docary.hxx> +#include <ndtxt.hxx> +#include <dcontact.hxx> +#include <fldbas.hxx> // SwField +#include <pam.hxx> // SwPosition (lcl_MinMaxNode) +#include <itratr.hxx> +#include <htmltbl.hxx> +#include <swtable.hxx> +#include <redlnitr.hxx> +#include <fmtsrnd.hxx> +#include <itrtxt.hxx> +#include <breakit.hxx> +#include <com/sun/star/i18n/WordType.hpp> +#include <com/sun/star/i18n/ScriptType.hdl> + +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star; + +/************************************************************************* + * SwAttrIter::Chg() + *************************************************************************/ + +void SwAttrIter::Chg( SwTxtAttr *pHt ) +{ + ASSERT( pHt && pFnt, "No attribute of font available for change"); + if( pRedln && pRedln->IsOn() ) + pRedln->ChangeTxtAttr( pFnt, *pHt, sal_True ); + else + aAttrHandler.PushAndChg( *pHt, *pFnt ); + nChgCnt++; +} + +/************************************************************************* + * SwAttrIter::Rst() + *************************************************************************/ + +void SwAttrIter::Rst( SwTxtAttr *pHt ) +{ + ASSERT( pHt && pFnt, "No attribute of font available for reset"); + // get top from stack after removing pHt + if( pRedln && pRedln->IsOn() ) + pRedln->ChangeTxtAttr( pFnt, *pHt, sal_False ); + else + aAttrHandler.PopAndChg( *pHt, *pFnt ); + nChgCnt--; +} + +/************************************************************************* + * virtual SwAttrIter::~SwAttrIter() + *************************************************************************/ + +SwAttrIter::~SwAttrIter() +{ + delete pRedln; + delete pFnt; +} + +/************************************************************************* + * SwAttrIter::GetAttr() + * + * Liefert fuer eine Position das Attribut, wenn das Attribut genau auf + * der Position nPos liegt und kein EndIndex besitzt. + * GetAttr() wird fuer Attribute benoetigt, die die Formatierung beeinflussen + * sollen, ohne dabei den Inhalt des Strings zu veraendern. Solche "entarteten" + * Attribute sind z.B. Felder (die expandierten Text bereit halten) und + * zeilengebundene Frames. Um Mehrdeutigkeiten zwischen verschiedenen + * solcher Attribute zu vermeiden, werden beim Anlegen eines Attributs + * an der Startposition ein Sonderzeichen in den String einfuegt. + * Der Formatierer stoesst auf das Sonderzeichen und holt sich per + * GetAttr() das entartete Attribut. + *************************************************************************/ + +SwTxtAttr *SwAttrIter::GetAttr( const xub_StrLen nPosition ) const +{ + return (m_pTxtNode) ? m_pTxtNode->GetTxtAttrForCharAt(nPosition) : 0; +} + +/************************************************************************* + * SwAttrIter::SeekAndChg() + *************************************************************************/ + +sal_Bool SwAttrIter::SeekAndChgAttrIter( const xub_StrLen nNewPos, OutputDevice* pOut ) +{ + sal_Bool bChg = nStartIndex && nNewPos == nPos ? pFnt->IsFntChg() : Seek( nNewPos ); + if ( pLastOut != pOut ) + { + pLastOut = pOut; + pFnt->SetFntChg( sal_True ); + bChg = sal_True; + } + if( bChg ) + { + // wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo + // des gewuenschten Fonts ... + if ( !nChgCnt && !nPropFont ) + pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ], + aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() ); + pFnt->ChgPhysFnt( pShell, *pOut ); + } + return bChg; +} + +sal_Bool SwAttrIter::IsSymbol( const xub_StrLen nNewPos ) +{ + Seek( nNewPos ); + if ( !nChgCnt && !nPropFont ) + pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ], + aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() ); + return pFnt->IsSymbol( pShell ); +} + +/************************************************************************* + * SwAttrIter::SeekStartAndChg() + *************************************************************************/ + +sal_Bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const sal_Bool bParaFont ) +{ + if ( pRedln && pRedln->ExtOn() ) + pRedln->LeaveExtend( *pFnt, 0 ); + + // reset font to its original state + aAttrHandler.Reset(); + aAttrHandler.ResetFont( *pFnt ); + + nStartIndex = nEndIndex = nPos = nChgCnt = 0; + if( nPropFont ) + pFnt->SetProportion( nPropFont ); + if( pRedln ) + { + pRedln->Clear( pFnt ); + if( !bParaFont ) + nChgCnt = nChgCnt + pRedln->Seek( *pFnt, 0, STRING_LEN ); + else + pRedln->Reset(); + } + + if ( pHints && !bParaFont ) + { + SwTxtAttr *pTxtAttr; + // Solange wir noch nicht am Ende des StartArrays angekommen sind && + // das TextAttribut an Position 0 beginnt ... + while ( ( nStartIndex < pHints->GetStartCount() ) && + !(*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()) ) + { + // oeffne die TextAttribute + Chg( pTxtAttr ); + nStartIndex++; + } + } + + sal_Bool bChg = pFnt->IsFntChg(); + if ( pLastOut != pOut ) + { + pLastOut = pOut; + pFnt->SetFntChg( sal_True ); + bChg = sal_True; + } + if( bChg ) + { + // wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo + // des gewuenschten Fonts ... + if ( !nChgCnt && !nPropFont ) + pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ], + aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() ); + pFnt->ChgPhysFnt( pShell, *pOut ); + } + return bChg; +} + +/************************************************************************* + * SwAttrIter::SeekFwd() + *************************************************************************/ + +// AMA: Neuer AttrIter Nov 94 + +void SwAttrIter::SeekFwd( const xub_StrLen nNewPos ) +{ + SwTxtAttr *pTxtAttr; + + if ( nStartIndex ) // wenn ueberhaupt schon Attribute geoeffnet wurden... + { + // Schliesse Attr, die z. Z. geoeffnet sind, vor nNewPos+1 aber enden. + + // Solange wir noch nicht am Ende des EndArrays angekommen sind && + // das TextAttribut vor oder an der neuen Position endet ... + while ( ( nEndIndex < pHints->GetEndCount() ) && + (*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos)) + { + // schliesse die TextAttribute, deren StartPos vor + // oder an der alten nPos lag, die z.Z. geoeffnet sind. + if (*pTxtAttr->GetStart() <= nPos) Rst( pTxtAttr ); + nEndIndex++; + } + } + else // ueberlies die nicht geoeffneten Enden + { + while ( ( nEndIndex < pHints->GetEndCount() ) && + (*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos)) + { + nEndIndex++; + } + } + // Solange wir noch nicht am Ende des StartArrays angekommen sind && + // das TextAttribut vor oder an der neuen Position beginnt ... + while ( ( nStartIndex < pHints->GetStartCount() ) && + (*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()<=nNewPos)) + { + // oeffne die TextAttribute, deren Ende hinter der neuen Position liegt + if ( *pTxtAttr->GetAnyEnd() > nNewPos ) Chg( pTxtAttr ); + nStartIndex++; + } + +} + +/************************************************************************* + * SwAttrIter::Seek() + *************************************************************************/ + +sal_Bool SwAttrIter::Seek( const xub_StrLen nNewPos ) +{ + if ( pRedln && pRedln->ExtOn() ) + pRedln->LeaveExtend( *pFnt, nNewPos ); + + if( pHints ) + { + if( !nNewPos || nNewPos < nPos ) + { + if( pRedln ) + pRedln->Clear( NULL ); + + // reset font to its original state + aAttrHandler.Reset(); + aAttrHandler.ResetFont( *pFnt ); + + if( nPropFont ) + pFnt->SetProportion( nPropFont ); + nStartIndex = nEndIndex = nPos = 0; + nChgCnt = 0; + + // Achtung! + // resetting the font here makes it necessary to apply any + // changes for extended input directly to the font + if ( pRedln && pRedln->ExtOn() ) + { + pRedln->UpdateExtFont( *pFnt ); + ++nChgCnt; + } + } + SeekFwd( nNewPos ); + } + + pFnt->SetActual( SwScriptInfo::WhichFont( nNewPos, 0, pScriptInfo ) ); + + if( pRedln ) + nChgCnt = nChgCnt + pRedln->Seek( *pFnt, nNewPos, nPos ); + nPos = nNewPos; + + if( nPropFont ) + pFnt->SetProportion( nPropFont ); + + return pFnt->IsFntChg(); +} + +/************************************************************************* + * SwAttrIter::GetNextAttr() + *************************************************************************/ + +xub_StrLen SwAttrIter::GetNextAttr( ) const +{ + xub_StrLen nNext = STRING_LEN; + if( pHints ) + { + if (pHints->GetStartCount() > nStartIndex) // Gibt es noch Starts? + nNext = (*pHints->GetStart(nStartIndex)->GetStart()); + if (pHints->GetEndCount() > nEndIndex) // Gibt es noch Enden? + { + xub_StrLen nNextEnd = (*pHints->GetEnd(nEndIndex)->GetAnyEnd()); + if ( nNextEnd<nNext ) nNext = nNextEnd; // Wer ist naeher? + } + } + if (m_pTxtNode!=NULL) { + //TODO maybe use hints like FieldHints for this instead of looking at the text... + int l=(nNext<m_pTxtNode->Len()?nNext:m_pTxtNode->Len()); + USHORT p=nPos; + const sal_Unicode *txt=m_pTxtNode->GetTxt().GetBuffer(); + while(p<l && txt[p]!=CH_TXT_ATR_FIELDSTART && txt[p]!=CH_TXT_ATR_FIELDEND && txt[p]!=CH_TXT_ATR_FORMELEMENT) p++; + if ((p<l && p>nPos) || nNext<=p) + nNext=p; + else + nNext=p+1; + } + if( pRedln ) + return pRedln->GetNextRedln( nNext ); + return nNext; +} + +#if OSL_DEBUG_LEVEL > 1 +/************************************************************************* + * SwAttrIter::Dump() + *************************************************************************/ + +void SwAttrIter::Dump( SvStream &/*rOS*/ ) const +{ +// Noch nicht an den neuen Attributiterator angepasst ... +} + +#endif + +class SwMinMaxArgs +{ +public: + OutputDevice* pOut; + ViewShell* pSh; + ULONG &rMin; + ULONG &rMax; + ULONG &rAbsMin; + long nRowWidth; + long nWordWidth; + long nWordAdd; + xub_StrLen nNoLineBreak; + SwMinMaxArgs( OutputDevice* pOutI, ViewShell* pShI, ULONG& rMinI, ULONG &rMaxI, ULONG &rAbsI ) + : pOut( pOutI ), pSh( pShI ), rMin( rMinI ), rMax( rMaxI ), rAbsMin( rAbsI ) + { nRowWidth = nWordWidth = nWordAdd = 0; nNoLineBreak = STRING_LEN; } + void Minimum( long nNew ) { if( (long)rMin < nNew ) rMin = nNew; } + void NewWord() { nWordAdd = nWordWidth = 0; } +}; + +sal_Bool lcl_MinMaxString( SwMinMaxArgs& rArg, SwFont* pFnt, const XubString &rTxt, + xub_StrLen nIdx, xub_StrLen nEnd ) +{ + sal_Bool bRet = sal_False; + while( nIdx < nEnd ) + { + xub_StrLen nStop = nIdx; + sal_Bool bClear; + LanguageType eLang = pFnt->GetLanguage(); + if( pBreakIt->GetBreakIter().is() ) + { + bClear = CH_BLANK == rTxt.GetChar( nStop ); + Boundary aBndry( pBreakIt->GetBreakIter()->getWordBoundary( rTxt, nIdx, + pBreakIt->GetLocale( eLang ), + WordType::DICTIONARY_WORD, TRUE ) ); + nStop = (xub_StrLen)aBndry.endPos; + if( nIdx <= aBndry.startPos && nIdx && nIdx-1 != rArg.nNoLineBreak ) + rArg.NewWord(); + if( nStop == nIdx ) + ++nStop; + if( nStop > nEnd ) + nStop = nEnd; + } + else + { + while( nStop < nEnd && CH_BLANK != rTxt.GetChar( nStop ) ) + ++nStop; + bClear = nStop == nIdx; + if ( bClear ) + { + rArg.NewWord(); + while( nStop < nEnd && CH_BLANK == rTxt.GetChar( nStop ) ) + ++nStop; + } + } + + SwDrawTextInfo aDrawInf( rArg.pSh, *rArg.pOut, 0, rTxt, nIdx, nStop - nIdx ); + long nAktWidth = pFnt->_GetTxtSize( aDrawInf ).Width(); + rArg.nRowWidth += nAktWidth; + if( bClear ) + rArg.NewWord(); + else + { + rArg.nWordWidth += nAktWidth; + if( (long)rArg.rAbsMin < rArg.nWordWidth ) + rArg.rAbsMin = rArg.nWordWidth; + rArg.Minimum( rArg.nWordWidth + rArg.nWordAdd ); + bRet = sal_True; + } + nIdx = nStop; + } + return bRet; +} + +sal_Bool SwTxtNode::IsSymbol( const xub_StrLen nBegin ) const +{ + SwScriptInfo aScriptInfo; + SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo ); + aIter.Seek( nBegin ); + const SwRootFrm* pTmpRootFrm = getIDocumentLayoutAccess()->GetRootFrm(); + return aIter.GetFnt()->IsSymbol( pTmpRootFrm ? + pTmpRootFrm->GetCurrShell() : + 0 ); +} + +class SwMinMaxNodeArgs +{ +public: + ULONG nMaxWidth; // Summe aller Rahmenbreite + long nMinWidth; // Breitester Rahmen + long nLeftRest; // noch nicht von Rahmen ueberdeckter Platz im l. Rand + long nRightRest; // noch nicht von Rahmen ueberdeckter Platz im r. Rand + long nLeftDiff; // Min/Max-Differenz des Rahmens im linken Rand + long nRightDiff; // Min/Max-Differenz des Rahmens im rechten Rand + ULONG nIndx; // Indexnummer des Nodes + void Minimum( long nNew ) { if( nNew > nMinWidth ) nMinWidth = nNew; } +}; + +sal_Bool lcl_MinMaxNode( const SwFrmFmtPtr& rpNd, void* pArgs ) +{ + const SwFmtAnchor& rFmtA = ((SwFrmFmt*)rpNd)->GetAnchor(); + + bool bCalculate = false; + if ((FLY_AT_PARA == rFmtA.GetAnchorId()) || + (FLY_AT_CHAR == rFmtA.GetAnchorId())) + { + bCalculate = true; + } + + if (bCalculate) + { + const SwMinMaxNodeArgs *pIn = (const SwMinMaxNodeArgs*)pArgs; + const SwPosition *pPos = rFmtA.GetCntntAnchor(); + ASSERT(pPos && pIn, "Unexpected NULL arguments"); + if (!pPos || !pIn || pIn->nIndx != pPos->nNode.GetIndex()) + bCalculate = false; + } + + if (bCalculate) + { + long nMin, nMax; + SwHTMLTableLayout *pLayout = 0; + MSHORT nWhich = ((SwFrmFmt*)rpNd)->Which(); + if( RES_DRAWFRMFMT != nWhich ) + { + // Enthaelt der Rahmen zu Beginn oder am Ende eine Tabelle? + const SwNodes& rNodes = static_cast<SwFrmFmt*>(rpNd)->GetDoc()->GetNodes(); + const SwFmtCntnt& rFlyCntnt = ((SwFrmFmt*)rpNd)->GetCntnt(); + ULONG nStt = rFlyCntnt.GetCntntIdx()->GetIndex(); + SwTableNode* pTblNd = rNodes[nStt+1]->GetTableNode(); + if( !pTblNd ) + { + SwNode *pNd = rNodes[nStt]; + pNd = rNodes[pNd->EndOfSectionIndex()-1]; + if( pNd->IsEndNode() ) + pTblNd = pNd->StartOfSectionNode()->GetTableNode(); + } + + if( pTblNd ) + pLayout = pTblNd->GetTable().GetHTMLTableLayout(); + } + + const SwFmtHoriOrient& rOrient = ((SwFrmFmt*)rpNd)->GetHoriOrient(); + sal_Int16 eHoriOri = rOrient.GetHoriOrient(); + + long nDiff; + if( pLayout ) + { + nMin = pLayout->GetMin(); + nMax = pLayout->GetMax(); + nDiff = nMax - nMin; + } + else + { + if( RES_DRAWFRMFMT == nWhich ) + { + const SdrObject* pSObj = rpNd->FindSdrObject(); + if( pSObj ) + nMin = pSObj->GetCurrentBoundRect().GetWidth(); + else + nMin = 0; + + } + else + { + const SwFmtFrmSize &rSz = ( (SwFrmFmt*)rpNd )->GetFrmSize(); + nMin = rSz.GetWidth(); + } + nMax = nMin; + nDiff = 0; + } + + const SvxLRSpaceItem &rLR = ( (SwFrmFmt*)rpNd )->GetLRSpace(); + nMin += rLR.GetLeft(); + nMin += rLR.GetRight(); + nMax += rLR.GetLeft(); + nMax += rLR.GetRight(); + + if( SURROUND_THROUGHT == ((SwFrmFmt*)rpNd)->GetSurround().GetSurround() ) + { + ( (SwMinMaxNodeArgs*)pArgs )->Minimum( nMin ); + return sal_True; + } + + // Rahmen, die recht bzw. links ausgerichtet sind, gehen nur + // teilweise in die Max-Berechnung ein, da der Rand schon berueck- + // sichtigt wird. Nur wenn die Rahmen in den Textkoerper ragen, + // wird dieser Teil hinzuaddiert. + switch( eHoriOri ) + { + case text::HoriOrientation::RIGHT: + { + if( nDiff ) + { + ((SwMinMaxNodeArgs*)pArgs)->nRightRest -= + ((SwMinMaxNodeArgs*)pArgs)->nRightDiff; + ((SwMinMaxNodeArgs*)pArgs)->nRightDiff = nDiff; + } + if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() ) + { + if( ((SwMinMaxNodeArgs*)pArgs)->nRightRest > 0 ) + ((SwMinMaxNodeArgs*)pArgs)->nRightRest = 0; + } + ((SwMinMaxNodeArgs*)pArgs)->nRightRest -= nMin; + break; + } + case text::HoriOrientation::LEFT: + { + if( nDiff ) + { + ((SwMinMaxNodeArgs*)pArgs)->nLeftRest -= + ((SwMinMaxNodeArgs*)pArgs)->nLeftDiff; + ((SwMinMaxNodeArgs*)pArgs)->nLeftDiff = nDiff; + } + if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() && + ((SwMinMaxNodeArgs*)pArgs)->nLeftRest < 0 ) + ((SwMinMaxNodeArgs*)pArgs)->nLeftRest = 0; + ((SwMinMaxNodeArgs*)pArgs)->nLeftRest -= nMin; + break; + } + default: + { + ( (SwMinMaxNodeArgs*)pArgs )->nMaxWidth += nMax; + ( (SwMinMaxNodeArgs*)pArgs )->Minimum( nMin ); + } + } + } + return sal_True; +} + +#define FLYINCNT_MIN_WIDTH 284 + +// changing this method very likely requires changing of +// "GetScalingOfSelectedText" +void SwTxtNode::GetMinMaxSize( ULONG nIndex, ULONG& rMin, ULONG &rMax, + ULONG& rAbsMin, OutputDevice* pOut ) const +{ + ViewShell* pSh = 0; + GetDoc()->GetEditShell( &pSh ); + if( !pOut ) + { + if( pSh ) + pOut = pSh->GetWin(); + if( !pOut ) + pOut = GetpApp()->GetDefaultDevice(); + } + + MapMode aOldMap( pOut->GetMapMode() ); + pOut->SetMapMode( MapMode( MAP_TWIP ) ); + + rMin = 0; + rMax = 0; + rAbsMin = 0; + + const SvxLRSpaceItem &rSpace = GetSwAttrSet().GetLRSpace(); + long nLROffset = rSpace.GetTxtLeft() + GetLeftMarginWithNum( sal_True ); + short nFLOffs; + // Bei Numerierung ist ein neg. Erstzeileneinzug vermutlich + // bereits gefuellt... + if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset ) + nLROffset = nFLOffs; + + SwMinMaxNodeArgs aNodeArgs; + aNodeArgs.nMinWidth = 0; + aNodeArgs.nMaxWidth = 0; + aNodeArgs.nLeftRest = nLROffset; + aNodeArgs.nRightRest = rSpace.GetRight(); + aNodeArgs.nLeftDiff = 0; + aNodeArgs.nRightDiff = 0; + if( nIndex ) + { + SwSpzFrmFmts* pTmp = (SwSpzFrmFmts*)GetDoc()->GetSpzFrmFmts(); + if( pTmp ) + { + aNodeArgs.nIndx = nIndex; + pTmp->ForEach( &lcl_MinMaxNode, &aNodeArgs ); + } + } + if( aNodeArgs.nLeftRest < 0 ) + aNodeArgs.Minimum( nLROffset - aNodeArgs.nLeftRest ); + aNodeArgs.nLeftRest -= aNodeArgs.nLeftDiff; + if( aNodeArgs.nLeftRest < 0 ) + aNodeArgs.nMaxWidth -= aNodeArgs.nLeftRest; + + if( aNodeArgs.nRightRest < 0 ) + aNodeArgs.Minimum( rSpace.GetRight() - aNodeArgs.nRightRest ); + aNodeArgs.nRightRest -= aNodeArgs.nRightDiff; + if( aNodeArgs.nRightRest < 0 ) + aNodeArgs.nMaxWidth -= aNodeArgs.nRightRest; + + SwScriptInfo aScriptInfo; + SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo ); + xub_StrLen nIdx = 0; + aIter.SeekAndChgAttrIter( nIdx, pOut ); + xub_StrLen nLen = m_Text.Len(); + long nAktWidth = 0; + MSHORT nAdd = 0; + SwMinMaxArgs aArg( pOut, pSh, rMin, rMax, rAbsMin ); + while( nIdx < nLen ) + { + xub_StrLen nNextChg = aIter.GetNextAttr(); + xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx ); + if( nNextChg > nStop ) + nNextChg = nStop; + SwTxtAttr *pHint = NULL; + xub_Unicode cChar = CH_BLANK; + nStop = nIdx; + while( nStop < nLen && nStop < nNextChg && + CH_TAB != ( cChar = m_Text.GetChar( nStop ) ) && + CH_BREAK != cChar && CHAR_HARDBLANK != cChar && + CHAR_HARDHYPHEN != cChar && CHAR_SOFTHYPHEN != cChar && + !pHint ) + { + if( ( CH_TXTATR_BREAKWORD != cChar && CH_TXTATR_INWORD != cChar ) + || ( 0 == ( pHint = aIter.GetAttr( nStop ) ) ) ) + ++nStop; + } + if ( lcl_MinMaxString( aArg, aIter.GetFnt(), m_Text, nIdx, nStop ) ) + { + nAdd = 20; + } + nIdx = nStop; + aIter.SeekAndChgAttrIter( nIdx, pOut ); + switch( cChar ) + { + case CH_BREAK : + { + if( (long)rMax < aArg.nRowWidth ) + rMax = aArg.nRowWidth; + aArg.nRowWidth = 0; + aArg.NewWord(); + aIter.SeekAndChgAttrIter( ++nIdx, pOut ); + } + break; + case CH_TAB : + { + aArg.NewWord(); + aIter.SeekAndChgAttrIter( ++nIdx, pOut ); + } + break; + case CHAR_SOFTHYPHEN: + ++nIdx; + break; + case CHAR_HARDBLANK: + case CHAR_HARDHYPHEN: + { + XubString sTmp( cChar ); + const SwRootFrm* pTmpRootFrm = getIDocumentLayoutAccess()->GetRootFrm(); + SwDrawTextInfo aDrawInf( pTmpRootFrm ? + pTmpRootFrm->GetCurrShell() : + 0, *pOut, 0, sTmp, 0, 1, 0, sal_False ); + nAktWidth = aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); + aArg.nWordWidth += nAktWidth; + aArg.nRowWidth += nAktWidth; + if( (long)rAbsMin < aArg.nWordWidth ) + rAbsMin = aArg.nWordWidth; + aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd ); + aArg.nNoLineBreak = nIdx++; + } + break; + case CH_TXTATR_BREAKWORD: + case CH_TXTATR_INWORD: + { + if( !pHint ) + break; + long nOldWidth = aArg.nWordWidth; + long nOldAdd = aArg.nWordAdd; + aArg.NewWord(); + + switch( pHint->Which() ) + { + case RES_TXTATR_FLYCNT : + { + SwFrmFmt *pFrmFmt = pHint->GetFlyCnt().GetFrmFmt(); + const SvxLRSpaceItem &rLR = pFrmFmt->GetLRSpace(); + if( RES_DRAWFRMFMT == pFrmFmt->Which() ) + { + const SdrObject* pSObj = pFrmFmt->FindSdrObject(); + if( pSObj ) + nAktWidth = pSObj->GetCurrentBoundRect().GetWidth(); + else + nAktWidth = 0; + } + else + { + const SwFmtFrmSize& rTmpSize = pFrmFmt->GetFrmSize(); + if( RES_FLYFRMFMT == pFrmFmt->Which() + && rTmpSize.GetWidthPercent() ) + { +/*-----------------24.01.97 14:09---------------------------------------------- + * Hier ein HACK fuer folgende Situation: In dem Absatz befindet sich + * ein Textrahmen mit relativer Groesse. Dann nehmen wir mal als minimale + * Breite 0,5 cm und als maximale KSHRT_MAX. + * Sauberer und vielleicht spaeter notwendig waere es, ueber den Inhalt + * des Textrahmens zu iterieren und GetMinMaxSize rekursiv zu rufen. + * --------------------------------------------------------------------------*/ + nAktWidth = FLYINCNT_MIN_WIDTH; // 0,5 cm + if( (long)rMax < KSHRT_MAX ) + rMax = KSHRT_MAX; + } + else + nAktWidth = pFrmFmt->GetFrmSize().GetWidth(); + } + nAktWidth += rLR.GetLeft(); + nAktWidth += rLR.GetRight(); + aArg.nWordAdd = nOldWidth + nOldAdd; + aArg.nWordWidth = nAktWidth; + aArg.nRowWidth += nAktWidth; + if( (long)rAbsMin < aArg.nWordWidth ) + rAbsMin = aArg.nWordWidth; + aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd ); + break; + } + case RES_TXTATR_FTN : + { + const XubString aTxt = pHint->GetFtn().GetNumStr(); + if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0, + aTxt.Len() ) ) + nAdd = 20; + break; + } + case RES_TXTATR_FIELD : + { + SwField *pFld = (SwField*)pHint->GetFld().GetFld(); + const String aTxt = pFld->GetCntnt( FALSE ); + if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0, + aTxt.Len() ) ) + nAdd = 20; + break; + } + default: aArg.nWordWidth = nOldWidth; + aArg.nWordAdd = nOldAdd; + + } + aIter.SeekAndChgAttrIter( ++nIdx, pOut ); + } + break; + } + } + if( (long)rMax < aArg.nRowWidth ) + rMax = aArg.nRowWidth; + + nLROffset += rSpace.GetRight(); + + rAbsMin += nLROffset; + rAbsMin += nAdd; + rMin += nLROffset; + rMin += nAdd; + if( (long)rMin < aNodeArgs.nMinWidth ) + rMin = aNodeArgs.nMinWidth; + if( (long)rAbsMin < aNodeArgs.nMinWidth ) + rAbsMin = aNodeArgs.nMinWidth; + rMax += aNodeArgs.nMaxWidth; + rMax += nLROffset; + rMax += nAdd; + if( rMax < rMin ) // z.B. Rahmen mit Durchlauf gehen zunaechst nur + rMax = rMin; // in das Minimum ein + pOut->SetMapMode( aOldMap ); +} + +/************************************************************************* + * SwTxtNode::GetScalingOfSelectedText() + * + * Calculates the width of the text part specified by nStt and nEnd, + * the height of the line containing nStt is devided by this width, + * indicating the scaling factor, if the text part is rotated. + * Having CH_BREAKs in the text part, this method returns the scaling + * factor for the longest of the text parts separated by the CH_BREAKs. + * + * changing this method very likely requires changing of "GetMinMaxSize" + *************************************************************************/ + +USHORT SwTxtNode::GetScalingOfSelectedText( xub_StrLen nStt, xub_StrLen nEnd ) + const +{ + ViewShell* pSh = NULL; + OutputDevice* pOut = NULL; + GetDoc()->GetEditShell( &pSh ); + + if ( pSh ) + pOut = &pSh->GetRefDev(); + else + { + //Zugriff ueber StarONE, es muss keine Shell existieren oder aktiv sein. + if ( getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) ) + pOut = GetpApp()->GetDefaultDevice(); + else + pOut = getIDocumentDeviceAccess()->getReferenceDevice( true ); + } + + ASSERT( pOut, "GetScalingOfSelectedText without outdev" ) + + MapMode aOldMap( pOut->GetMapMode() ); + pOut->SetMapMode( MapMode( MAP_TWIP ) ); + + if ( nStt == nEnd ) + { + if ( !pBreakIt->GetBreakIter().is() ) + return 100; + + SwScriptInfo aScriptInfo; + SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo ); + aIter.SeekAndChgAttrIter( nStt, pOut ); + + Boundary aBound = + pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), nStt, + pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ), + WordType::DICTIONARY_WORD, sal_True ); + + if ( nStt == aBound.startPos ) + { + // cursor is at left or right border of word + pOut->SetMapMode( aOldMap ); + return 100; + } + + nStt = (xub_StrLen)aBound.startPos; + nEnd = (xub_StrLen)aBound.endPos; + + if ( nStt == nEnd ) + { + pOut->SetMapMode( aOldMap ); + return 100; + } + } + + SwScriptInfo aScriptInfo; + SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo ); + + // We do not want scaling attributes to be considered during this + // calculation. For this, we push a temporary scaling attribute with + // scaling value 100 and priority flag on top of the scaling stack + SwAttrHandler& rAH = aIter.GetAttrHandler(); + SvxCharScaleWidthItem aItem(100, RES_CHRATR_SCALEW); + SwTxtAttrEnd aAttr( aItem, nStt, nEnd ); + aAttr.SetPriorityAttr( sal_True ); + rAH.PushAndChg( aAttr, *(aIter.GetFnt()) ); + + xub_StrLen nIdx = nStt; + + ULONG nWidth = 0; + ULONG nProWidth = 0; + + while( nIdx < nEnd ) + { + aIter.SeekAndChgAttrIter( nIdx, pOut ); + + // scan for end of portion + xub_StrLen nNextChg = aIter.GetNextAttr(); + xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx ); + if( nNextChg > nStop ) + nNextChg = nStop; + + nStop = nIdx; + xub_Unicode cChar = CH_BLANK; + SwTxtAttr* pHint = NULL; + + // stop at special characters in [ nIdx, nNextChg ] + while( nStop < nEnd && nStop < nNextChg ) + { + cChar = m_Text.GetChar( nStop ); + if( CH_TAB == cChar || CH_BREAK == cChar || + CHAR_HARDBLANK == cChar || CHAR_HARDHYPHEN == cChar || + CHAR_SOFTHYPHEN == cChar || + ( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar ) && + ( 0 == ( pHint = aIter.GetAttr( nStop ) ) ) ) + break; + else + ++nStop; + } + + // calculate text widths up to cChar + if ( nStop > nIdx ) + { + SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nIdx, nStop - nIdx ); + nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); + } + + nIdx = nStop; + aIter.SeekAndChgAttrIter( nIdx, pOut ); + + if ( cChar == CH_BREAK ) + { + nWidth = Max( nWidth, nProWidth ); + nProWidth = 0; + nIdx++; + } + else if ( cChar == CH_TAB ) + { + // tab receives width of one space + XubString sTmp( CH_BLANK ); + SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 ); + nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); + nIdx++; + } + else if ( cChar == CHAR_SOFTHYPHEN ) + ++nIdx; + else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN ) + { + XubString sTmp( cChar ); + SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 ); + nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); + nIdx++; + } + else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || CH_TXTATR_INWORD ) ) + { + switch( pHint->Which() ) + { + case RES_TXTATR_FTN : + { + const XubString aTxt = pHint->GetFtn().GetNumStr(); + SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() ); + + nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); + break; + } + case RES_TXTATR_FIELD : + { + SwField *pFld = (SwField*)pHint->GetFld().GetFld(); + const String aTxt = pFld->GetCntnt( FALSE ); + SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() ); + + nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); + break; + } + default: + { + // any suggestions for a default action? + } + } // end of switch + nIdx++; + } // end of while + } + + nWidth = Max( nWidth, nProWidth ); + + // search for a text frame this node belongs to + SwClientIter aClientIter( *(SwTxtNode*)this ); + SwClient* pLastFrm = aClientIter.GoStart(); + SwTxtFrm* pFrm = 0; + + while( pLastFrm ) + { + if ( pLastFrm->ISA( SwTxtFrm ) ) + { + SwTxtFrm* pTmpFrm = ( SwTxtFrm* )pLastFrm; + if ( pTmpFrm->GetOfst() <= nStt && + ( !pTmpFrm->GetFollow() || + pTmpFrm->GetFollow()->GetOfst() > nStt ) ) + { + pFrm = pTmpFrm; + break; + } + } + pLastFrm = ++aClientIter; + } + + // search for the line containing nStt + if ( pFrm && pFrm->HasPara() ) + { + SwTxtInfo aInf( pFrm ); + SwTxtIter aLine( pFrm, &aInf ); + aLine.CharToLine( nStt ); + pOut->SetMapMode( aOldMap ); + return (USHORT)( nWidth ? + ( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 ); + } + // no frame or no paragraph, we take the height of the character + // at nStt as line height + + aIter.SeekAndChgAttrIter( nStt, pOut ); + pOut->SetMapMode( aOldMap ); + + SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nStt, 1 ); + return (USHORT) + ( nWidth ? ((100 * aIter.GetFnt()->_GetTxtSize( aDrawInf ).Height()) / nWidth ) : 0 ); +} + +USHORT SwTxtNode::GetWidthOfLeadingTabs() const +{ + USHORT nRet = 0; + + xub_StrLen nIdx = 0; + sal_Unicode cCh; + + while ( nIdx < GetTxt().Len() && + ( '\t' == ( cCh = GetTxt().GetChar( nIdx ) ) || + ' ' == cCh ) ) + ++nIdx; + + if ( nIdx > 0 ) + { + SwPosition aPos( *this ); + aPos.nContent += nIdx; + + // Find the non-follow text frame: + SwClientIter aClientIter( (SwTxtNode&)*this ); + SwClient* pLastFrm = aClientIter.GoStart(); + + while( pLastFrm ) + { + // Only consider master frames: + if ( pLastFrm->ISA(SwTxtFrm) && + !static_cast<SwTxtFrm*>(pLastFrm)->IsFollow() ) + { + const SwTxtFrm* pFrm = static_cast<SwTxtFrm*>(pLastFrm); + SWRECTFN( pFrm ) + SwRect aRect; + pFrm->GetCharRect( aRect, aPos ); + nRet = (USHORT) + ( pFrm->IsRightToLeft() ? + (pFrm->*fnRect->fnGetPrtRight)() - (aRect.*fnRect->fnGetRight)() : + (aRect.*fnRect->fnGetLeft)() - (pFrm->*fnRect->fnGetPrtLeft)() ); + break; + } + pLastFrm = ++aClientIter; + } + } + + return nRet; +} |