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