merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / text / itratr.cxx
blob09be2bd79827f82e74b4d521bf672fe189f781a5
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: itratr.cxx,v $
10 * $Revision: 1.40 $
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"
35 #include <hintids.hxx>
36 #include <svx/charscaleitem.hxx>
37 #include <txtatr.hxx>
38 #include <sfx2/printer.hxx>
39 #include <svx/lrspitem.hxx>
40 #include <vcl/window.hxx>
41 #include <vcl/svapp.hxx>
42 #include <fmtanchr.hxx>
43 #include <fmtfsize.hxx>
44 #include <fmtornt.hxx>
45 #include <fmtflcnt.hxx>
46 #include <fmtcntnt.hxx>
47 #include <fmtftn.hxx>
48 #include <frmatr.hxx>
49 #include <frmfmt.hxx>
50 #include <fmtfld.hxx>
51 #include <doc.hxx>
52 #include <viewsh.hxx> // ViewShell
53 #include <rootfrm.hxx>
54 #include <docary.hxx>
55 #include <ndtxt.hxx>
56 #include <dcontact.hxx>
57 #include <fldbas.hxx> // SwField
58 #include <pam.hxx> // SwPosition (lcl_MinMaxNode)
59 #include <itratr.hxx>
60 #include <htmltbl.hxx>
61 #include <swtable.hxx>
62 #include <redlnitr.hxx>
63 #include <fmtsrnd.hxx>
64 #include <itrtxt.hxx>
65 #include <breakit.hxx>
66 #include <com/sun/star/i18n/WordType.hpp>
67 #include <com/sun/star/i18n/ScriptType.hdl>
69 using namespace ::com::sun::star::i18n;
70 using namespace ::com::sun::star;
72 /*************************************************************************
73 * SwAttrIter::Chg()
74 *************************************************************************/
76 void SwAttrIter::Chg( SwTxtAttr *pHt )
78 ASSERT( pHt && pFnt, "No attribute of font available for change");
79 if( pRedln && pRedln->IsOn() )
80 pRedln->ChangeTxtAttr( pFnt, *pHt, sal_True );
81 else
82 aAttrHandler.PushAndChg( *pHt, *pFnt );
83 nChgCnt++;
86 /*************************************************************************
87 * SwAttrIter::Rst()
88 *************************************************************************/
90 void SwAttrIter::Rst( SwTxtAttr *pHt )
92 ASSERT( pHt && pFnt, "No attribute of font available for reset");
93 // get top from stack after removing pHt
94 if( pRedln && pRedln->IsOn() )
95 pRedln->ChangeTxtAttr( pFnt, *pHt, sal_False );
96 else
97 aAttrHandler.PopAndChg( *pHt, *pFnt );
98 nChgCnt--;
101 /*************************************************************************
102 * virtual SwAttrIter::~SwAttrIter()
103 *************************************************************************/
105 SwAttrIter::~SwAttrIter()
107 delete pRedln;
108 delete pFnt;
111 /*************************************************************************
112 * SwAttrIter::GetAttr()
114 * Liefert fuer eine Position das Attribut, wenn das Attribut genau auf
115 * der Position nPos liegt und kein EndIndex besitzt.
116 * GetAttr() wird fuer Attribute benoetigt, die die Formatierung beeinflussen
117 * sollen, ohne dabei den Inhalt des Strings zu veraendern. Solche "entarteten"
118 * Attribute sind z.B. Felder (die expandierten Text bereit halten) und
119 * zeilengebundene Frames. Um Mehrdeutigkeiten zwischen verschiedenen
120 * solcher Attribute zu vermeiden, werden beim Anlegen eines Attributs
121 * an der Startposition ein Sonderzeichen in den String einfuegt.
122 * Der Formatierer stoesst auf das Sonderzeichen und holt sich per
123 * GetAttr() das entartete Attribut.
124 *************************************************************************/
126 SwTxtAttr *SwAttrIter::GetAttr( const xub_StrLen nPosition ) const
128 return (m_pTxtNode) ? m_pTxtNode->GetTxtAttrForCharAt(nPosition) : 0;
131 /*************************************************************************
132 * SwAttrIter::SeekAndChg()
133 *************************************************************************/
135 sal_Bool SwAttrIter::SeekAndChgAttrIter( const xub_StrLen nNewPos, OutputDevice* pOut )
137 sal_Bool bChg = nStartIndex && nNewPos == nPos ? pFnt->IsFntChg() : Seek( nNewPos );
138 if ( pLastOut != pOut )
140 pLastOut = pOut;
141 pFnt->SetFntChg( sal_True );
142 bChg = sal_True;
144 if( bChg )
146 // wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo
147 // des gewuenschten Fonts ...
148 if ( !nChgCnt && !nPropFont )
149 pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
150 aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
151 pFnt->ChgPhysFnt( pShell, *pOut );
153 return bChg;
156 sal_Bool SwAttrIter::IsSymbol( const xub_StrLen nNewPos )
158 Seek( nNewPos );
159 if ( !nChgCnt && !nPropFont )
160 pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
161 aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
162 return pFnt->IsSymbol( pShell );
165 /*************************************************************************
166 * SwAttrIter::SeekStartAndChg()
167 *************************************************************************/
169 sal_Bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const sal_Bool bParaFont )
171 if ( pRedln && pRedln->ExtOn() )
172 pRedln->LeaveExtend( *pFnt, 0 );
174 // reset font to its original state
175 aAttrHandler.Reset();
176 aAttrHandler.ResetFont( *pFnt );
178 nStartIndex = nEndIndex = nPos = nChgCnt = 0;
179 if( nPropFont )
180 pFnt->SetProportion( nPropFont );
181 if( pRedln )
183 pRedln->Clear( pFnt );
184 if( !bParaFont )
185 nChgCnt = nChgCnt + pRedln->Seek( *pFnt, 0, STRING_LEN );
186 else
187 pRedln->Reset();
190 if ( pHints && !bParaFont )
192 SwTxtAttr *pTxtAttr;
193 // Solange wir noch nicht am Ende des StartArrays angekommen sind &&
194 // das TextAttribut an Position 0 beginnt ...
195 while ( ( nStartIndex < pHints->GetStartCount() ) &&
196 !(*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()) )
198 // oeffne die TextAttribute
199 Chg( pTxtAttr );
200 nStartIndex++;
204 sal_Bool bChg = pFnt->IsFntChg();
205 if ( pLastOut != pOut )
207 pLastOut = pOut;
208 pFnt->SetFntChg( sal_True );
209 bChg = sal_True;
211 if( bChg )
213 // wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo
214 // des gewuenschten Fonts ...
215 if ( !nChgCnt && !nPropFont )
216 pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
217 aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
218 pFnt->ChgPhysFnt( pShell, *pOut );
220 return bChg;
223 /*************************************************************************
224 * SwAttrIter::SeekFwd()
225 *************************************************************************/
227 // AMA: Neuer AttrIter Nov 94
229 void SwAttrIter::SeekFwd( const xub_StrLen nNewPos )
231 SwTxtAttr *pTxtAttr;
233 if ( nStartIndex ) // wenn ueberhaupt schon Attribute geoeffnet wurden...
235 // Schliesse Attr, die z. Z. geoeffnet sind, vor nNewPos+1 aber enden.
237 // Solange wir noch nicht am Ende des EndArrays angekommen sind &&
238 // das TextAttribut vor oder an der neuen Position endet ...
239 while ( ( nEndIndex < pHints->GetEndCount() ) &&
240 (*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos))
242 // schliesse die TextAttribute, deren StartPos vor
243 // oder an der alten nPos lag, die z.Z. geoeffnet sind.
244 if (*pTxtAttr->GetStart() <= nPos) Rst( pTxtAttr );
245 nEndIndex++;
248 else // ueberlies die nicht geoeffneten Enden
250 while ( ( nEndIndex < pHints->GetEndCount() ) &&
251 (*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos))
253 nEndIndex++;
256 // Solange wir noch nicht am Ende des StartArrays angekommen sind &&
257 // das TextAttribut vor oder an der neuen Position beginnt ...
258 while ( ( nStartIndex < pHints->GetStartCount() ) &&
259 (*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()<=nNewPos))
261 // oeffne die TextAttribute, deren Ende hinter der neuen Position liegt
262 if ( *pTxtAttr->GetAnyEnd() > nNewPos ) Chg( pTxtAttr );
263 nStartIndex++;
268 /*************************************************************************
269 * SwAttrIter::Seek()
270 *************************************************************************/
272 sal_Bool SwAttrIter::Seek( const xub_StrLen nNewPos )
274 if ( pRedln && pRedln->ExtOn() )
275 pRedln->LeaveExtend( *pFnt, nNewPos );
277 if( pHints )
279 if( !nNewPos || nNewPos < nPos )
281 if( pRedln )
282 pRedln->Clear( NULL );
284 // reset font to its original state
285 aAttrHandler.Reset();
286 aAttrHandler.ResetFont( *pFnt );
288 if( nPropFont )
289 pFnt->SetProportion( nPropFont );
290 nStartIndex = nEndIndex = nPos = 0;
291 nChgCnt = 0;
293 // Achtung!
294 // resetting the font here makes it necessary to apply any
295 // changes for extended input directly to the font
296 if ( pRedln && pRedln->ExtOn() )
298 pRedln->UpdateExtFont( *pFnt );
299 ++nChgCnt;
302 SeekFwd( nNewPos );
305 pFnt->SetActual( SwScriptInfo::WhichFont( nNewPos, 0, pScriptInfo ) );
307 if( pRedln )
308 nChgCnt = nChgCnt + pRedln->Seek( *pFnt, nNewPos, nPos );
309 nPos = nNewPos;
311 if( nPropFont )
312 pFnt->SetProportion( nPropFont );
314 return pFnt->IsFntChg();
317 /*************************************************************************
318 * SwAttrIter::GetNextAttr()
319 *************************************************************************/
321 xub_StrLen SwAttrIter::GetNextAttr( ) const
323 xub_StrLen nNext = STRING_LEN;
324 if( pHints )
326 if (pHints->GetStartCount() > nStartIndex) // Gibt es noch Starts?
327 nNext = (*pHints->GetStart(nStartIndex)->GetStart());
328 if (pHints->GetEndCount() > nEndIndex) // Gibt es noch Enden?
330 xub_StrLen nNextEnd = (*pHints->GetEnd(nEndIndex)->GetAnyEnd());
331 if ( nNextEnd<nNext ) nNext = nNextEnd; // Wer ist naeher?
334 if (m_pTxtNode!=NULL) {
335 //TODO maybe use hints like FieldHints for this instead of looking at the text...
336 int l=(nNext<m_pTxtNode->Len()?nNext:m_pTxtNode->Len());
337 USHORT p=nPos;
338 const sal_Unicode *txt=m_pTxtNode->GetTxt().GetBuffer();
339 while(p<l && txt[p]!=CH_TXT_ATR_FIELDSTART && txt[p]!=CH_TXT_ATR_FIELDEND && txt[p]!=CH_TXT_ATR_FORMELEMENT) p++;
340 if ((p<l && p>nPos) || nNext<=p)
341 nNext=p;
342 else
343 nNext=p+1;
345 if( pRedln )
346 return pRedln->GetNextRedln( nNext );
347 return nNext;
350 #if OSL_DEBUG_LEVEL > 1
351 /*************************************************************************
352 * SwAttrIter::Dump()
353 *************************************************************************/
355 void SwAttrIter::Dump( SvStream &/*rOS*/ ) const
357 // Noch nicht an den neuen Attributiterator angepasst ...
360 #endif
362 class SwMinMaxArgs
364 public:
365 OutputDevice* pOut;
366 ViewShell* pSh;
367 ULONG &rMin;
368 ULONG &rMax;
369 ULONG &rAbsMin;
370 long nRowWidth;
371 long nWordWidth;
372 long nWordAdd;
373 xub_StrLen nNoLineBreak;
374 SwMinMaxArgs( OutputDevice* pOutI, ViewShell* pShI, ULONG& rMinI, ULONG &rMaxI, ULONG &rAbsI )
375 : pOut( pOutI ), pSh( pShI ), rMin( rMinI ), rMax( rMaxI ), rAbsMin( rAbsI )
376 { nRowWidth = nWordWidth = nWordAdd = 0; nNoLineBreak = STRING_LEN; }
377 void Minimum( long nNew ) { if( (long)rMin < nNew ) rMin = nNew; }
378 void NewWord() { nWordAdd = nWordWidth = 0; }
381 sal_Bool lcl_MinMaxString( SwMinMaxArgs& rArg, SwFont* pFnt, const XubString &rTxt,
382 xub_StrLen nIdx, xub_StrLen nEnd )
384 sal_Bool bRet = sal_False;
385 while( nIdx < nEnd )
387 xub_StrLen nStop = nIdx;
388 sal_Bool bClear;
389 LanguageType eLang = pFnt->GetLanguage();
390 if( pBreakIt->GetBreakIter().is() )
392 bClear = CH_BLANK == rTxt.GetChar( nStop );
393 Boundary aBndry( pBreakIt->GetBreakIter()->getWordBoundary( rTxt, nIdx,
394 pBreakIt->GetLocale( eLang ),
395 WordType::DICTIONARY_WORD, TRUE ) );
396 nStop = (xub_StrLen)aBndry.endPos;
397 if( nIdx <= aBndry.startPos && nIdx && nIdx-1 != rArg.nNoLineBreak )
398 rArg.NewWord();
399 if( nStop == nIdx )
400 ++nStop;
401 if( nStop > nEnd )
402 nStop = nEnd;
404 else
406 while( nStop < nEnd && CH_BLANK != rTxt.GetChar( nStop ) )
407 ++nStop;
408 bClear = nStop == nIdx;
409 if ( bClear )
411 rArg.NewWord();
412 while( nStop < nEnd && CH_BLANK == rTxt.GetChar( nStop ) )
413 ++nStop;
417 SwDrawTextInfo aDrawInf( rArg.pSh, *rArg.pOut, 0, rTxt, nIdx, nStop - nIdx );
418 long nAktWidth = pFnt->_GetTxtSize( aDrawInf ).Width();
419 rArg.nRowWidth += nAktWidth;
420 if( bClear )
421 rArg.NewWord();
422 else
424 rArg.nWordWidth += nAktWidth;
425 if( (long)rArg.rAbsMin < rArg.nWordWidth )
426 rArg.rAbsMin = rArg.nWordWidth;
427 rArg.Minimum( rArg.nWordWidth + rArg.nWordAdd );
428 bRet = sal_True;
430 nIdx = nStop;
432 return bRet;
435 sal_Bool SwTxtNode::IsSymbol( const xub_StrLen nBegin ) const
437 SwScriptInfo aScriptInfo;
438 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
439 aIter.Seek( nBegin );
440 const SwRootFrm* pTmpRootFrm = getIDocumentLayoutAccess()->GetRootFrm();
441 return aIter.GetFnt()->IsSymbol( pTmpRootFrm ?
442 pTmpRootFrm->GetCurrShell() :
443 0 );
446 class SwMinMaxNodeArgs
448 public:
449 ULONG nMaxWidth; // Summe aller Rahmenbreite
450 long nMinWidth; // Breitester Rahmen
451 long nLeftRest; // noch nicht von Rahmen ueberdeckter Platz im l. Rand
452 long nRightRest; // noch nicht von Rahmen ueberdeckter Platz im r. Rand
453 long nLeftDiff; // Min/Max-Differenz des Rahmens im linken Rand
454 long nRightDiff; // Min/Max-Differenz des Rahmens im rechten Rand
455 ULONG nIndx; // Indexnummer des Nodes
456 void Minimum( long nNew ) { if( nNew > nMinWidth ) nMinWidth = nNew; }
459 sal_Bool lcl_MinMaxNode( const SwFrmFmtPtr& rpNd, void* pArgs )
461 const SwFmtAnchor& rFmtA = ((SwFrmFmt*)rpNd)->GetAnchor();
463 bool bCalculate = false;
464 if (
465 (FLY_AT_CNTNT == rFmtA.GetAnchorId()) ||
466 (FLY_AUTO_CNTNT == rFmtA.GetAnchorId())
469 bCalculate = true;
472 if (bCalculate)
474 const SwMinMaxNodeArgs *pIn = (const SwMinMaxNodeArgs*)pArgs;
475 const SwPosition *pPos = rFmtA.GetCntntAnchor();
476 ASSERT(pPos && pIn, "Unexpected NULL arguments");
477 if (!pPos || !pIn || pIn->nIndx != pPos->nNode.GetIndex())
478 bCalculate = false;
481 if (bCalculate)
483 long nMin, nMax;
484 SwHTMLTableLayout *pLayout = 0;
485 MSHORT nWhich = ((SwFrmFmt*)rpNd)->Which();
486 if( RES_DRAWFRMFMT != nWhich )
488 // Enthaelt der Rahmen zu Beginn oder am Ende eine Tabelle?
489 const SwNodes& rNodes = static_cast<SwFrmFmt*>(rpNd)->GetDoc()->GetNodes();
490 const SwFmtCntnt& rFlyCntnt = ((SwFrmFmt*)rpNd)->GetCntnt();
491 ULONG nStt = rFlyCntnt.GetCntntIdx()->GetIndex();
492 SwTableNode* pTblNd = rNodes[nStt+1]->GetTableNode();
493 if( !pTblNd )
495 SwNode *pNd = rNodes[nStt];
496 pNd = rNodes[pNd->EndOfSectionIndex()-1];
497 if( pNd->IsEndNode() )
498 pTblNd = pNd->StartOfSectionNode()->GetTableNode();
501 if( pTblNd )
502 pLayout = pTblNd->GetTable().GetHTMLTableLayout();
505 const SwFmtHoriOrient& rOrient = ((SwFrmFmt*)rpNd)->GetHoriOrient();
506 sal_Int16 eHoriOri = rOrient.GetHoriOrient();
508 long nDiff;
509 if( pLayout )
511 nMin = pLayout->GetMin();
512 nMax = pLayout->GetMax();
513 nDiff = nMax - nMin;
515 else
517 if( RES_DRAWFRMFMT == nWhich )
519 const SdrObject* pSObj = rpNd->FindSdrObject();
520 if( pSObj )
521 nMin = pSObj->GetCurrentBoundRect().GetWidth();
522 else
523 nMin = 0;
526 else
528 const SwFmtFrmSize &rSz = ( (SwFrmFmt*)rpNd )->GetFrmSize();
529 nMin = rSz.GetWidth();
531 nMax = nMin;
532 nDiff = 0;
535 const SvxLRSpaceItem &rLR = ( (SwFrmFmt*)rpNd )->GetLRSpace();
536 nMin += rLR.GetLeft();
537 nMin += rLR.GetRight();
538 nMax += rLR.GetLeft();
539 nMax += rLR.GetRight();
541 if( SURROUND_THROUGHT == ((SwFrmFmt*)rpNd)->GetSurround().GetSurround() )
543 ( (SwMinMaxNodeArgs*)pArgs )->Minimum( nMin );
544 return sal_True;
547 // Rahmen, die recht bzw. links ausgerichtet sind, gehen nur
548 // teilweise in die Max-Berechnung ein, da der Rand schon berueck-
549 // sichtigt wird. Nur wenn die Rahmen in den Textkoerper ragen,
550 // wird dieser Teil hinzuaddiert.
551 switch( eHoriOri )
553 case text::HoriOrientation::RIGHT:
555 if( nDiff )
557 ((SwMinMaxNodeArgs*)pArgs)->nRightRest -=
558 ((SwMinMaxNodeArgs*)pArgs)->nRightDiff;
559 ((SwMinMaxNodeArgs*)pArgs)->nRightDiff = nDiff;
561 if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() )
563 if( ((SwMinMaxNodeArgs*)pArgs)->nRightRest > 0 )
564 ((SwMinMaxNodeArgs*)pArgs)->nRightRest = 0;
566 ((SwMinMaxNodeArgs*)pArgs)->nRightRest -= nMin;
567 break;
569 case text::HoriOrientation::LEFT:
571 if( nDiff )
573 ((SwMinMaxNodeArgs*)pArgs)->nLeftRest -=
574 ((SwMinMaxNodeArgs*)pArgs)->nLeftDiff;
575 ((SwMinMaxNodeArgs*)pArgs)->nLeftDiff = nDiff;
577 if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() &&
578 ((SwMinMaxNodeArgs*)pArgs)->nLeftRest < 0 )
579 ((SwMinMaxNodeArgs*)pArgs)->nLeftRest = 0;
580 ((SwMinMaxNodeArgs*)pArgs)->nLeftRest -= nMin;
581 break;
583 default:
585 ( (SwMinMaxNodeArgs*)pArgs )->nMaxWidth += nMax;
586 ( (SwMinMaxNodeArgs*)pArgs )->Minimum( nMin );
590 return sal_True;
593 #define FLYINCNT_MIN_WIDTH 284
595 // changing this method very likely requires changing of
596 // "GetScalingOfSelectedText"
597 void SwTxtNode::GetMinMaxSize( ULONG nIndex, ULONG& rMin, ULONG &rMax,
598 ULONG& rAbsMin, OutputDevice* pOut ) const
600 ViewShell* pSh = 0;
601 GetDoc()->GetEditShell( &pSh );
602 if( !pOut )
604 if( pSh )
605 pOut = pSh->GetWin();
606 if( !pOut )
607 pOut = GetpApp()->GetDefaultDevice();
610 MapMode aOldMap( pOut->GetMapMode() );
611 pOut->SetMapMode( MapMode( MAP_TWIP ) );
613 rMin = 0;
614 rMax = 0;
615 rAbsMin = 0;
617 const SvxLRSpaceItem &rSpace = GetSwAttrSet().GetLRSpace();
618 long nLROffset = rSpace.GetTxtLeft() + GetLeftMarginWithNum( sal_True );
619 short nFLOffs;
620 // Bei Numerierung ist ein neg. Erstzeileneinzug vermutlich
621 // bereits gefuellt...
622 if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset )
623 nLROffset = nFLOffs;
625 SwMinMaxNodeArgs aNodeArgs;
626 aNodeArgs.nMinWidth = 0;
627 aNodeArgs.nMaxWidth = 0;
628 aNodeArgs.nLeftRest = nLROffset;
629 aNodeArgs.nRightRest = rSpace.GetRight();
630 aNodeArgs.nLeftDiff = 0;
631 aNodeArgs.nRightDiff = 0;
632 if( nIndex )
634 SwSpzFrmFmts* pTmp = (SwSpzFrmFmts*)GetDoc()->GetSpzFrmFmts();
635 if( pTmp )
637 aNodeArgs.nIndx = nIndex;
638 pTmp->ForEach( &lcl_MinMaxNode, &aNodeArgs );
641 if( aNodeArgs.nLeftRest < 0 )
642 aNodeArgs.Minimum( nLROffset - aNodeArgs.nLeftRest );
643 aNodeArgs.nLeftRest -= aNodeArgs.nLeftDiff;
644 if( aNodeArgs.nLeftRest < 0 )
645 aNodeArgs.nMaxWidth -= aNodeArgs.nLeftRest;
647 if( aNodeArgs.nRightRest < 0 )
648 aNodeArgs.Minimum( rSpace.GetRight() - aNodeArgs.nRightRest );
649 aNodeArgs.nRightRest -= aNodeArgs.nRightDiff;
650 if( aNodeArgs.nRightRest < 0 )
651 aNodeArgs.nMaxWidth -= aNodeArgs.nRightRest;
653 SwScriptInfo aScriptInfo;
654 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
655 xub_StrLen nIdx = 0;
656 aIter.SeekAndChgAttrIter( nIdx, pOut );
657 xub_StrLen nLen = m_Text.Len();
658 long nAktWidth = 0;
659 MSHORT nAdd = 0;
660 SwMinMaxArgs aArg( pOut, pSh, rMin, rMax, rAbsMin );
661 while( nIdx < nLen )
663 xub_StrLen nNextChg = aIter.GetNextAttr();
664 xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
665 if( nNextChg > nStop )
666 nNextChg = nStop;
667 SwTxtAttr *pHint = NULL;
668 xub_Unicode cChar = CH_BLANK;
669 nStop = nIdx;
670 while( nStop < nLen && nStop < nNextChg &&
671 CH_TAB != ( cChar = m_Text.GetChar( nStop ) ) &&
672 CH_BREAK != cChar && CHAR_HARDBLANK != cChar &&
673 CHAR_HARDHYPHEN != cChar && CHAR_SOFTHYPHEN != cChar &&
674 !pHint )
676 if( ( CH_TXTATR_BREAKWORD != cChar && CH_TXTATR_INWORD != cChar )
677 || ( 0 == ( pHint = aIter.GetAttr( nStop ) ) ) )
678 ++nStop;
680 if ( lcl_MinMaxString( aArg, aIter.GetFnt(), m_Text, nIdx, nStop ) )
682 nAdd = 20;
684 nIdx = nStop;
685 aIter.SeekAndChgAttrIter( nIdx, pOut );
686 switch( cChar )
688 case CH_BREAK :
690 if( (long)rMax < aArg.nRowWidth )
691 rMax = aArg.nRowWidth;
692 aArg.nRowWidth = 0;
693 aArg.NewWord();
694 aIter.SeekAndChgAttrIter( ++nIdx, pOut );
696 break;
697 case CH_TAB :
699 aArg.NewWord();
700 aIter.SeekAndChgAttrIter( ++nIdx, pOut );
702 break;
703 case CHAR_SOFTHYPHEN:
704 ++nIdx;
705 break;
706 case CHAR_HARDBLANK:
707 case CHAR_HARDHYPHEN:
709 XubString sTmp( cChar );
710 const SwRootFrm* pTmpRootFrm = getIDocumentLayoutAccess()->GetRootFrm();
711 SwDrawTextInfo aDrawInf( pTmpRootFrm ?
712 pTmpRootFrm->GetCurrShell() :
713 0, *pOut, 0, sTmp, 0, 1, 0, sal_False );
714 nAktWidth = aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
715 aArg.nWordWidth += nAktWidth;
716 aArg.nRowWidth += nAktWidth;
717 if( (long)rAbsMin < aArg.nWordWidth )
718 rAbsMin = aArg.nWordWidth;
719 aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
720 aArg.nNoLineBreak = nIdx++;
722 break;
723 case CH_TXTATR_BREAKWORD:
724 case CH_TXTATR_INWORD:
726 if( !pHint )
727 break;
728 long nOldWidth = aArg.nWordWidth;
729 long nOldAdd = aArg.nWordAdd;
730 aArg.NewWord();
732 switch( pHint->Which() )
734 case RES_TXTATR_FLYCNT :
736 SwFrmFmt *pFrmFmt = pHint->GetFlyCnt().GetFrmFmt();
737 const SvxLRSpaceItem &rLR = pFrmFmt->GetLRSpace();
738 if( RES_DRAWFRMFMT == pFrmFmt->Which() )
740 const SdrObject* pSObj = pFrmFmt->FindSdrObject();
741 if( pSObj )
742 nAktWidth = pSObj->GetCurrentBoundRect().GetWidth();
743 else
744 nAktWidth = 0;
746 else
748 const SwFmtFrmSize& rTmpSize = pFrmFmt->GetFrmSize();
749 if( RES_FLYFRMFMT == pFrmFmt->Which()
750 && rTmpSize.GetWidthPercent() )
752 /*-----------------24.01.97 14:09----------------------------------------------
753 * Hier ein HACK fuer folgende Situation: In dem Absatz befindet sich
754 * ein Textrahmen mit relativer Groesse. Dann nehmen wir mal als minimale
755 * Breite 0,5 cm und als maximale KSHRT_MAX.
756 * Sauberer und vielleicht spaeter notwendig waere es, ueber den Inhalt
757 * des Textrahmens zu iterieren und GetMinMaxSize rekursiv zu rufen.
758 * --------------------------------------------------------------------------*/
759 nAktWidth = FLYINCNT_MIN_WIDTH; // 0,5 cm
760 if( (long)rMax < KSHRT_MAX )
761 rMax = KSHRT_MAX;
763 else
764 nAktWidth = pFrmFmt->GetFrmSize().GetWidth();
766 nAktWidth += rLR.GetLeft();
767 nAktWidth += rLR.GetRight();
768 aArg.nWordAdd = nOldWidth + nOldAdd;
769 aArg.nWordWidth = nAktWidth;
770 aArg.nRowWidth += nAktWidth;
771 if( (long)rAbsMin < aArg.nWordWidth )
772 rAbsMin = aArg.nWordWidth;
773 aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
774 break;
776 case RES_TXTATR_FTN :
778 const XubString aTxt = pHint->GetFtn().GetNumStr();
779 if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0,
780 aTxt.Len() ) )
781 nAdd = 20;
782 break;
784 case RES_TXTATR_FIELD :
786 SwField *pFld = (SwField*)pHint->GetFld().GetFld();
787 const String aTxt = pFld->GetCntnt( FALSE );
788 if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0,
789 aTxt.Len() ) )
790 nAdd = 20;
791 break;
793 default: aArg.nWordWidth = nOldWidth;
794 aArg.nWordAdd = nOldAdd;
797 aIter.SeekAndChgAttrIter( ++nIdx, pOut );
799 break;
802 if( (long)rMax < aArg.nRowWidth )
803 rMax = aArg.nRowWidth;
805 nLROffset += rSpace.GetRight();
807 rAbsMin += nLROffset;
808 rAbsMin += nAdd;
809 rMin += nLROffset;
810 rMin += nAdd;
811 if( (long)rMin < aNodeArgs.nMinWidth )
812 rMin = aNodeArgs.nMinWidth;
813 if( (long)rAbsMin < aNodeArgs.nMinWidth )
814 rAbsMin = aNodeArgs.nMinWidth;
815 rMax += aNodeArgs.nMaxWidth;
816 rMax += nLROffset;
817 rMax += nAdd;
818 if( rMax < rMin ) // z.B. Rahmen mit Durchlauf gehen zunaechst nur
819 rMax = rMin; // in das Minimum ein
820 pOut->SetMapMode( aOldMap );
823 /*************************************************************************
824 * SwTxtNode::GetScalingOfSelectedText()
826 * Calculates the width of the text part specified by nStt and nEnd,
827 * the height of the line containing nStt is devided by this width,
828 * indicating the scaling factor, if the text part is rotated.
829 * Having CH_BREAKs in the text part, this method returns the scaling
830 * factor for the longest of the text parts separated by the CH_BREAKs.
832 * changing this method very likely requires changing of "GetMinMaxSize"
833 *************************************************************************/
835 USHORT SwTxtNode::GetScalingOfSelectedText( xub_StrLen nStt, xub_StrLen nEnd )
836 const
838 ViewShell* pSh = NULL;
839 OutputDevice* pOut = NULL;
840 GetDoc()->GetEditShell( &pSh );
842 if ( pSh )
843 pOut = &pSh->GetRefDev();
844 else
846 //Zugriff ueber StarONE, es muss keine Shell existieren oder aktiv sein.
847 if ( getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) )
848 pOut = GetpApp()->GetDefaultDevice();
849 else
850 pOut = getIDocumentDeviceAccess()->getReferenceDevice( true );
853 ASSERT( pOut, "GetScalingOfSelectedText without outdev" )
855 MapMode aOldMap( pOut->GetMapMode() );
856 pOut->SetMapMode( MapMode( MAP_TWIP ) );
858 if ( nStt == nEnd )
860 if ( !pBreakIt->GetBreakIter().is() )
861 return 100;
863 SwScriptInfo aScriptInfo;
864 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
865 aIter.SeekAndChgAttrIter( nStt, pOut );
867 Boundary aBound =
868 pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), nStt,
869 pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ),
870 WordType::DICTIONARY_WORD, sal_True );
872 if ( nStt == aBound.startPos )
874 // cursor is at left or right border of word
875 pOut->SetMapMode( aOldMap );
876 return 100;
879 nStt = (xub_StrLen)aBound.startPos;
880 nEnd = (xub_StrLen)aBound.endPos;
882 if ( nStt == nEnd )
884 pOut->SetMapMode( aOldMap );
885 return 100;
889 SwScriptInfo aScriptInfo;
890 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
892 // We do not want scaling attributes to be considered during this
893 // calculation. For this, we push a temporary scaling attribute with
894 // scaling value 100 and priority flag on top of the scaling stack
895 SwAttrHandler& rAH = aIter.GetAttrHandler();
896 SvxCharScaleWidthItem aItem(100, RES_CHRATR_SCALEW);
897 SwTxtAttrEnd aAttr( aItem, nStt, nEnd );
898 aAttr.SetPriorityAttr( sal_True );
899 rAH.PushAndChg( aAttr, *(aIter.GetFnt()) );
901 xub_StrLen nIdx = nStt;
903 ULONG nWidth = 0;
904 ULONG nProWidth = 0;
906 while( nIdx < nEnd )
908 aIter.SeekAndChgAttrIter( nIdx, pOut );
910 // scan for end of portion
911 xub_StrLen nNextChg = aIter.GetNextAttr();
912 xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
913 if( nNextChg > nStop )
914 nNextChg = nStop;
916 nStop = nIdx;
917 xub_Unicode cChar = CH_BLANK;
918 SwTxtAttr* pHint = NULL;
920 // stop at special characters in [ nIdx, nNextChg ]
921 while( nStop < nEnd && nStop < nNextChg )
923 cChar = m_Text.GetChar( nStop );
924 if( CH_TAB == cChar || CH_BREAK == cChar ||
925 CHAR_HARDBLANK == cChar || CHAR_HARDHYPHEN == cChar ||
926 CHAR_SOFTHYPHEN == cChar ||
927 ( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar ) &&
928 ( 0 == ( pHint = aIter.GetAttr( nStop ) ) ) )
929 break;
930 else
931 ++nStop;
934 // calculate text widths up to cChar
935 if ( nStop > nIdx )
937 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nIdx, nStop - nIdx );
938 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
941 nIdx = nStop;
942 aIter.SeekAndChgAttrIter( nIdx, pOut );
944 if ( cChar == CH_BREAK )
946 nWidth = Max( nWidth, nProWidth );
947 nProWidth = 0;
948 nIdx++;
950 else if ( cChar == CH_TAB )
952 // tab receives width of one space
953 XubString sTmp( CH_BLANK );
954 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
955 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
956 nIdx++;
958 else if ( cChar == CHAR_SOFTHYPHEN )
959 ++nIdx;
960 else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN )
962 XubString sTmp( cChar );
963 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
964 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
965 nIdx++;
967 else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || CH_TXTATR_INWORD ) )
969 switch( pHint->Which() )
971 case RES_TXTATR_FTN :
973 const XubString aTxt = pHint->GetFtn().GetNumStr();
974 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
976 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
977 break;
979 case RES_TXTATR_FIELD :
981 SwField *pFld = (SwField*)pHint->GetFld().GetFld();
982 const String aTxt = pFld->GetCntnt( FALSE );
983 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
985 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
986 break;
988 default:
990 // any suggestions for a default action?
992 } // end of switch
993 nIdx++;
994 } // end of while
997 nWidth = Max( nWidth, nProWidth );
999 // search for a text frame this node belongs to
1000 SwClientIter aClientIter( *(SwTxtNode*)this );
1001 SwClient* pLastFrm = aClientIter.GoStart();
1002 SwTxtFrm* pFrm = 0;
1004 while( pLastFrm )
1006 if ( pLastFrm->ISA( SwTxtFrm ) )
1008 SwTxtFrm* pTmpFrm = ( SwTxtFrm* )pLastFrm;
1009 if ( pTmpFrm->GetOfst() <= nStt &&
1010 ( !pTmpFrm->GetFollow() ||
1011 pTmpFrm->GetFollow()->GetOfst() > nStt ) )
1013 pFrm = pTmpFrm;
1014 break;
1017 pLastFrm = ++aClientIter;
1020 // search for the line containing nStt
1021 if ( pFrm && pFrm->HasPara() )
1023 SwTxtInfo aInf( pFrm );
1024 SwTxtIter aLine( pFrm, &aInf );
1025 aLine.CharToLine( nStt );
1026 pOut->SetMapMode( aOldMap );
1027 return (USHORT)( nWidth ?
1028 ( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 );
1030 // no frame or no paragraph, we take the height of the character
1031 // at nStt as line height
1033 aIter.SeekAndChgAttrIter( nStt, pOut );
1034 pOut->SetMapMode( aOldMap );
1036 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nStt, 1 );
1037 return (USHORT)
1038 ( nWidth ? ((100 * aIter.GetFnt()->_GetTxtSize( aDrawInf ).Height()) / nWidth ) : 0 );
1041 USHORT SwTxtNode::GetWidthOfLeadingTabs() const
1043 USHORT nRet = 0;
1045 xub_StrLen nIdx = 0;
1046 sal_Unicode cCh;
1048 while ( nIdx < GetTxt().Len() &&
1049 ( '\t' == ( cCh = GetTxt().GetChar( nIdx ) ) ||
1050 ' ' == cCh ) )
1051 ++nIdx;
1053 if ( nIdx > 0 )
1055 SwPosition aPos( *this );
1056 aPos.nContent += nIdx;
1058 // Find the non-follow text frame:
1059 SwClientIter aClientIter( (SwTxtNode&)*this );
1060 SwClient* pLastFrm = aClientIter.GoStart();
1062 while( pLastFrm )
1064 // Only consider master frames:
1065 if ( pLastFrm->ISA(SwTxtFrm) &&
1066 !static_cast<SwTxtFrm*>(pLastFrm)->IsFollow() )
1068 const SwTxtFrm* pFrm = static_cast<SwTxtFrm*>(pLastFrm);
1069 SWRECTFN( pFrm )
1070 SwRect aRect;
1071 pFrm->GetCharRect( aRect, aPos );
1072 nRet = (USHORT)
1073 ( pFrm->IsRightToLeft() ?
1074 (pFrm->*fnRect->fnGetPrtRight)() - (aRect.*fnRect->fnGetRight)() :
1075 (aRect.*fnRect->fnGetLeft)() - (pFrm->*fnRect->fnGetPrtLeft)() );
1076 break;
1078 pLastFrm = ++aClientIter;
1082 return nRet;