1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 31 32 #include <hintids.hxx> 33 #include <editeng/charscaleitem.hxx> 34 #include <txtatr.hxx> 35 #include <sfx2/printer.hxx> 36 #include <svx/svdobj.hxx> 37 #include <vcl/window.hxx> 38 #include <vcl/svapp.hxx> 39 #include <fmtanchr.hxx> 40 #include <fmtfsize.hxx> 41 #include <fmtornt.hxx> 42 #include <fmtflcnt.hxx> 43 #include <fmtcntnt.hxx> 44 #include <fmtftn.hxx> 45 #include <frmatr.hxx> 46 #include <frmfmt.hxx> 47 #include <fmtfld.hxx> 48 #include <doc.hxx> 49 #include <viewsh.hxx> // ViewShell 50 #include <rootfrm.hxx> 51 #include <docary.hxx> 52 #include <ndtxt.hxx> 53 #include <dcontact.hxx> 54 #include <fldbas.hxx> // SwField 55 #include <pam.hxx> // SwPosition (lcl_MinMaxNode) 56 #include <itratr.hxx> 57 #include <htmltbl.hxx> 58 #include <swtable.hxx> 59 #include <redlnitr.hxx> 60 #include <fmtsrnd.hxx> 61 #include <itrtxt.hxx> 62 #include <breakit.hxx> 63 #include <com/sun/star/i18n/WordType.hpp> 64 #include <com/sun/star/i18n/ScriptType.hdl> 65 #include <editeng/lrspitem.hxx> 66 #include <switerator.hxx> 67 68 using namespace ::com::sun::star::i18n; 69 using namespace ::com::sun::star; 70 71 /************************************************************************* 72 * SwAttrIter::Chg() 73 *************************************************************************/ 74 75 void SwAttrIter::Chg( SwTxtAttr *pHt ) 76 { 77 ASSERT( pHt && pFnt, "No attribute of font available for change"); 78 if( pRedln && pRedln->IsOn() ) 79 pRedln->ChangeTxtAttr( pFnt, *pHt, sal_True ); 80 else 81 aAttrHandler.PushAndChg( *pHt, *pFnt ); 82 nChgCnt++; 83 } 84 85 /************************************************************************* 86 * SwAttrIter::Rst() 87 *************************************************************************/ 88 89 void SwAttrIter::Rst( SwTxtAttr *pHt ) 90 { 91 ASSERT( pHt && pFnt, "No attribute of font available for reset"); 92 // get top from stack after removing pHt 93 if( pRedln && pRedln->IsOn() ) 94 pRedln->ChangeTxtAttr( pFnt, *pHt, sal_False ); 95 else 96 aAttrHandler.PopAndChg( *pHt, *pFnt ); 97 nChgCnt--; 98 } 99 100 /************************************************************************* 101 * virtual SwAttrIter::~SwAttrIter() 102 *************************************************************************/ 103 104 SwAttrIter::~SwAttrIter() 105 { 106 delete pRedln; 107 delete pFnt; 108 } 109 110 /************************************************************************* 111 * SwAttrIter::GetAttr() 112 * 113 * Liefert fuer eine Position das Attribut, wenn das Attribut genau auf 114 * der Position nPos liegt und kein EndIndex besitzt. 115 * GetAttr() wird fuer Attribute benoetigt, die die Formatierung beeinflussen 116 * sollen, ohne dabei den Inhalt des Strings zu veraendern. Solche "entarteten" 117 * Attribute sind z.B. Felder (die expandierten Text bereit halten) und 118 * zeilengebundene Frames. Um Mehrdeutigkeiten zwischen verschiedenen 119 * solcher Attribute zu vermeiden, werden beim Anlegen eines Attributs 120 * an der Startposition ein Sonderzeichen in den String einfuegt. 121 * Der Formatierer stoesst auf das Sonderzeichen und holt sich per 122 * GetAttr() das entartete Attribut. 123 *************************************************************************/ 124 125 SwTxtAttr *SwAttrIter::GetAttr( const xub_StrLen nPosition ) const 126 { 127 return (m_pTxtNode) ? m_pTxtNode->GetTxtAttrForCharAt(nPosition) : 0; 128 } 129 130 /************************************************************************* 131 * SwAttrIter::SeekAndChg() 132 *************************************************************************/ 133 134 sal_Bool SwAttrIter::SeekAndChgAttrIter( const xub_StrLen nNewPos, OutputDevice* pOut ) 135 { 136 sal_Bool bChg = nStartIndex && nNewPos == nPos ? pFnt->IsFntChg() : Seek( nNewPos ); 137 if ( pLastOut != pOut ) 138 { 139 pLastOut = pOut; 140 pFnt->SetFntChg( sal_True ); 141 bChg = sal_True; 142 } 143 if( bChg ) 144 { 145 // wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo 146 // des gewuenschten Fonts ... 147 if ( !nChgCnt && !nPropFont ) 148 pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ], 149 aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() ); 150 pFnt->ChgPhysFnt( pShell, *pOut ); 151 } 152 return bChg; 153 } 154 155 sal_Bool SwAttrIter::IsSymbol( const xub_StrLen nNewPos ) 156 { 157 Seek( nNewPos ); 158 if ( !nChgCnt && !nPropFont ) 159 pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ], 160 aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() ); 161 return pFnt->IsSymbol( pShell ); 162 } 163 164 /************************************************************************* 165 * SwAttrIter::SeekStartAndChg() 166 *************************************************************************/ 167 168 sal_Bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const sal_Bool bParaFont ) 169 { 170 if ( pRedln && pRedln->ExtOn() ) 171 pRedln->LeaveExtend( *pFnt, 0 ); 172 173 // reset font to its original state 174 aAttrHandler.Reset(); 175 aAttrHandler.ResetFont( *pFnt ); 176 177 nStartIndex = nEndIndex = nPos = nChgCnt = 0; 178 if( nPropFont ) 179 pFnt->SetProportion( nPropFont ); 180 if( pRedln ) 181 { 182 pRedln->Clear( pFnt ); 183 if( !bParaFont ) 184 nChgCnt = nChgCnt + pRedln->Seek( *pFnt, 0, STRING_LEN ); 185 else 186 pRedln->Reset(); 187 } 188 189 if ( pHints && !bParaFont ) 190 { 191 SwTxtAttr *pTxtAttr; 192 // Solange wir noch nicht am Ende des StartArrays angekommen sind && 193 // das TextAttribut an Position 0 beginnt ... 194 while ( ( nStartIndex < pHints->GetStartCount() ) && 195 !(*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()) ) 196 { 197 // oeffne die TextAttribute 198 Chg( pTxtAttr ); 199 nStartIndex++; 200 } 201 } 202 203 sal_Bool bChg = pFnt->IsFntChg(); 204 if ( pLastOut != pOut ) 205 { 206 pLastOut = pOut; 207 pFnt->SetFntChg( sal_True ); 208 bChg = sal_True; 209 } 210 if( bChg ) 211 { 212 // wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo 213 // des gewuenschten Fonts ... 214 if ( !nChgCnt && !nPropFont ) 215 pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ], 216 aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() ); 217 pFnt->ChgPhysFnt( pShell, *pOut ); 218 } 219 return bChg; 220 } 221 222 /************************************************************************* 223 * SwAttrIter::SeekFwd() 224 *************************************************************************/ 225 226 // AMA: Neuer AttrIter Nov 94 227 228 void SwAttrIter::SeekFwd( const xub_StrLen nNewPos ) 229 { 230 SwTxtAttr *pTxtAttr; 231 232 if ( nStartIndex ) // wenn ueberhaupt schon Attribute geoeffnet wurden... 233 { 234 // Schliesse Attr, die z. Z. geoeffnet sind, vor nNewPos+1 aber enden. 235 236 // Solange wir noch nicht am Ende des EndArrays angekommen sind && 237 // das TextAttribut vor oder an der neuen Position endet ... 238 while ( ( nEndIndex < pHints->GetEndCount() ) && 239 (*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos)) 240 { 241 // schliesse die TextAttribute, deren StartPos vor 242 // oder an der alten nPos lag, die z.Z. geoeffnet sind. 243 if (*pTxtAttr->GetStart() <= nPos) Rst( pTxtAttr ); 244 nEndIndex++; 245 } 246 } 247 else // ueberlies die nicht geoeffneten Enden 248 { 249 while ( ( nEndIndex < pHints->GetEndCount() ) && 250 (*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos)) 251 { 252 nEndIndex++; 253 } 254 } 255 // Solange wir noch nicht am Ende des StartArrays angekommen sind && 256 // das TextAttribut vor oder an der neuen Position beginnt ... 257 while ( ( nStartIndex < pHints->GetStartCount() ) && 258 (*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()<=nNewPos)) 259 { 260 // oeffne die TextAttribute, deren Ende hinter der neuen Position liegt 261 if ( *pTxtAttr->GetAnyEnd() > nNewPos ) Chg( pTxtAttr ); 262 nStartIndex++; 263 } 264 265 } 266 267 /************************************************************************* 268 * SwAttrIter::Seek() 269 *************************************************************************/ 270 271 sal_Bool SwAttrIter::Seek( const xub_StrLen nNewPos ) 272 { 273 if ( pRedln && pRedln->ExtOn() ) 274 pRedln->LeaveExtend( *pFnt, nNewPos ); 275 276 if( pHints ) 277 { 278 if( !nNewPos || nNewPos < nPos ) 279 { 280 if( pRedln ) 281 pRedln->Clear( NULL ); 282 283 // reset font to its original state 284 aAttrHandler.Reset(); 285 aAttrHandler.ResetFont( *pFnt ); 286 287 if( nPropFont ) 288 pFnt->SetProportion( nPropFont ); 289 nStartIndex = nEndIndex = nPos = 0; 290 nChgCnt = 0; 291 292 // Achtung! 293 // resetting the font here makes it necessary to apply any 294 // changes for extended input directly to the font 295 if ( pRedln && pRedln->ExtOn() ) 296 { 297 pRedln->UpdateExtFont( *pFnt ); 298 ++nChgCnt; 299 } 300 } 301 SeekFwd( nNewPos ); 302 } 303 304 pFnt->SetActual( SwScriptInfo::WhichFont( nNewPos, 0, pScriptInfo ) ); 305 306 if( pRedln ) 307 nChgCnt = nChgCnt + pRedln->Seek( *pFnt, nNewPos, nPos ); 308 nPos = nNewPos; 309 310 if( nPropFont ) 311 pFnt->SetProportion( nPropFont ); 312 313 return pFnt->IsFntChg(); 314 } 315 316 /************************************************************************* 317 * SwAttrIter::GetNextAttr() 318 *************************************************************************/ 319 320 xub_StrLen SwAttrIter::GetNextAttr( ) const 321 { 322 xub_StrLen nNext = STRING_LEN; 323 if( pHints ) 324 { 325 if (pHints->GetStartCount() > nStartIndex) // Gibt es noch Starts? 326 nNext = (*pHints->GetStart(nStartIndex)->GetStart()); 327 if (pHints->GetEndCount() > nEndIndex) // Gibt es noch Enden? 328 { 329 xub_StrLen nNextEnd = (*pHints->GetEnd(nEndIndex)->GetAnyEnd()); 330 if ( nNextEnd<nNext ) nNext = nNextEnd; // Wer ist naeher? 331 } 332 } 333 if (m_pTxtNode!=NULL) { 334 //TODO maybe use hints like FieldHints for this instead of looking at the text... 335 int l=(nNext<m_pTxtNode->Len()?nNext:m_pTxtNode->Len()); 336 sal_uInt16 p=nPos; 337 const sal_Unicode *txt=m_pTxtNode->GetTxt().GetBuffer(); 338 while(p<l && txt[p]!=CH_TXT_ATR_FIELDSTART && txt[p]!=CH_TXT_ATR_FIELDEND && txt[p]!=CH_TXT_ATR_FORMELEMENT) p++; 339 if ((p<l && p>nPos) || nNext<=p) 340 nNext=p; 341 else 342 nNext=p+1; 343 } 344 if( pRedln ) 345 return pRedln->GetNextRedln( nNext ); 346 return nNext; 347 } 348 349 #if OSL_DEBUG_LEVEL > 1 350 /************************************************************************* 351 * SwAttrIter::Dump() 352 *************************************************************************/ 353 354 void SwAttrIter::Dump( SvStream &/*rOS*/ ) const 355 { 356 // Noch nicht an den neuen Attributiterator angepasst ... 357 } 358 359 #endif 360 361 class SwMinMaxArgs 362 { 363 public: 364 OutputDevice* pOut; 365 ViewShell* pSh; 366 sal_uLong &rMin; 367 sal_uLong &rMax; 368 sal_uLong &rAbsMin; 369 long nRowWidth; 370 long nWordWidth; 371 long nWordAdd; 372 xub_StrLen nNoLineBreak; 373 SwMinMaxArgs( OutputDevice* pOutI, ViewShell* pShI, sal_uLong& rMinI, sal_uLong &rMaxI, sal_uLong &rAbsI ) 374 : pOut( pOutI ), pSh( pShI ), rMin( rMinI ), rMax( rMaxI ), rAbsMin( rAbsI ) 375 { nRowWidth = nWordWidth = nWordAdd = 0; nNoLineBreak = STRING_LEN; } 376 void Minimum( long nNew ) { if( (long)rMin < nNew ) rMin = nNew; } 377 void NewWord() { nWordAdd = nWordWidth = 0; } 378 }; 379 380 sal_Bool lcl_MinMaxString( SwMinMaxArgs& rArg, SwFont* pFnt, const XubString &rTxt, 381 xub_StrLen nIdx, xub_StrLen nEnd ) 382 { 383 sal_Bool bRet = sal_False; 384 while( nIdx < nEnd ) 385 { 386 xub_StrLen nStop = nIdx; 387 sal_Bool bClear; 388 LanguageType eLang = pFnt->GetLanguage(); 389 if( pBreakIt->GetBreakIter().is() ) 390 { 391 bClear = CH_BLANK == rTxt.GetChar( nStop ); 392 Boundary aBndry( pBreakIt->GetBreakIter()->getWordBoundary( rTxt, nIdx, 393 pBreakIt->GetLocale( eLang ), 394 WordType::DICTIONARY_WORD, sal_True ) ); 395 nStop = (xub_StrLen)aBndry.endPos; 396 if( nIdx <= aBndry.startPos && nIdx && nIdx-1 != rArg.nNoLineBreak ) 397 rArg.NewWord(); 398 if( nStop == nIdx ) 399 ++nStop; 400 if( nStop > nEnd ) 401 nStop = nEnd; 402 } 403 else 404 { 405 while( nStop < nEnd && CH_BLANK != rTxt.GetChar( nStop ) ) 406 ++nStop; 407 bClear = nStop == nIdx; 408 if ( bClear ) 409 { 410 rArg.NewWord(); 411 while( nStop < nEnd && CH_BLANK == rTxt.GetChar( nStop ) ) 412 ++nStop; 413 } 414 } 415 416 SwDrawTextInfo aDrawInf( rArg.pSh, *rArg.pOut, 0, rTxt, nIdx, nStop - nIdx ); 417 long nAktWidth = pFnt->_GetTxtSize( aDrawInf ).Width(); 418 rArg.nRowWidth += nAktWidth; 419 if( bClear ) 420 rArg.NewWord(); 421 else 422 { 423 rArg.nWordWidth += nAktWidth; 424 if( (long)rArg.rAbsMin < rArg.nWordWidth ) 425 rArg.rAbsMin = rArg.nWordWidth; 426 rArg.Minimum( rArg.nWordWidth + rArg.nWordAdd ); 427 bRet = sal_True; 428 } 429 nIdx = nStop; 430 } 431 return bRet; 432 } 433 434 sal_Bool SwTxtNode::IsSymbol( const xub_StrLen nBegin ) const//swmodtest 080307 435 { 436 SwScriptInfo aScriptInfo; 437 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo ); 438 aIter.Seek( nBegin ); 439 return aIter.GetFnt()->IsSymbol( 440 const_cast<ViewShell *>(getIDocumentLayoutAccess()->GetCurrentViewShell()) );//swmod 080311 441 } 442 443 class SwMinMaxNodeArgs 444 { 445 public: 446 sal_uLong nMaxWidth; // Summe aller Rahmenbreite 447 long nMinWidth; // Breitester Rahmen 448 long nLeftRest; // noch nicht von Rahmen ueberdeckter Platz im l. Rand 449 long nRightRest; // noch nicht von Rahmen ueberdeckter Platz im r. Rand 450 long nLeftDiff; // Min/Max-Differenz des Rahmens im linken Rand 451 long nRightDiff; // Min/Max-Differenz des Rahmens im rechten Rand 452 sal_uLong nIndx; // Indexnummer des Nodes 453 void Minimum( long nNew ) { if( nNew > nMinWidth ) nMinWidth = nNew; } 454 }; 455 456 sal_Bool lcl_MinMaxNode( const SwFrmFmtPtr& rpNd, void* pArgs ) 457 { 458 const SwFmtAnchor& rFmtA = ((SwFrmFmt*)rpNd)->GetAnchor(); 459 460 bool bCalculate = false; 461 if ((FLY_AT_PARA == rFmtA.GetAnchorId()) || 462 (FLY_AT_CHAR == rFmtA.GetAnchorId())) 463 { 464 bCalculate = true; 465 } 466 467 if (bCalculate) 468 { 469 const SwMinMaxNodeArgs *pIn = (const SwMinMaxNodeArgs*)pArgs; 470 const SwPosition *pPos = rFmtA.GetCntntAnchor(); 471 ASSERT(pPos && pIn, "Unexpected NULL arguments"); 472 if (!pPos || !pIn || pIn->nIndx != pPos->nNode.GetIndex()) 473 bCalculate = false; 474 } 475 476 if (bCalculate) 477 { 478 long nMin, nMax; 479 SwHTMLTableLayout *pLayout = 0; 480 MSHORT nWhich = ((SwFrmFmt*)rpNd)->Which(); 481 if( RES_DRAWFRMFMT != nWhich ) 482 { 483 // Enthaelt der Rahmen zu Beginn oder am Ende eine Tabelle? 484 const SwNodes& rNodes = static_cast<SwFrmFmt*>(rpNd)->GetDoc()->GetNodes(); 485 const SwFmtCntnt& rFlyCntnt = ((SwFrmFmt*)rpNd)->GetCntnt(); 486 sal_uLong nStt = rFlyCntnt.GetCntntIdx()->GetIndex(); 487 SwTableNode* pTblNd = rNodes[nStt+1]->GetTableNode(); 488 if( !pTblNd ) 489 { 490 SwNode *pNd = rNodes[nStt]; 491 pNd = rNodes[pNd->EndOfSectionIndex()-1]; 492 if( pNd->IsEndNode() ) 493 pTblNd = pNd->StartOfSectionNode()->GetTableNode(); 494 } 495 496 if( pTblNd ) 497 pLayout = pTblNd->GetTable().GetHTMLTableLayout(); 498 } 499 500 const SwFmtHoriOrient& rOrient = ((SwFrmFmt*)rpNd)->GetHoriOrient(); 501 sal_Int16 eHoriOri = rOrient.GetHoriOrient(); 502 503 long nDiff; 504 if( pLayout ) 505 { 506 nMin = pLayout->GetMin(); 507 nMax = pLayout->GetMax(); 508 nDiff = nMax - nMin; 509 } 510 else 511 { 512 if( RES_DRAWFRMFMT == nWhich ) 513 { 514 const SdrObject* pSObj = rpNd->FindSdrObject(); 515 if( pSObj ) 516 nMin = pSObj->GetCurrentBoundRect().GetWidth(); 517 else 518 nMin = 0; 519 520 } 521 else 522 { 523 const SwFmtFrmSize &rSz = ( (SwFrmFmt*)rpNd )->GetFrmSize(); 524 nMin = rSz.GetWidth(); 525 } 526 nMax = nMin; 527 nDiff = 0; 528 } 529 530 const SvxLRSpaceItem &rLR = ( (SwFrmFmt*)rpNd )->GetLRSpace(); 531 nMin += rLR.GetLeft(); 532 nMin += rLR.GetRight(); 533 nMax += rLR.GetLeft(); 534 nMax += rLR.GetRight(); 535 536 if( SURROUND_THROUGHT == ((SwFrmFmt*)rpNd)->GetSurround().GetSurround() ) 537 { 538 ( (SwMinMaxNodeArgs*)pArgs )->Minimum( nMin ); 539 return sal_True; 540 } 541 542 // Rahmen, die recht bzw. links ausgerichtet sind, gehen nur 543 // teilweise in die Max-Berechnung ein, da der Rand schon berueck- 544 // sichtigt wird. Nur wenn die Rahmen in den Textkoerper ragen, 545 // wird dieser Teil hinzuaddiert. 546 switch( eHoriOri ) 547 { 548 case text::HoriOrientation::RIGHT: 549 { 550 if( nDiff ) 551 { 552 ((SwMinMaxNodeArgs*)pArgs)->nRightRest -= 553 ((SwMinMaxNodeArgs*)pArgs)->nRightDiff; 554 ((SwMinMaxNodeArgs*)pArgs)->nRightDiff = nDiff; 555 } 556 if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() ) 557 { 558 if( ((SwMinMaxNodeArgs*)pArgs)->nRightRest > 0 ) 559 ((SwMinMaxNodeArgs*)pArgs)->nRightRest = 0; 560 } 561 ((SwMinMaxNodeArgs*)pArgs)->nRightRest -= nMin; 562 break; 563 } 564 case text::HoriOrientation::LEFT: 565 { 566 if( nDiff ) 567 { 568 ((SwMinMaxNodeArgs*)pArgs)->nLeftRest -= 569 ((SwMinMaxNodeArgs*)pArgs)->nLeftDiff; 570 ((SwMinMaxNodeArgs*)pArgs)->nLeftDiff = nDiff; 571 } 572 if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() && 573 ((SwMinMaxNodeArgs*)pArgs)->nLeftRest < 0 ) 574 ((SwMinMaxNodeArgs*)pArgs)->nLeftRest = 0; 575 ((SwMinMaxNodeArgs*)pArgs)->nLeftRest -= nMin; 576 break; 577 } 578 default: 579 { 580 ( (SwMinMaxNodeArgs*)pArgs )->nMaxWidth += nMax; 581 ( (SwMinMaxNodeArgs*)pArgs )->Minimum( nMin ); 582 } 583 } 584 } 585 return sal_True; 586 } 587 588 #define FLYINCNT_MIN_WIDTH 284 589 590 // changing this method very likely requires changing of 591 // "GetScalingOfSelectedText" 592 void SwTxtNode::GetMinMaxSize( sal_uLong nIndex, sal_uLong& rMin, sal_uLong &rMax, 593 sal_uLong& rAbsMin, OutputDevice* pOut ) const 594 { 595 ViewShell* pSh = 0; 596 GetDoc()->GetEditShell( &pSh ); 597 if( !pOut ) 598 { 599 if( pSh ) 600 pOut = pSh->GetWin(); 601 if( !pOut ) 602 pOut = GetpApp()->GetDefaultDevice(); 603 } 604 605 MapMode aOldMap( pOut->GetMapMode() ); 606 pOut->SetMapMode( MapMode( MAP_TWIP ) ); 607 608 rMin = 0; 609 rMax = 0; 610 rAbsMin = 0; 611 612 const SvxLRSpaceItem &rSpace = GetSwAttrSet().GetLRSpace(); 613 long nLROffset = rSpace.GetTxtLeft() + GetLeftMarginWithNum( sal_True ); 614 short nFLOffs; 615 // Bei Numerierung ist ein neg. Erstzeileneinzug vermutlich 616 // bereits gefuellt... 617 if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset ) 618 nLROffset = nFLOffs; 619 620 SwMinMaxNodeArgs aNodeArgs; 621 aNodeArgs.nMinWidth = 0; 622 aNodeArgs.nMaxWidth = 0; 623 aNodeArgs.nLeftRest = nLROffset; 624 aNodeArgs.nRightRest = rSpace.GetRight(); 625 aNodeArgs.nLeftDiff = 0; 626 aNodeArgs.nRightDiff = 0; 627 if( nIndex ) 628 { 629 SwSpzFrmFmts* pTmp = (SwSpzFrmFmts*)GetDoc()->GetSpzFrmFmts(); 630 if( pTmp ) 631 { 632 aNodeArgs.nIndx = nIndex; 633 pTmp->ForEach( &lcl_MinMaxNode, &aNodeArgs ); 634 } 635 } 636 if( aNodeArgs.nLeftRest < 0 ) 637 aNodeArgs.Minimum( nLROffset - aNodeArgs.nLeftRest ); 638 aNodeArgs.nLeftRest -= aNodeArgs.nLeftDiff; 639 if( aNodeArgs.nLeftRest < 0 ) 640 aNodeArgs.nMaxWidth -= aNodeArgs.nLeftRest; 641 642 if( aNodeArgs.nRightRest < 0 ) 643 aNodeArgs.Minimum( rSpace.GetRight() - aNodeArgs.nRightRest ); 644 aNodeArgs.nRightRest -= aNodeArgs.nRightDiff; 645 if( aNodeArgs.nRightRest < 0 ) 646 aNodeArgs.nMaxWidth -= aNodeArgs.nRightRest; 647 648 SwScriptInfo aScriptInfo; 649 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo ); 650 xub_StrLen nIdx = 0; 651 aIter.SeekAndChgAttrIter( nIdx, pOut ); 652 xub_StrLen nLen = m_Text.Len(); 653 long nAktWidth = 0; 654 MSHORT nAdd = 0; 655 SwMinMaxArgs aArg( pOut, pSh, rMin, rMax, rAbsMin ); 656 while( nIdx < nLen ) 657 { 658 xub_StrLen nNextChg = aIter.GetNextAttr(); 659 xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx ); 660 if( nNextChg > nStop ) 661 nNextChg = nStop; 662 SwTxtAttr *pHint = NULL; 663 xub_Unicode cChar = CH_BLANK; 664 nStop = nIdx; 665 while( nStop < nLen && nStop < nNextChg && 666 CH_TAB != ( cChar = m_Text.GetChar( nStop ) ) && 667 CH_BREAK != cChar && CHAR_HARDBLANK != cChar && 668 CHAR_HARDHYPHEN != cChar && CHAR_SOFTHYPHEN != cChar && 669 !pHint ) 670 { 671 if( ( CH_TXTATR_BREAKWORD != cChar && CH_TXTATR_INWORD != cChar ) 672 || ( 0 == ( pHint = aIter.GetAttr( nStop ) ) ) ) 673 ++nStop; 674 } 675 if ( lcl_MinMaxString( aArg, aIter.GetFnt(), m_Text, nIdx, nStop ) ) 676 { 677 nAdd = 20; 678 } 679 nIdx = nStop; 680 aIter.SeekAndChgAttrIter( nIdx, pOut ); 681 switch( cChar ) 682 { 683 case CH_BREAK : 684 { 685 if( (long)rMax < aArg.nRowWidth ) 686 rMax = aArg.nRowWidth; 687 aArg.nRowWidth = 0; 688 aArg.NewWord(); 689 aIter.SeekAndChgAttrIter( ++nIdx, pOut ); 690 } 691 break; 692 case CH_TAB : 693 { 694 aArg.NewWord(); 695 aIter.SeekAndChgAttrIter( ++nIdx, pOut ); 696 } 697 break; 698 case CHAR_SOFTHYPHEN: 699 ++nIdx; 700 break; 701 case CHAR_HARDBLANK: 702 case CHAR_HARDHYPHEN: 703 { 704 XubString sTmp( cChar ); 705 SwDrawTextInfo aDrawInf( const_cast<ViewShell *>(getIDocumentLayoutAccess()->GetCurrentViewShell()), 706 *pOut, 0, sTmp, 0, 1, 0, sal_False );//swmod 080311 707 nAktWidth = aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); 708 aArg.nWordWidth += nAktWidth; 709 aArg.nRowWidth += nAktWidth; 710 if( (long)rAbsMin < aArg.nWordWidth ) 711 rAbsMin = aArg.nWordWidth; 712 aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd ); 713 aArg.nNoLineBreak = nIdx++; 714 } 715 break; 716 case CH_TXTATR_BREAKWORD: 717 case CH_TXTATR_INWORD: 718 { 719 if( !pHint ) 720 break; 721 long nOldWidth = aArg.nWordWidth; 722 long nOldAdd = aArg.nWordAdd; 723 aArg.NewWord(); 724 725 switch( pHint->Which() ) 726 { 727 case RES_TXTATR_FLYCNT : 728 { 729 SwFrmFmt *pFrmFmt = pHint->GetFlyCnt().GetFrmFmt(); 730 const SvxLRSpaceItem &rLR = pFrmFmt->GetLRSpace(); 731 if( RES_DRAWFRMFMT == pFrmFmt->Which() ) 732 { 733 const SdrObject* pSObj = pFrmFmt->FindSdrObject(); 734 if( pSObj ) 735 nAktWidth = pSObj->GetCurrentBoundRect().GetWidth(); 736 else 737 nAktWidth = 0; 738 } 739 else 740 { 741 const SwFmtFrmSize& rTmpSize = pFrmFmt->GetFrmSize(); 742 if( RES_FLYFRMFMT == pFrmFmt->Which() 743 && rTmpSize.GetWidthPercent() ) 744 { 745 /*-----------------24.01.97 14:09---------------------------------------------- 746 * Hier ein HACK fuer folgende Situation: In dem Absatz befindet sich 747 * ein Textrahmen mit relativer Groesse. Dann nehmen wir mal als minimale 748 * Breite 0,5 cm und als maximale KSHRT_MAX. 749 * Sauberer und vielleicht spaeter notwendig waere es, ueber den Inhalt 750 * des Textrahmens zu iterieren und GetMinMaxSize rekursiv zu rufen. 751 * --------------------------------------------------------------------------*/ 752 nAktWidth = FLYINCNT_MIN_WIDTH; // 0,5 cm 753 if( (long)rMax < KSHRT_MAX ) 754 rMax = KSHRT_MAX; 755 } 756 else 757 nAktWidth = pFrmFmt->GetFrmSize().GetWidth(); 758 } 759 nAktWidth += rLR.GetLeft(); 760 nAktWidth += rLR.GetRight(); 761 aArg.nWordAdd = nOldWidth + nOldAdd; 762 aArg.nWordWidth = nAktWidth; 763 aArg.nRowWidth += nAktWidth; 764 if( (long)rAbsMin < aArg.nWordWidth ) 765 rAbsMin = aArg.nWordWidth; 766 aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd ); 767 break; 768 } 769 case RES_TXTATR_FTN : 770 { 771 const XubString aTxt = pHint->GetFtn().GetNumStr(); 772 if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0, 773 aTxt.Len() ) ) 774 nAdd = 20; 775 break; 776 } 777 case RES_TXTATR_FIELD : 778 { 779 SwField *pFld = (SwField*)pHint->GetFld().GetFld(); 780 const String aTxt = pFld->ExpandField(true); 781 if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0, 782 aTxt.Len() ) ) 783 nAdd = 20; 784 break; 785 } 786 default: aArg.nWordWidth = nOldWidth; 787 aArg.nWordAdd = nOldAdd; 788 789 } 790 aIter.SeekAndChgAttrIter( ++nIdx, pOut ); 791 } 792 break; 793 } 794 } 795 if( (long)rMax < aArg.nRowWidth ) 796 rMax = aArg.nRowWidth; 797 798 nLROffset += rSpace.GetRight(); 799 800 rAbsMin += nLROffset; 801 rAbsMin += nAdd; 802 rMin += nLROffset; 803 rMin += nAdd; 804 if( (long)rMin < aNodeArgs.nMinWidth ) 805 rMin = aNodeArgs.nMinWidth; 806 if( (long)rAbsMin < aNodeArgs.nMinWidth ) 807 rAbsMin = aNodeArgs.nMinWidth; 808 rMax += aNodeArgs.nMaxWidth; 809 rMax += nLROffset; 810 rMax += nAdd; 811 if( rMax < rMin ) // z.B. Rahmen mit Durchlauf gehen zunaechst nur 812 rMax = rMin; // in das Minimum ein 813 pOut->SetMapMode( aOldMap ); 814 } 815 816 /************************************************************************* 817 * SwTxtNode::GetScalingOfSelectedText() 818 * 819 * Calculates the width of the text part specified by nStt and nEnd, 820 * the height of the line containing nStt is devided by this width, 821 * indicating the scaling factor, if the text part is rotated. 822 * Having CH_BREAKs in the text part, this method returns the scaling 823 * factor for the longest of the text parts separated by the CH_BREAKs. 824 * 825 * changing this method very likely requires changing of "GetMinMaxSize" 826 *************************************************************************/ 827 828 sal_uInt16 SwTxtNode::GetScalingOfSelectedText( xub_StrLen nStt, xub_StrLen nEnd ) 829 const 830 { 831 ViewShell* pSh = NULL; 832 OutputDevice* pOut = NULL; 833 GetDoc()->GetEditShell( &pSh ); 834 835 if ( pSh ) 836 pOut = &pSh->GetRefDev(); 837 else 838 { 839 //Zugriff ueber StarONE, es muss keine Shell existieren oder aktiv sein. 840 if ( getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE) ) 841 pOut = GetpApp()->GetDefaultDevice(); 842 else 843 pOut = getIDocumentDeviceAccess()->getReferenceDevice( true ); 844 } 845 846 ASSERT( pOut, "GetScalingOfSelectedText without outdev" ) 847 848 MapMode aOldMap( pOut->GetMapMode() ); 849 pOut->SetMapMode( MapMode( MAP_TWIP ) ); 850 851 if ( nStt == nEnd ) 852 { 853 if ( !pBreakIt->GetBreakIter().is() ) 854 return 100; 855 856 SwScriptInfo aScriptInfo; 857 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo ); 858 aIter.SeekAndChgAttrIter( nStt, pOut ); 859 860 Boundary aBound = 861 pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), nStt, 862 pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ), 863 WordType::DICTIONARY_WORD, sal_True ); 864 865 if ( nStt == aBound.startPos ) 866 { 867 // cursor is at left or right border of word 868 pOut->SetMapMode( aOldMap ); 869 return 100; 870 } 871 872 nStt = (xub_StrLen)aBound.startPos; 873 nEnd = (xub_StrLen)aBound.endPos; 874 875 if ( nStt == nEnd ) 876 { 877 pOut->SetMapMode( aOldMap ); 878 return 100; 879 } 880 } 881 882 SwScriptInfo aScriptInfo; 883 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo ); 884 885 // We do not want scaling attributes to be considered during this 886 // calculation. For this, we push a temporary scaling attribute with 887 // scaling value 100 and priority flag on top of the scaling stack 888 SwAttrHandler& rAH = aIter.GetAttrHandler(); 889 SvxCharScaleWidthItem aItem(100, RES_CHRATR_SCALEW); 890 SwTxtAttrEnd aAttr( aItem, nStt, nEnd ); 891 aAttr.SetPriorityAttr( sal_True ); 892 rAH.PushAndChg( aAttr, *(aIter.GetFnt()) ); 893 894 xub_StrLen nIdx = nStt; 895 896 sal_uLong nWidth = 0; 897 sal_uLong nProWidth = 0; 898 899 while( nIdx < nEnd ) 900 { 901 aIter.SeekAndChgAttrIter( nIdx, pOut ); 902 903 // scan for end of portion 904 xub_StrLen nNextChg = aIter.GetNextAttr(); 905 xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx ); 906 if( nNextChg > nStop ) 907 nNextChg = nStop; 908 909 nStop = nIdx; 910 xub_Unicode cChar = CH_BLANK; 911 SwTxtAttr* pHint = NULL; 912 913 // stop at special characters in [ nIdx, nNextChg ] 914 while( nStop < nEnd && nStop < nNextChg ) 915 { 916 cChar = m_Text.GetChar( nStop ); 917 if ( 918 CH_TAB == cChar || 919 CH_BREAK == cChar || 920 CHAR_HARDBLANK == cChar || 921 CHAR_HARDHYPHEN == cChar || 922 CHAR_SOFTHYPHEN == cChar || 923 ( 924 (CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar) && 925 (0 == (pHint = aIter.GetAttr(nStop))) 926 ) 927 ) 928 { 929 break; 930 } 931 else 932 ++nStop; 933 } 934 935 // calculate text widths up to cChar 936 if ( nStop > nIdx ) 937 { 938 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nIdx, nStop - nIdx ); 939 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); 940 } 941 942 nIdx = nStop; 943 aIter.SeekAndChgAttrIter( nIdx, pOut ); 944 945 if ( cChar == CH_BREAK ) 946 { 947 nWidth = Max( nWidth, nProWidth ); 948 nProWidth = 0; 949 nIdx++; 950 } 951 else if ( cChar == CH_TAB ) 952 { 953 // tab receives width of one space 954 XubString sTmp( CH_BLANK ); 955 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 ); 956 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); 957 nIdx++; 958 } 959 else if ( cChar == CHAR_SOFTHYPHEN ) 960 ++nIdx; 961 else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN ) 962 { 963 XubString sTmp( cChar ); 964 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 ); 965 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); 966 nIdx++; 967 } 968 else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || CH_TXTATR_INWORD ) ) 969 { 970 switch( pHint->Which() ) 971 { 972 case RES_TXTATR_FTN : 973 { 974 const XubString aTxt = pHint->GetFtn().GetNumStr(); 975 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() ); 976 977 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); 978 break; 979 } 980 case RES_TXTATR_FIELD : 981 { 982 SwField *pFld = (SwField*)pHint->GetFld().GetFld(); 983 String const aTxt = pFld->ExpandField(true); 984 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() ); 985 986 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); 987 break; 988 } 989 default: 990 { 991 // any suggestions for a default action? 992 } 993 } // end of switch 994 nIdx++; 995 } // end of while 996 } 997 998 nWidth = Max( nWidth, nProWidth ); 999 1000 // search for a text frame this node belongs to 1001 SwIterator<SwTxtFrm,SwTxtNode> aFrmIter( *this ); 1002 SwTxtFrm* pFrm = 0; 1003 for( SwTxtFrm* pTmpFrm = aFrmIter.First(); pTmpFrm; pTmpFrm = aFrmIter.Next() ) 1004 { 1005 if ( pTmpFrm->GetOfst() <= nStt && 1006 ( !pTmpFrm->GetFollow() || 1007 pTmpFrm->GetFollow()->GetOfst() > nStt ) ) 1008 { 1009 pFrm = pTmpFrm; 1010 break; 1011 } 1012 } 1013 1014 // search for the line containing nStt 1015 if ( pFrm && pFrm->HasPara() ) 1016 { 1017 SwTxtInfo aInf( pFrm ); 1018 SwTxtIter aLine( pFrm, &aInf ); 1019 aLine.CharToLine( nStt ); 1020 pOut->SetMapMode( aOldMap ); 1021 return (sal_uInt16)( nWidth ? 1022 ( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 ); 1023 } 1024 // no frame or no paragraph, we take the height of the character 1025 // at nStt as line height 1026 1027 aIter.SeekAndChgAttrIter( nStt, pOut ); 1028 pOut->SetMapMode( aOldMap ); 1029 1030 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nStt, 1 ); 1031 return (sal_uInt16) 1032 ( nWidth ? ((100 * aIter.GetFnt()->_GetTxtSize( aDrawInf ).Height()) / nWidth ) : 0 ); 1033 } 1034 1035 sal_uInt16 SwTxtNode::GetWidthOfLeadingTabs() const 1036 { 1037 sal_uInt16 nRet = 0; 1038 1039 xub_StrLen nIdx = 0; 1040 sal_Unicode cCh; 1041 1042 while ( nIdx < GetTxt().Len() && 1043 ( '\t' == ( cCh = GetTxt().GetChar( nIdx ) ) || 1044 ' ' == cCh ) ) 1045 ++nIdx; 1046 1047 if ( nIdx > 0 ) 1048 { 1049 SwPosition aPos( *this ); 1050 aPos.nContent += nIdx; 1051 1052 // Find the non-follow text frame: 1053 SwIterator<SwTxtFrm,SwTxtNode> aIter( *this ); 1054 for( SwTxtFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() ) 1055 { 1056 // Only consider master frames: 1057 if ( !pFrm->IsFollow() ) 1058 { 1059 SWRECTFN( pFrm ) 1060 SwRect aRect; 1061 pFrm->GetCharRect( aRect, aPos ); 1062 nRet = (sal_uInt16) 1063 ( pFrm->IsRightToLeft() ? 1064 (pFrm->*fnRect->fnGetPrtRight)() - (aRect.*fnRect->fnGetRight)() : 1065 (aRect.*fnRect->fnGetLeft)() - (pFrm->*fnRect->fnGetPrtLeft)() ); 1066 break; 1067 } 1068 } 1069 } 1070 1071 return nRet; 1072 } 1073