Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / sw / source / core / text / itratr.cxx
blob084df86e81fc324437250f539801007b9944a9ca
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <hintids.hxx>
21 #include <editeng/charscaleitem.hxx>
22 #include <txtatr.hxx>
23 #include <sfx2/printer.hxx>
24 #include <svx/svdobj.hxx>
25 #include <vcl/window.hxx>
26 #include <vcl/svapp.hxx>
27 #include <fmtanchr.hxx>
28 #include <fmtfsize.hxx>
29 #include <fmtornt.hxx>
30 #include <fmtflcnt.hxx>
31 #include <fmtcntnt.hxx>
32 #include <fmtftn.hxx>
33 #include <frmatr.hxx>
34 #include <frmfmt.hxx>
35 #include <fmtfld.hxx>
36 #include <doc.hxx>
37 #include <viewsh.hxx> // ViewShell
38 #include <rootfrm.hxx>
39 #include <docary.hxx>
40 #include <ndtxt.hxx>
41 #include <dcontact.hxx>
42 #include <fldbas.hxx> // SwField
43 #include <pam.hxx> // SwPosition (lcl_MinMaxNode)
44 #include <itratr.hxx>
45 #include <htmltbl.hxx>
46 #include <swtable.hxx>
47 #include <redlnitr.hxx>
48 #include <fmtsrnd.hxx>
49 #include <itrtxt.hxx>
50 #include <breakit.hxx>
51 #include <com/sun/star/i18n/WordType.hpp>
52 #include <com/sun/star/i18n/ScriptType.hpp>
53 #include <editeng/lrspitem.hxx>
54 #include <switerator.hxx>
55 #include <boost/foreach.hpp>
57 using namespace ::com::sun::star::i18n;
58 using namespace ::com::sun::star;
60 /*************************************************************************
61 * SwAttrIter::Chg()
62 *************************************************************************/
64 void SwAttrIter::Chg( SwTxtAttr *pHt )
66 OSL_ENSURE( pHt && pFnt, "No attribute of font available for change");
67 if( pRedln && pRedln->IsOn() )
68 pRedln->ChangeTxtAttr( pFnt, *pHt, sal_True );
69 else
70 aAttrHandler.PushAndChg( *pHt, *pFnt );
71 nChgCnt++;
74 /*************************************************************************
75 * SwAttrIter::Rst()
76 *************************************************************************/
78 void SwAttrIter::Rst( SwTxtAttr *pHt )
80 OSL_ENSURE( pHt && pFnt, "No attribute of font available for reset");
81 // get top from stack after removing pHt
82 if( pRedln && pRedln->IsOn() )
83 pRedln->ChangeTxtAttr( pFnt, *pHt, sal_False );
84 else
85 aAttrHandler.PopAndChg( *pHt, *pFnt );
86 nChgCnt--;
89 /*************************************************************************
90 * virtual SwAttrIter::~SwAttrIter()
91 *************************************************************************/
93 SwAttrIter::~SwAttrIter()
95 delete pRedln;
96 delete pFnt;
99 /*************************************************************************
100 * SwAttrIter::GetAttr()
102 * Liefert fuer eine Position das Attribut, wenn das Attribut genau auf
103 * der Position nPos liegt und kein EndIndex besitzt.
104 * GetAttr() wird fuer Attribute benoetigt, die die Formatierung beeinflussen
105 * sollen, ohne dabei den Inhalt des Strings zu veraendern. Solche "entarteten"
106 * Attribute sind z.B. Felder (die expandierten Text bereit halten) und
107 * zeilengebundene Frames. Um Mehrdeutigkeiten zwischen verschiedenen
108 * solcher Attribute zu vermeiden, werden beim Anlegen eines Attributs
109 * an der Startposition ein Sonderzeichen in den String einfuegt.
110 * Der Formatierer stoesst auf das Sonderzeichen und holt sich per
111 * GetAttr() das entartete Attribut.
112 *************************************************************************/
114 SwTxtAttr *SwAttrIter::GetAttr( const xub_StrLen nPosition ) const
116 return (m_pTxtNode) ? m_pTxtNode->GetTxtAttrForCharAt(nPosition) : 0;
119 /*************************************************************************
120 * SwAttrIter::SeekAndChg()
121 *************************************************************************/
123 sal_Bool SwAttrIter::SeekAndChgAttrIter( const xub_StrLen nNewPos, OutputDevice* pOut )
125 sal_Bool bChg = nStartIndex && nNewPos == nPos ? pFnt->IsFntChg() : Seek( nNewPos );
126 if ( pLastOut != pOut )
128 pLastOut = pOut;
129 pFnt->SetFntChg( sal_True );
130 bChg = sal_True;
132 if( bChg )
134 // wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo
135 // des gewuenschten Fonts ...
136 if ( !nChgCnt && !nPropFont )
137 pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
138 aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
139 pFnt->ChgPhysFnt( pShell, *pOut );
141 return bChg;
144 sal_Bool SwAttrIter::IsSymbol( const xub_StrLen nNewPos )
146 Seek( nNewPos );
147 if ( !nChgCnt && !nPropFont )
148 pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
149 aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
150 return pFnt->IsSymbol( pShell );
153 /*************************************************************************
154 * SwAttrIter::SeekStartAndChg()
155 *************************************************************************/
157 sal_Bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const sal_Bool bParaFont )
159 if ( pRedln && pRedln->ExtOn() )
160 pRedln->LeaveExtend( *pFnt, 0 );
162 // reset font to its original state
163 aAttrHandler.Reset();
164 aAttrHandler.ResetFont( *pFnt );
166 nStartIndex = nEndIndex = nPos = nChgCnt = 0;
167 if( nPropFont )
168 pFnt->SetProportion( nPropFont );
169 if( pRedln )
171 pRedln->Clear( pFnt );
172 if( !bParaFont )
173 nChgCnt = nChgCnt + pRedln->Seek( *pFnt, 0, STRING_LEN );
174 else
175 pRedln->Reset();
178 if ( pHints && !bParaFont )
180 SwTxtAttr *pTxtAttr;
181 // Solange wir noch nicht am Ende des StartArrays angekommen sind &&
182 // das TextAttribut an Position 0 beginnt ...
183 while ( ( nStartIndex < pHints->GetStartCount() ) &&
184 !(*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()) )
186 // oeffne die TextAttribute
187 Chg( pTxtAttr );
188 nStartIndex++;
192 sal_Bool bChg = pFnt->IsFntChg();
193 if ( pLastOut != pOut )
195 pLastOut = pOut;
196 pFnt->SetFntChg( sal_True );
197 bChg = sal_True;
199 if( bChg )
201 // wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo
202 // des gewuenschten Fonts ...
203 if ( !nChgCnt && !nPropFont )
204 pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
205 aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
206 pFnt->ChgPhysFnt( pShell, *pOut );
208 return bChg;
211 /*************************************************************************
212 * SwAttrIter::SeekFwd()
213 *************************************************************************/
215 // AMA: Neuer AttrIter Nov 94
217 void SwAttrIter::SeekFwd( const xub_StrLen nNewPos )
219 SwTxtAttr *pTxtAttr;
221 if ( nStartIndex ) // wenn ueberhaupt schon Attribute geoeffnet wurden...
223 // Schliesse Attr, die z. Z. geoeffnet sind, vor nNewPos+1 aber enden.
225 // Solange wir noch nicht am Ende des EndArrays angekommen sind &&
226 // das TextAttribut vor oder an der neuen Position endet ...
227 while ( ( nEndIndex < pHints->GetEndCount() ) &&
228 (*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos))
230 // schliesse die TextAttribute, deren StartPos vor
231 // oder an der alten nPos lag, die z.Z. geoeffnet sind.
232 if (*pTxtAttr->GetStart() <= nPos) Rst( pTxtAttr );
233 nEndIndex++;
236 else // ueberlies die nicht geoeffneten Enden
238 while ( ( nEndIndex < pHints->GetEndCount() ) &&
239 (*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos))
241 nEndIndex++;
244 // Solange wir noch nicht am Ende des StartArrays angekommen sind &&
245 // das TextAttribut vor oder an der neuen Position beginnt ...
246 while ( ( nStartIndex < pHints->GetStartCount() ) &&
247 (*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()<=nNewPos))
249 // oeffne die TextAttribute, deren Ende hinter der neuen Position liegt
250 if ( *pTxtAttr->GetAnyEnd() > nNewPos ) Chg( pTxtAttr );
251 nStartIndex++;
256 /*************************************************************************
257 * SwAttrIter::Seek()
258 *************************************************************************/
260 sal_Bool SwAttrIter::Seek( const xub_StrLen nNewPos )
262 if ( pRedln && pRedln->ExtOn() )
263 pRedln->LeaveExtend( *pFnt, nNewPos );
265 if( pHints )
267 if( !nNewPos || nNewPos < nPos )
269 if( pRedln )
270 pRedln->Clear( NULL );
272 // reset font to its original state
273 aAttrHandler.Reset();
274 aAttrHandler.ResetFont( *pFnt );
276 if( nPropFont )
277 pFnt->SetProportion( nPropFont );
278 nStartIndex = nEndIndex = nPos = 0;
279 nChgCnt = 0;
281 // Achtung!
282 // resetting the font here makes it necessary to apply any
283 // changes for extended input directly to the font
284 if ( pRedln && pRedln->ExtOn() )
286 pRedln->UpdateExtFont( *pFnt );
287 ++nChgCnt;
290 SeekFwd( nNewPos );
293 pFnt->SetActual( SwScriptInfo::WhichFont( nNewPos, 0, pScriptInfo ) );
295 if( pRedln )
296 nChgCnt = nChgCnt + pRedln->Seek( *pFnt, nNewPos, nPos );
297 nPos = nNewPos;
299 if( nPropFont )
300 pFnt->SetProportion( nPropFont );
302 return pFnt->IsFntChg();
305 /*************************************************************************
306 * SwAttrIter::GetNextAttr()
307 *************************************************************************/
309 xub_StrLen SwAttrIter::GetNextAttr( ) const
311 xub_StrLen nNext = STRING_LEN;
312 if( pHints )
314 if (pHints->GetStartCount() > nStartIndex) // Gibt es noch Starts?
315 nNext = (*pHints->GetStart(nStartIndex)->GetStart());
316 if (pHints->GetEndCount() > nEndIndex) // Gibt es noch Enden?
318 xub_StrLen nNextEnd = (*pHints->GetEnd(nEndIndex)->GetAnyEnd());
319 if ( nNextEnd<nNext ) nNext = nNextEnd; // Wer ist naeher?
322 if (m_pTxtNode!=NULL) {
323 //TODO maybe use hints like FieldHints for this instead of looking at the text...
324 int l=(nNext<m_pTxtNode->Len()?nNext:m_pTxtNode->Len());
325 sal_uInt16 p=nPos;
326 const sal_Unicode *txt=m_pTxtNode->GetTxt().GetBuffer();
327 while(p<l && txt[p]!=CH_TXT_ATR_FIELDSTART && txt[p]!=CH_TXT_ATR_FIELDEND && txt[p]!=CH_TXT_ATR_FORMELEMENT) p++;
328 if ((p<l && p>nPos) || nNext<=p)
329 nNext=p;
330 else
331 nNext=p+1;
333 if( pRedln )
334 return pRedln->GetNextRedln( nNext );
335 return nNext;
338 class SwMinMaxArgs
340 public:
341 OutputDevice* pOut;
342 ViewShell* pSh;
343 sal_uLong &rMin;
344 sal_uLong &rMax;
345 sal_uLong &rAbsMin;
346 long nRowWidth;
347 long nWordWidth;
348 long nWordAdd;
349 xub_StrLen nNoLineBreak;
350 SwMinMaxArgs( OutputDevice* pOutI, ViewShell* pShI, sal_uLong& rMinI, sal_uLong &rMaxI, sal_uLong &rAbsI )
351 : pOut( pOutI ), pSh( pShI ), rMin( rMinI ), rMax( rMaxI ), rAbsMin( rAbsI )
352 { nRowWidth = nWordWidth = nWordAdd = 0; nNoLineBreak = STRING_LEN; }
353 void Minimum( long nNew ) const { if( (long)rMin < nNew ) rMin = nNew; }
354 void NewWord() { nWordAdd = nWordWidth = 0; }
357 static sal_Bool lcl_MinMaxString( SwMinMaxArgs& rArg, SwFont* pFnt, const XubString &rTxt,
358 xub_StrLen nIdx, xub_StrLen nEnd )
360 sal_Bool bRet = sal_False;
361 while( nIdx < nEnd )
363 xub_StrLen nStop = nIdx;
364 sal_Bool bClear;
365 LanguageType eLang = pFnt->GetLanguage();
366 if( pBreakIt->GetBreakIter().is() )
368 bClear = CH_BLANK == rTxt.GetChar( nStop );
369 Boundary aBndry( pBreakIt->GetBreakIter()->getWordBoundary( rTxt, nIdx,
370 pBreakIt->GetLocale( eLang ),
371 WordType::DICTIONARY_WORD, sal_True ) );
372 nStop = (xub_StrLen)aBndry.endPos;
373 if( nIdx <= aBndry.startPos && nIdx && nIdx-1 != rArg.nNoLineBreak )
374 rArg.NewWord();
375 if( nStop == nIdx )
376 ++nStop;
377 if( nStop > nEnd )
378 nStop = nEnd;
380 else
382 while( nStop < nEnd && CH_BLANK != rTxt.GetChar( nStop ) )
383 ++nStop;
384 bClear = nStop == nIdx;
385 if ( bClear )
387 rArg.NewWord();
388 while( nStop < nEnd && CH_BLANK == rTxt.GetChar( nStop ) )
389 ++nStop;
393 SwDrawTextInfo aDrawInf( rArg.pSh, *rArg.pOut, 0, rTxt, nIdx, nStop - nIdx );
394 long nAktWidth = pFnt->_GetTxtSize( aDrawInf ).Width();
395 rArg.nRowWidth += nAktWidth;
396 if( bClear )
397 rArg.NewWord();
398 else
400 rArg.nWordWidth += nAktWidth;
401 if( (long)rArg.rAbsMin < rArg.nWordWidth )
402 rArg.rAbsMin = rArg.nWordWidth;
403 rArg.Minimum( rArg.nWordWidth + rArg.nWordAdd );
404 bRet = sal_True;
406 nIdx = nStop;
408 return bRet;
411 sal_Bool SwTxtNode::IsSymbol( const xub_StrLen nBegin ) const//swmodtest 080307
413 SwScriptInfo aScriptInfo;
414 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
415 aIter.Seek( nBegin );
416 return aIter.GetFnt()->IsSymbol(
417 const_cast<ViewShell *>(getIDocumentLayoutAccess()->GetCurrentViewShell()) );//swmod 080311
420 class SwMinMaxNodeArgs
422 public:
423 sal_uLong nMaxWidth; // Summe aller Rahmenbreite
424 long nMinWidth; // Breitester Rahmen
425 long nLeftRest; // noch nicht von Rahmen ueberdeckter Platz im l. Rand
426 long nRightRest; // noch nicht von Rahmen ueberdeckter Platz im r. Rand
427 long nLeftDiff; // Min/Max-Differenz des Rahmens im linken Rand
428 long nRightDiff; // Min/Max-Differenz des Rahmens im rechten Rand
429 sal_uLong nIndx; // Indexnummer des Nodes
430 void Minimum( long nNew ) { if( nNew > nMinWidth ) nMinWidth = nNew; }
433 static void lcl_MinMaxNode( SwFrmFmt* pNd, SwMinMaxNodeArgs* pIn )
435 const SwFmtAnchor& rFmtA = pNd->GetAnchor();
437 bool bCalculate = false;
438 if ((FLY_AT_PARA == rFmtA.GetAnchorId()) ||
439 (FLY_AT_CHAR == rFmtA.GetAnchorId()))
441 bCalculate = true;
444 if (bCalculate)
446 const SwPosition *pPos = rFmtA.GetCntntAnchor();
447 OSL_ENSURE(pPos && pIn, "Unexpected NULL arguments");
448 if (!pPos || !pIn || pIn->nIndx != pPos->nNode.GetIndex())
449 bCalculate = false;
452 if (bCalculate)
454 long nMin, nMax;
455 SwHTMLTableLayout *pLayout = 0;
456 MSHORT nWhich = pNd->Which();
457 if( RES_DRAWFRMFMT != nWhich )
459 // Enthaelt der Rahmen zu Beginn oder am Ende eine Tabelle?
460 const SwNodes& rNodes = pNd->GetDoc()->GetNodes();
461 const SwFmtCntnt& rFlyCntnt = pNd->GetCntnt();
462 sal_uLong nStt = rFlyCntnt.GetCntntIdx()->GetIndex();
463 SwTableNode* pTblNd = rNodes[nStt+1]->GetTableNode();
464 if( !pTblNd )
466 SwNode *pNd2 = rNodes[nStt];
467 pNd2 = rNodes[pNd2->EndOfSectionIndex()-1];
468 if( pNd2->IsEndNode() )
469 pTblNd = pNd2->StartOfSectionNode()->GetTableNode();
472 if( pTblNd )
473 pLayout = pTblNd->GetTable().GetHTMLTableLayout();
476 const SwFmtHoriOrient& rOrient = pNd->GetHoriOrient();
477 sal_Int16 eHoriOri = rOrient.GetHoriOrient();
479 long nDiff;
480 if( pLayout )
482 nMin = pLayout->GetMin();
483 nMax = pLayout->GetMax();
484 nDiff = nMax - nMin;
486 else
488 if( RES_DRAWFRMFMT == nWhich )
490 const SdrObject* pSObj = pNd->FindSdrObject();
491 if( pSObj )
492 nMin = pSObj->GetCurrentBoundRect().GetWidth();
493 else
494 nMin = 0;
497 else
499 const SwFmtFrmSize &rSz = pNd->GetFrmSize();
500 nMin = rSz.GetWidth();
502 nMax = nMin;
503 nDiff = 0;
506 const SvxLRSpaceItem &rLR = pNd->GetLRSpace();
507 nMin += rLR.GetLeft();
508 nMin += rLR.GetRight();
509 nMax += rLR.GetLeft();
510 nMax += rLR.GetRight();
512 if( SURROUND_THROUGHT == pNd->GetSurround().GetSurround() )
514 pIn->Minimum( nMin );
515 return;
518 // Rahmen, die recht bzw. links ausgerichtet sind, gehen nur
519 // teilweise in die Max-Berechnung ein, da der Rand schon berueck-
520 // sichtigt wird. Nur wenn die Rahmen in den Textkoerper ragen,
521 // wird dieser Teil hinzuaddiert.
522 switch( eHoriOri )
524 case text::HoriOrientation::RIGHT:
526 if( nDiff )
528 pIn->nRightRest -= pIn->nRightDiff;
529 pIn->nRightDiff = nDiff;
531 if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() )
533 if( pIn->nRightRest > 0 )
534 pIn->nRightRest = 0;
536 pIn->nRightRest -= nMin;
537 break;
539 case text::HoriOrientation::LEFT:
541 if( nDiff )
543 pIn->nLeftRest -= pIn->nLeftDiff;
544 pIn->nLeftDiff = nDiff;
546 if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() &&
547 pIn->nLeftRest < 0 )
548 pIn->nLeftRest = 0;
549 pIn->nLeftRest -= nMin;
550 break;
552 default:
554 pIn->nMaxWidth += nMax;
555 pIn->Minimum( nMin );
561 #define FLYINCNT_MIN_WIDTH 284
563 // changing this method very likely requires changing of
564 // "GetScalingOfSelectedText"
565 void SwTxtNode::GetMinMaxSize( sal_uLong nIndex, sal_uLong& rMin, sal_uLong &rMax,
566 sal_uLong& rAbsMin, OutputDevice* pOut ) const
568 ViewShell* pSh = 0;
569 GetDoc()->GetEditShell( &pSh );
570 if( !pOut )
572 if( pSh )
573 pOut = pSh->GetWin();
574 if( !pOut )
575 pOut = GetpApp()->GetDefaultDevice();
578 MapMode aOldMap( pOut->GetMapMode() );
579 pOut->SetMapMode( MapMode( MAP_TWIP ) );
581 rMin = 0;
582 rMax = 0;
583 rAbsMin = 0;
585 const SvxLRSpaceItem &rSpace = GetSwAttrSet().GetLRSpace();
586 long nLROffset = rSpace.GetTxtLeft() + GetLeftMarginWithNum( sal_True );
587 short nFLOffs;
588 // Bei Numerierung ist ein neg. Erstzeileneinzug vermutlich
589 // bereits gefuellt...
590 if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset )
591 nLROffset = nFLOffs;
593 SwMinMaxNodeArgs aNodeArgs;
594 aNodeArgs.nMinWidth = 0;
595 aNodeArgs.nMaxWidth = 0;
596 aNodeArgs.nLeftRest = nLROffset;
597 aNodeArgs.nRightRest = rSpace.GetRight();
598 aNodeArgs.nLeftDiff = 0;
599 aNodeArgs.nRightDiff = 0;
600 if( nIndex )
602 SwFrmFmts* pTmp = (SwFrmFmts*)GetDoc()->GetSpzFrmFmts();
603 if( pTmp )
605 aNodeArgs.nIndx = nIndex;
606 BOOST_FOREACH( SwFrmFmt *pFmt, *pTmp )
607 lcl_MinMaxNode( pFmt, &aNodeArgs );
610 if( aNodeArgs.nLeftRest < 0 )
611 aNodeArgs.Minimum( nLROffset - aNodeArgs.nLeftRest );
612 aNodeArgs.nLeftRest -= aNodeArgs.nLeftDiff;
613 if( aNodeArgs.nLeftRest < 0 )
614 aNodeArgs.nMaxWidth -= aNodeArgs.nLeftRest;
616 if( aNodeArgs.nRightRest < 0 )
617 aNodeArgs.Minimum( rSpace.GetRight() - aNodeArgs.nRightRest );
618 aNodeArgs.nRightRest -= aNodeArgs.nRightDiff;
619 if( aNodeArgs.nRightRest < 0 )
620 aNodeArgs.nMaxWidth -= aNodeArgs.nRightRest;
622 SwScriptInfo aScriptInfo;
623 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
624 xub_StrLen nIdx = 0;
625 aIter.SeekAndChgAttrIter( nIdx, pOut );
626 xub_StrLen nLen = m_Text.Len();
627 long nAktWidth = 0;
628 MSHORT nAdd = 0;
629 SwMinMaxArgs aArg( pOut, pSh, rMin, rMax, rAbsMin );
630 while( nIdx < nLen )
632 xub_StrLen nNextChg = aIter.GetNextAttr();
633 xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
634 if( nNextChg > nStop )
635 nNextChg = nStop;
636 SwTxtAttr *pHint = NULL;
637 sal_Unicode cChar = CH_BLANK;
638 nStop = nIdx;
639 while( nStop < nLen && nStop < nNextChg &&
640 CH_TAB != ( cChar = m_Text.GetChar( nStop ) ) &&
641 CH_BREAK != cChar && CHAR_HARDBLANK != cChar &&
642 CHAR_HARDHYPHEN != cChar && CHAR_SOFTHYPHEN != cChar &&
643 !pHint )
645 if( ( CH_TXTATR_BREAKWORD != cChar && CH_TXTATR_INWORD != cChar )
646 || ( 0 == ( pHint = aIter.GetAttr( nStop ) ) ) )
647 ++nStop;
649 if ( lcl_MinMaxString( aArg, aIter.GetFnt(), m_Text, nIdx, nStop ) )
651 nAdd = 20;
653 nIdx = nStop;
654 aIter.SeekAndChgAttrIter( nIdx, pOut );
655 switch( cChar )
657 case CH_BREAK :
659 if( (long)rMax < aArg.nRowWidth )
660 rMax = aArg.nRowWidth;
661 aArg.nRowWidth = 0;
662 aArg.NewWord();
663 aIter.SeekAndChgAttrIter( ++nIdx, pOut );
665 break;
666 case CH_TAB :
668 aArg.NewWord();
669 aIter.SeekAndChgAttrIter( ++nIdx, pOut );
671 break;
672 case CHAR_SOFTHYPHEN:
673 ++nIdx;
674 break;
675 case CHAR_HARDBLANK:
676 case CHAR_HARDHYPHEN:
678 OUString sTmp( cChar );
679 SwDrawTextInfo aDrawInf( const_cast<ViewShell *>(getIDocumentLayoutAccess()->GetCurrentViewShell()),
680 *pOut, 0, sTmp, 0, 1, 0, sal_False );//swmod 080311
681 nAktWidth = aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
682 aArg.nWordWidth += nAktWidth;
683 aArg.nRowWidth += nAktWidth;
684 if( (long)rAbsMin < aArg.nWordWidth )
685 rAbsMin = aArg.nWordWidth;
686 aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
687 aArg.nNoLineBreak = nIdx++;
689 break;
690 case CH_TXTATR_BREAKWORD:
691 case CH_TXTATR_INWORD:
693 if( !pHint )
694 break;
695 long nOldWidth = aArg.nWordWidth;
696 long nOldAdd = aArg.nWordAdd;
697 aArg.NewWord();
699 switch( pHint->Which() )
701 case RES_TXTATR_FLYCNT :
703 SwFrmFmt *pFrmFmt = pHint->GetFlyCnt().GetFrmFmt();
704 const SvxLRSpaceItem &rLR = pFrmFmt->GetLRSpace();
705 if( RES_DRAWFRMFMT == pFrmFmt->Which() )
707 const SdrObject* pSObj = pFrmFmt->FindSdrObject();
708 if( pSObj )
709 nAktWidth = pSObj->GetCurrentBoundRect().GetWidth();
710 else
711 nAktWidth = 0;
713 else
715 const SwFmtFrmSize& rTmpSize = pFrmFmt->GetFrmSize();
716 if( RES_FLYFRMFMT == pFrmFmt->Which()
717 && rTmpSize.GetWidthPercent() )
719 /*-----------------------------------------------------------------------------
720 * Hier ein HACK fuer folgende Situation: In dem Absatz befindet sich
721 * ein Textrahmen mit relativer Groesse. Dann nehmen wir mal als minimale
722 * Breite 0,5 cm und als maximale KSHRT_MAX.
723 * Sauberer und vielleicht spaeter notwendig waere es, ueber den Inhalt
724 * des Textrahmens zu iterieren und GetMinMaxSize rekursiv zu rufen.
725 * --------------------------------------------------------------------------*/
726 nAktWidth = FLYINCNT_MIN_WIDTH; // 0,5 cm
727 if( (long)rMax < KSHRT_MAX )
728 rMax = KSHRT_MAX;
730 else
731 nAktWidth = pFrmFmt->GetFrmSize().GetWidth();
733 nAktWidth += rLR.GetLeft();
734 nAktWidth += rLR.GetRight();
735 aArg.nWordAdd = nOldWidth + nOldAdd;
736 aArg.nWordWidth = nAktWidth;
737 aArg.nRowWidth += nAktWidth;
738 if( (long)rAbsMin < aArg.nWordWidth )
739 rAbsMin = aArg.nWordWidth;
740 aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
741 break;
743 case RES_TXTATR_FTN :
745 const XubString aTxt = pHint->GetFtn().GetNumStr();
746 if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0,
747 aTxt.Len() ) )
748 nAdd = 20;
749 break;
751 case RES_TXTATR_FIELD :
753 SwField *pFld = (SwField*)pHint->GetFld().GetFld();
754 const String aTxt = pFld->ExpandField(true);
755 if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0,
756 aTxt.Len() ) )
757 nAdd = 20;
758 break;
760 default: aArg.nWordWidth = nOldWidth;
761 aArg.nWordAdd = nOldAdd;
764 aIter.SeekAndChgAttrIter( ++nIdx, pOut );
766 break;
769 if( (long)rMax < aArg.nRowWidth )
770 rMax = aArg.nRowWidth;
772 nLROffset += rSpace.GetRight();
774 rAbsMin += nLROffset;
775 rAbsMin += nAdd;
776 rMin += nLROffset;
777 rMin += nAdd;
778 if( (long)rMin < aNodeArgs.nMinWidth )
779 rMin = aNodeArgs.nMinWidth;
780 if( (long)rAbsMin < aNodeArgs.nMinWidth )
781 rAbsMin = aNodeArgs.nMinWidth;
782 rMax += aNodeArgs.nMaxWidth;
783 rMax += nLROffset;
784 rMax += nAdd;
785 if( rMax < rMin ) // z.B. Rahmen mit Durchlauf gehen zunaechst nur
786 rMax = rMin; // in das Minimum ein
787 pOut->SetMapMode( aOldMap );
790 /*************************************************************************
791 * SwTxtNode::GetScalingOfSelectedText()
793 * Calculates the width of the text part specified by nStt and nEnd,
794 * the height of the line containing nStt is devided by this width,
795 * indicating the scaling factor, if the text part is rotated.
796 * Having CH_BREAKs in the text part, this method returns the scaling
797 * factor for the longest of the text parts separated by the CH_BREAKs.
799 * changing this method very likely requires changing of "GetMinMaxSize"
800 *************************************************************************/
802 sal_uInt16 SwTxtNode::GetScalingOfSelectedText( xub_StrLen nStt, xub_StrLen nEnd )
803 const
805 ViewShell* pSh = NULL;
806 OutputDevice* pOut = NULL;
807 GetDoc()->GetEditShell( &pSh );
809 if ( pSh )
810 pOut = &pSh->GetRefDev();
811 else
813 //Zugriff ueber StarONE, es muss keine Shell existieren oder aktiv sein.
814 if ( getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE) )
815 pOut = GetpApp()->GetDefaultDevice();
816 else
817 pOut = getIDocumentDeviceAccess()->getReferenceDevice( true );
820 OSL_ENSURE( pOut, "GetScalingOfSelectedText without outdev" );
822 MapMode aOldMap( pOut->GetMapMode() );
823 pOut->SetMapMode( MapMode( MAP_TWIP ) );
825 if ( nStt == nEnd )
827 if ( !pBreakIt->GetBreakIter().is() )
828 return 100;
830 SwScriptInfo aScriptInfo;
831 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
832 aIter.SeekAndChgAttrIter( nStt, pOut );
834 Boundary aBound =
835 pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), nStt,
836 pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ),
837 WordType::DICTIONARY_WORD, sal_True );
839 if ( nStt == aBound.startPos )
841 // cursor is at left or right border of word
842 pOut->SetMapMode( aOldMap );
843 return 100;
846 nStt = (xub_StrLen)aBound.startPos;
847 nEnd = (xub_StrLen)aBound.endPos;
849 if ( nStt == nEnd )
851 pOut->SetMapMode( aOldMap );
852 return 100;
856 SwScriptInfo aScriptInfo;
857 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
859 // We do not want scaling attributes to be considered during this
860 // calculation. For this, we push a temporary scaling attribute with
861 // scaling value 100 and priority flag on top of the scaling stack
862 SwAttrHandler& rAH = aIter.GetAttrHandler();
863 SvxCharScaleWidthItem aItem(100, RES_CHRATR_SCALEW);
864 SwTxtAttrEnd aAttr( aItem, nStt, nEnd );
865 aAttr.SetPriorityAttr( sal_True );
866 rAH.PushAndChg( aAttr, *(aIter.GetFnt()) );
868 xub_StrLen nIdx = nStt;
870 sal_uLong nWidth = 0;
871 sal_uLong nProWidth = 0;
873 while( nIdx < nEnd )
875 aIter.SeekAndChgAttrIter( nIdx, pOut );
877 // scan for end of portion
878 xub_StrLen nNextChg = aIter.GetNextAttr();
879 xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
880 if( nNextChg > nStop )
881 nNextChg = nStop;
883 nStop = nIdx;
884 sal_Unicode cChar = CH_BLANK;
885 SwTxtAttr* pHint = NULL;
887 // stop at special characters in [ nIdx, nNextChg ]
888 while( nStop < nEnd && nStop < nNextChg )
890 cChar = m_Text.GetChar( nStop );
891 if (
892 CH_TAB == cChar ||
893 CH_BREAK == cChar ||
894 CHAR_HARDBLANK == cChar ||
895 CHAR_HARDHYPHEN == cChar ||
896 CHAR_SOFTHYPHEN == cChar ||
898 (CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar) &&
899 (0 == (pHint = aIter.GetAttr(nStop)))
903 break;
905 else
906 ++nStop;
909 // calculate text widths up to cChar
910 if ( nStop > nIdx )
912 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nIdx, nStop - nIdx );
913 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
916 nIdx = nStop;
917 aIter.SeekAndChgAttrIter( nIdx, pOut );
919 if ( cChar == CH_BREAK )
921 nWidth = Max( nWidth, nProWidth );
922 nProWidth = 0;
923 nIdx++;
925 else if ( cChar == CH_TAB )
927 // tab receives width of one space
928 OUString sTmp( CH_BLANK );
929 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
930 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
931 nIdx++;
933 else if ( cChar == CHAR_SOFTHYPHEN )
934 ++nIdx;
935 else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN )
937 OUString sTmp( cChar );
938 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
939 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
940 nIdx++;
942 else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || CH_TXTATR_INWORD ) )
944 switch( pHint->Which() )
946 case RES_TXTATR_FTN :
948 const XubString aTxt = pHint->GetFtn().GetNumStr();
949 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
951 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
952 break;
954 case RES_TXTATR_FIELD :
956 SwField *pFld = (SwField*)pHint->GetFld().GetFld();
957 String const aTxt = pFld->ExpandField(true);
958 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
960 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
961 break;
963 default:
965 // any suggestions for a default action?
967 } // end of switch
968 nIdx++;
969 } // end of while
972 nWidth = Max( nWidth, nProWidth );
974 // search for a text frame this node belongs to
975 SwIterator<SwTxtFrm,SwTxtNode> aFrmIter( *this );
976 SwTxtFrm* pFrm = 0;
977 for( SwTxtFrm* pTmpFrm = aFrmIter.First(); pTmpFrm; pTmpFrm = aFrmIter.Next() )
979 if ( pTmpFrm->GetOfst() <= nStt &&
980 ( !pTmpFrm->GetFollow() ||
981 pTmpFrm->GetFollow()->GetOfst() > nStt ) )
983 pFrm = pTmpFrm;
984 break;
988 // search for the line containing nStt
989 if ( pFrm && pFrm->HasPara() )
991 SwTxtInfo aInf( pFrm );
992 SwTxtIter aLine( pFrm, &aInf );
993 aLine.CharToLine( nStt );
994 pOut->SetMapMode( aOldMap );
995 return (sal_uInt16)( nWidth ?
996 ( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 );
998 // no frame or no paragraph, we take the height of the character
999 // at nStt as line height
1001 aIter.SeekAndChgAttrIter( nStt, pOut );
1002 pOut->SetMapMode( aOldMap );
1004 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nStt, 1 );
1005 return (sal_uInt16)
1006 ( nWidth ? ((100 * aIter.GetFnt()->_GetTxtSize( aDrawInf ).Height()) / nWidth ) : 0 );
1009 sal_uInt16 SwTxtNode::GetWidthOfLeadingTabs() const
1011 sal_uInt16 nRet = 0;
1013 xub_StrLen nIdx = 0;
1014 sal_Unicode cCh;
1016 while ( nIdx < GetTxt().Len() &&
1017 ( '\t' == ( cCh = GetTxt().GetChar( nIdx ) ) ||
1018 ' ' == cCh ) )
1019 ++nIdx;
1021 if ( nIdx > 0 )
1023 SwPosition aPos( *this );
1024 aPos.nContent += nIdx;
1026 // Find the non-follow text frame:
1027 SwIterator<SwTxtFrm,SwTxtNode> aIter( *this );
1028 for( SwTxtFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
1030 // Only consider master frames:
1031 if ( !pFrm->IsFollow() )
1033 SWRECTFN( pFrm )
1034 SwRect aRect;
1035 pFrm->GetCharRect( aRect, aPos );
1036 nRet = (sal_uInt16)
1037 ( pFrm->IsRightToLeft() ?
1038 (pFrm->*fnRect->fnGetPrtRight)() - (aRect.*fnRect->fnGetRight)() :
1039 (aRect.*fnRect->fnGetLeft)() - (pFrm->*fnRect->fnGetPrtLeft)() );
1040 break;
1045 return nRet;
1048 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */