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 774 case RES_TXTATR_FIELD : 775 case RES_TXTATR_ANNOTATION : 776 { 777 SwField *pFld = (SwField*)pHint->GetFmtFld().GetField(); 778 const String aTxt = pFld->ExpandField(true); 779 if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0, 780 aTxt.Len() ) ) 781 nAdd = 20; 782 break; 783 } 784 785 default: aArg.nWordWidth = nOldWidth; 786 aArg.nWordAdd = nOldAdd; 787 788 } 789 aIter.SeekAndChgAttrIter( ++nIdx, pOut ); 790 } 791 break; 792 } 793 } 794 if( (long)rMax < aArg.nRowWidth ) 795 rMax = aArg.nRowWidth; 796 797 nLROffset += rSpace.GetRight(); 798 799 rAbsMin += nLROffset; 800 rAbsMin += nAdd; 801 rMin += nLROffset; 802 rMin += nAdd; 803 if( (long)rMin < aNodeArgs.nMinWidth ) 804 rMin = aNodeArgs.nMinWidth; 805 if( (long)rAbsMin < aNodeArgs.nMinWidth ) 806 rAbsMin = aNodeArgs.nMinWidth; 807 rMax += aNodeArgs.nMaxWidth; 808 rMax += nLROffset; 809 rMax += nAdd; 810 if( rMax < rMin ) // z.B. Rahmen mit Durchlauf gehen zunaechst nur 811 rMax = rMin; // in das Minimum ein 812 pOut->SetMapMode( aOldMap ); 813 } 814 815 /************************************************************************* 816 * SwTxtNode::GetScalingOfSelectedText() 817 * 818 * Calculates the width of the text part specified by nStt and nEnd, 819 * the height of the line containing nStt is devided by this width, 820 * indicating the scaling factor, if the text part is rotated. 821 * Having CH_BREAKs in the text part, this method returns the scaling 822 * factor for the longest of the text parts separated by the CH_BREAKs. 823 * 824 * changing this method very likely requires changing of "GetMinMaxSize" 825 *************************************************************************/ 826 827 sal_uInt16 SwTxtNode::GetScalingOfSelectedText( xub_StrLen nStt, xub_StrLen nEnd ) 828 const 829 { 830 ViewShell* pSh = NULL; 831 OutputDevice* pOut = NULL; 832 GetDoc()->GetEditShell( &pSh ); 833 834 if ( pSh ) 835 pOut = &pSh->GetRefDev(); 836 else 837 { 838 //Zugriff ueber StarONE, es muss keine Shell existieren oder aktiv sein. 839 if ( getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE) ) 840 pOut = GetpApp()->GetDefaultDevice(); 841 else 842 pOut = getIDocumentDeviceAccess()->getReferenceDevice( true ); 843 } 844 845 ASSERT( pOut, "GetScalingOfSelectedText without outdev" ) 846 847 MapMode aOldMap( pOut->GetMapMode() ); 848 pOut->SetMapMode( MapMode( MAP_TWIP ) ); 849 850 if ( nStt == nEnd ) 851 { 852 if ( !pBreakIt->GetBreakIter().is() ) 853 return 100; 854 855 SwScriptInfo aScriptInfo; 856 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo ); 857 aIter.SeekAndChgAttrIter( nStt, pOut ); 858 859 Boundary aBound = 860 pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), nStt, 861 pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ), 862 WordType::DICTIONARY_WORD, sal_True ); 863 864 if ( nStt == aBound.startPos ) 865 { 866 // cursor is at left or right border of word 867 pOut->SetMapMode( aOldMap ); 868 return 100; 869 } 870 871 nStt = (xub_StrLen)aBound.startPos; 872 nEnd = (xub_StrLen)aBound.endPos; 873 874 if ( nStt == nEnd ) 875 { 876 pOut->SetMapMode( aOldMap ); 877 return 100; 878 } 879 } 880 881 SwScriptInfo aScriptInfo; 882 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo ); 883 884 // We do not want scaling attributes to be considered during this 885 // calculation. For this, we push a temporary scaling attribute with 886 // scaling value 100 and priority flag on top of the scaling stack 887 SwAttrHandler& rAH = aIter.GetAttrHandler(); 888 SvxCharScaleWidthItem aItem(100, RES_CHRATR_SCALEW); 889 SwTxtAttrEnd aAttr( aItem, nStt, nEnd ); 890 aAttr.SetPriorityAttr( sal_True ); 891 rAH.PushAndChg( aAttr, *(aIter.GetFnt()) ); 892 893 xub_StrLen nIdx = nStt; 894 895 sal_uLong nWidth = 0; 896 sal_uLong nProWidth = 0; 897 898 while( nIdx < nEnd ) 899 { 900 aIter.SeekAndChgAttrIter( nIdx, pOut ); 901 902 // scan for end of portion 903 xub_StrLen nNextChg = aIter.GetNextAttr(); 904 xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx ); 905 if( nNextChg > nStop ) 906 nNextChg = nStop; 907 908 nStop = nIdx; 909 xub_Unicode cChar = CH_BLANK; 910 SwTxtAttr* pHint = NULL; 911 912 // stop at special characters in [ nIdx, nNextChg ] 913 while( nStop < nEnd && nStop < nNextChg ) 914 { 915 cChar = m_Text.GetChar( nStop ); 916 if ( 917 CH_TAB == cChar || 918 CH_BREAK == cChar || 919 CHAR_HARDBLANK == cChar || 920 CHAR_HARDHYPHEN == cChar || 921 CHAR_SOFTHYPHEN == cChar || 922 ( 923 (CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar) && 924 (0 == (pHint = aIter.GetAttr(nStop))) 925 ) 926 ) 927 { 928 break; 929 } 930 else 931 ++nStop; 932 } 933 934 // calculate text widths up to cChar 935 if ( nStop > nIdx ) 936 { 937 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nIdx, nStop - nIdx ); 938 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); 939 } 940 941 nIdx = nStop; 942 aIter.SeekAndChgAttrIter( nIdx, pOut ); 943 944 if ( cChar == CH_BREAK ) 945 { 946 nWidth = Max( nWidth, nProWidth ); 947 nProWidth = 0; 948 nIdx++; 949 } 950 else if ( cChar == CH_TAB ) 951 { 952 // tab receives width of one space 953 XubString sTmp( CH_BLANK ); 954 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 ); 955 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); 956 nIdx++; 957 } 958 else if ( cChar == CHAR_SOFTHYPHEN ) 959 ++nIdx; 960 else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN ) 961 { 962 XubString sTmp( cChar ); 963 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 ); 964 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); 965 nIdx++; 966 } 967 else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || CH_TXTATR_INWORD ) ) 968 { 969 switch( pHint->Which() ) 970 { 971 case RES_TXTATR_FTN : 972 { 973 const XubString aTxt = pHint->GetFtn().GetNumStr(); 974 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() ); 975 976 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); 977 break; 978 } 979 980 case RES_TXTATR_FIELD : 981 case RES_TXTATR_ANNOTATION : 982 { 983 SwField *pFld = (SwField*)pHint->GetFmtFld().GetField(); 984 String const aTxt = pFld->ExpandField(true); 985 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() ); 986 987 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width(); 988 break; 989 } 990 991 default: 992 { 993 // any suggestions for a default action? 994 } 995 } // end of switch 996 nIdx++; 997 } // end of while 998 } 999 1000 nWidth = Max( nWidth, nProWidth ); 1001 1002 // search for a text frame this node belongs to 1003 SwIterator<SwTxtFrm,SwTxtNode> aFrmIter( *this ); 1004 SwTxtFrm* pFrm = 0; 1005 for( SwTxtFrm* pTmpFrm = aFrmIter.First(); pTmpFrm; pTmpFrm = aFrmIter.Next() ) 1006 { 1007 if ( pTmpFrm->GetOfst() <= nStt && 1008 ( !pTmpFrm->GetFollow() || 1009 pTmpFrm->GetFollow()->GetOfst() > nStt ) ) 1010 { 1011 pFrm = pTmpFrm; 1012 break; 1013 } 1014 } 1015 1016 // search for the line containing nStt 1017 if ( pFrm && pFrm->HasPara() ) 1018 { 1019 SwTxtInfo aInf( pFrm ); 1020 SwTxtIter aLine( pFrm, &aInf ); 1021 aLine.CharToLine( nStt ); 1022 pOut->SetMapMode( aOldMap ); 1023 return (sal_uInt16)( nWidth ? 1024 ( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 ); 1025 } 1026 // no frame or no paragraph, we take the height of the character 1027 // at nStt as line height 1028 1029 aIter.SeekAndChgAttrIter( nStt, pOut ); 1030 pOut->SetMapMode( aOldMap ); 1031 1032 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nStt, 1 ); 1033 return (sal_uInt16) 1034 ( nWidth ? ((100 * aIter.GetFnt()->_GetTxtSize( aDrawInf ).Height()) / nWidth ) : 0 ); 1035 } 1036 1037 sal_uInt16 SwTxtNode::GetWidthOfLeadingTabs() const 1038 { 1039 sal_uInt16 nRet = 0; 1040 1041 xub_StrLen nIdx = 0; 1042 sal_Unicode cCh; 1043 1044 while ( nIdx < GetTxt().Len() && 1045 ( '\t' == ( cCh = GetTxt().GetChar( nIdx ) ) || 1046 ' ' == cCh ) ) 1047 ++nIdx; 1048 1049 if ( nIdx > 0 ) 1050 { 1051 SwPosition aPos( *this ); 1052 aPos.nContent += nIdx; 1053 1054 // Find the non-follow text frame: 1055 SwIterator<SwTxtFrm,SwTxtNode> aIter( *this ); 1056 for( SwTxtFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() ) 1057 { 1058 // Only consider master frames: 1059 if ( !pFrm->IsFollow() ) 1060 { 1061 SWRECTFN( pFrm ) 1062 SwRect aRect; 1063 pFrm->GetCharRect( aRect, aPos ); 1064 nRet = (sal_uInt16) 1065 ( pFrm->IsRightToLeft() ? 1066 (pFrm->*fnRect->fnGetPrtRight)() - (aRect.*fnRect->fnGetRight)() : 1067 (aRect.*fnRect->fnGetLeft)() - (pFrm->*fnRect->fnGetPrtLeft)() ); 1068 break; 1069 } 1070 } 1071 } 1072 1073 return nRet; 1074 } 1075