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_sc.hxx" 26 27 28 29 30 // INCLUDE --------------------------------------------------------------- 31 32 #include "scitems.hxx" 33 #include <editeng/eeitem.hxx> 34 35 36 #include <editeng/adjitem.hxx> 37 #include <svx/algitem.hxx> 38 #include <editeng/brshitem.hxx> 39 #include <svtools/colorcfg.hxx> 40 #include <editeng/colritem.hxx> 41 #include <editeng/editobj.hxx> 42 #include <editeng/editstat.hxx> 43 #include <editeng/fhgtitem.hxx> 44 #include <editeng/forbiddencharacterstable.hxx> 45 #include <editeng/frmdiritem.hxx> 46 #include <editeng/langitem.hxx> 47 #include <svx/rotmodit.hxx> 48 #include <editeng/scripttypeitem.hxx> 49 #include <editeng/udlnitem.hxx> 50 #include <editeng/unolingu.hxx> 51 #include <svl/zforlist.hxx> 52 #include <svl/zformat.hxx> 53 #include <vcl/svapp.hxx> 54 #include <vcl/metric.hxx> 55 #include <vcl/outdev.hxx> 56 #include <vcl/pdfextoutdevdata.hxx> 57 58 #ifndef _SVSTDARR_USHORTS 59 #define _SVSTDARR_USHORTS 60 #include <svl/svstdarr.hxx> 61 #endif 62 63 #include "output.hxx" 64 #include "document.hxx" 65 #include "cell.hxx" 66 #include "attrib.hxx" 67 #include "patattr.hxx" 68 #include "cellform.hxx" 69 #include "editutil.hxx" 70 #include "progress.hxx" 71 #include "scmod.hxx" 72 #include "fillinfo.hxx" 73 74 #include <math.h> 75 76 //! Autofilter-Breite mit column.cxx zusammenfassen 77 #define DROPDOWN_BITMAP_SIZE 18 78 79 #define DRAWTEXT_MAX 32767 80 81 const sal_uInt16 SC_SHRINKAGAIN_MAX = 7; 82 83 // STATIC DATA ----------------------------------------------------------- 84 85 86 // ----------------------------------------------------------------------- 87 88 class ScDrawStringsVars 89 { 90 ScOutputData* pOutput; // Verbindung 91 92 const ScPatternAttr* pPattern; // Attribute 93 const SfxItemSet* pCondSet; // aus bedingter Formatierung 94 95 Font aFont; // aus Attributen erzeugt 96 FontMetric aMetric; 97 long nAscentPixel; // always pixels 98 SvxCellOrientation eAttrOrient; 99 SvxCellHorJustify eAttrHorJust; 100 SvxCellVerJustify eAttrVerJust; 101 const SvxMarginItem* pMargin; 102 sal_uInt16 nIndent; 103 sal_Bool bRotated; 104 105 String aString; // Inhalte 106 Size aTextSize; 107 long nOriginalWidth; 108 long nMaxDigitWidth; 109 long nSignWidth; 110 long nDotWidth; 111 long nExpWidth; 112 113 ScBaseCell* pLastCell; 114 sal_uLong nValueFormat; 115 sal_Bool bLineBreak; 116 sal_Bool bRepeat; 117 sal_Bool bShrink; 118 119 sal_Bool bPixelToLogic; 120 sal_Bool bCellContrast; 121 122 Color aBackConfigColor; // used for ScPatternAttr::GetFont calls 123 Color aTextConfigColor; 124 125 public: 126 ScDrawStringsVars(ScOutputData* pData, sal_Bool bPTL); 127 ~ScDrawStringsVars(); 128 129 // SetPattern = ex-SetVars 130 // SetPatternSimple: ohne Font 131 132 void SetPattern( const ScPatternAttr* pNew, const SfxItemSet* pSet, ScBaseCell* pCell, sal_uInt8 nScript ); 133 void SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet ); 134 135 sal_Bool SetText( ScBaseCell* pCell ); // sal_True -> pOldPattern vergessen 136 void SetTextToWidthOrHash( ScBaseCell* pCell, long nWidth ); 137 void SetAutoText( const String& rAutoText ); 138 139 const ScPatternAttr* GetPattern() const { return pPattern; } 140 SvxCellOrientation GetOrient() const { return eAttrOrient; } 141 SvxCellHorJustify GetHorJust() const { return eAttrHorJust; } 142 SvxCellVerJustify GetVerJust() const { return eAttrVerJust; } 143 const SvxMarginItem* GetMargin() const { return pMargin; } 144 145 sal_uInt16 GetLeftTotal() const { return pMargin->GetLeftMargin() + nIndent; } 146 147 const String& GetString() const { return aString; } 148 const Size& GetTextSize() const { return aTextSize; } 149 long GetOriginalWidth() const { return nOriginalWidth; } 150 151 sal_uLong GetResultValueFormat( const ScBaseCell* pCell ) const; 152 153 sal_uLong GetValueFormat() const { return nValueFormat; } 154 sal_Bool GetLineBreak() const { return bLineBreak; } 155 sal_Bool IsRepeat() const { return bRepeat; } 156 sal_Bool IsShrink() const { return bShrink; } 157 158 long GetAscent() const { return nAscentPixel; } 159 sal_Bool IsRotated() const { return bRotated; } 160 161 void SetShrinkScale( long nScale, sal_uInt8 nScript ); 162 163 sal_Bool HasCondHeight() const { return pCondSet && SFX_ITEM_SET == 164 pCondSet->GetItemState( ATTR_FONT_HEIGHT, sal_True ); } 165 166 sal_Bool HasEditCharacters() const; 167 168 private: 169 void SetHashText(); 170 long GetMaxDigitWidth(); // in logic units 171 long GetSignWidth(); 172 long GetDotWidth(); 173 long GetExpWidth(); 174 void TextChanged(); 175 }; 176 177 //================================================================== 178 179 ScDrawStringsVars::ScDrawStringsVars(ScOutputData* pData, sal_Bool bPTL) : 180 pOutput ( pData ), 181 pPattern ( NULL ), 182 pCondSet ( NULL ), 183 eAttrOrient ( SVX_ORIENTATION_STANDARD ), 184 eAttrHorJust( SVX_HOR_JUSTIFY_STANDARD ), 185 eAttrVerJust( SVX_VER_JUSTIFY_BOTTOM ), 186 pMargin ( NULL ), 187 nIndent ( 0 ), 188 bRotated ( sal_False ), 189 nOriginalWidth( 0 ), 190 nMaxDigitWidth( 0 ), 191 nSignWidth( 0 ), 192 nDotWidth( 0 ), 193 nExpWidth( 0 ), 194 pLastCell ( NULL ), 195 nValueFormat( 0 ), 196 bLineBreak ( sal_False ), 197 bRepeat ( sal_False ), 198 bShrink ( sal_False ), 199 bPixelToLogic( bPTL ) 200 { 201 ScModule* pScMod = SC_MOD(); 202 // #105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True) 203 bCellContrast = pOutput->bUseStyleColor && 204 Application::GetSettings().GetStyleSettings().GetHighContrastMode(); 205 206 const svtools::ColorConfig& rColorConfig = pScMod->GetColorConfig(); 207 aBackConfigColor.SetColor( rColorConfig.GetColorValue(svtools::DOCCOLOR).nColor ); 208 aTextConfigColor.SetColor( rColorConfig.GetColorValue(svtools::FONTCOLOR).nColor ); 209 } 210 211 ScDrawStringsVars::~ScDrawStringsVars() 212 { 213 } 214 215 void ScDrawStringsVars::SetShrinkScale( long nScale, sal_uInt8 nScript ) 216 { 217 // text remains valid, size is updated 218 219 OutputDevice* pDev = pOutput->pDev; 220 OutputDevice* pRefDevice = pOutput->pRefDevice; 221 OutputDevice* pFmtDevice = pOutput->pFmtDevice; 222 223 // call GetFont with a modified fraction, use only the height 224 225 Fraction aFraction( nScale, 100 ); 226 if ( !bPixelToLogic ) 227 aFraction *= pOutput->aZoomY; 228 Font aTmpFont; 229 pPattern->GetFont( aTmpFont, SC_AUTOCOL_RAW, pFmtDevice, &aFraction, pCondSet, nScript ); 230 long nNewHeight = aTmpFont.GetHeight(); 231 if ( nNewHeight > 0 ) 232 aFont.SetHeight( nNewHeight ); 233 234 // set font and dependent variables as in SetPattern 235 236 pDev->SetFont( aFont ); 237 if ( pFmtDevice != pDev ) 238 pFmtDevice->SetFont( aFont ); 239 240 aMetric = pFmtDevice->GetFontMetric(); 241 if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 ) 242 { 243 OutputDevice* pDefaultDev = Application::GetDefaultDevice(); 244 MapMode aOld = pDefaultDev->GetMapMode(); 245 pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() ); 246 aMetric = pDefaultDev->GetFontMetric( aFont ); 247 pDefaultDev->SetMapMode( aOld ); 248 } 249 250 nAscentPixel = aMetric.GetAscent(); 251 if ( bPixelToLogic ) 252 nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height(); 253 254 SetAutoText( aString ); // same text again, to get text size 255 } 256 257 void ScDrawStringsVars::SetPattern( const ScPatternAttr* pNew, const SfxItemSet* pSet, 258 ScBaseCell* pCell, sal_uInt8 nScript ) 259 { 260 nMaxDigitWidth = 0; 261 nSignWidth = 0; 262 nDotWidth = 0; 263 nExpWidth = 0; 264 265 pPattern = pNew; 266 pCondSet = pSet; 267 268 // pPattern auswerten 269 270 OutputDevice* pDev = pOutput->pDev; 271 OutputDevice* pRefDevice = pOutput->pRefDevice; 272 OutputDevice* pFmtDevice = pOutput->pFmtDevice; 273 274 // Font 275 276 ScAutoFontColorMode eColorMode; 277 if ( pOutput->bUseStyleColor ) 278 { 279 if ( pOutput->bForceAutoColor ) 280 eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREALL : SC_AUTOCOL_IGNOREFONT; 281 else 282 eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREBACK : SC_AUTOCOL_DISPLAY; 283 } 284 else 285 eColorMode = SC_AUTOCOL_PRINT; 286 287 if ( bPixelToLogic ) 288 pPattern->GetFont( aFont, eColorMode, pFmtDevice, NULL, pCondSet, nScript, 289 &aBackConfigColor, &aTextConfigColor ); 290 else 291 pPattern->GetFont( aFont, eColorMode, pFmtDevice, &pOutput->aZoomY, pCondSet, nScript, 292 &aBackConfigColor, &aTextConfigColor ); 293 aFont.SetAlign(ALIGN_BASELINE); 294 295 // Orientierung 296 297 eAttrOrient = pPattern->GetCellOrientation( pCondSet ); 298 299 // alignment 300 301 eAttrHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue(); 302 303 eAttrVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&)pPattern->GetItem( ATTR_VER_JUSTIFY, pCondSet )).GetValue(); 304 if ( eAttrVerJust == SVX_VER_JUSTIFY_STANDARD ) 305 eAttrVerJust = SVX_VER_JUSTIFY_BOTTOM; 306 307 // line break 308 309 bLineBreak = ((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK, pCondSet )).GetValue(); 310 311 // handle "repeat" alignment 312 313 bRepeat = ( eAttrHorJust == SVX_HOR_JUSTIFY_REPEAT ); 314 if ( bRepeat ) 315 { 316 // "repeat" disables rotation (before constructing the font) 317 eAttrOrient = SVX_ORIENTATION_STANDARD; 318 319 // #i31843# "repeat" with "line breaks" is treated as default alignment (but rotation is still disabled) 320 if ( bLineBreak ) 321 eAttrHorJust = SVX_HOR_JUSTIFY_STANDARD; 322 } 323 324 short nRot; 325 switch (eAttrOrient) 326 { 327 case SVX_ORIENTATION_STANDARD: 328 nRot = 0; 329 bRotated = (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE, pCondSet )).GetValue() != 0) && 330 !bRepeat; 331 break; 332 case SVX_ORIENTATION_STACKED: 333 nRot = 0; 334 bRotated = sal_False; 335 break; 336 case SVX_ORIENTATION_TOPBOTTOM: 337 nRot = 2700; 338 bRotated = sal_False; 339 break; 340 case SVX_ORIENTATION_BOTTOMTOP: 341 nRot = 900; 342 bRotated = sal_False; 343 break; 344 default: 345 DBG_ERROR("Falscher SvxCellOrientation Wert"); 346 nRot = 0; 347 bRotated = sal_False; 348 break; 349 } 350 aFont.SetOrientation( nRot ); 351 352 // Syntax-Modus 353 354 if (pOutput->bSyntaxMode) 355 pOutput->SetSyntaxColor( &aFont, pCell ); 356 357 pDev->SetFont( aFont ); 358 if ( pFmtDevice != pDev ) 359 pFmtDevice->SetFont( aFont ); 360 361 aMetric = pFmtDevice->GetFontMetric(); 362 363 // 364 // Wenn auf dem Drucker das Leading 0 ist, gibt es Probleme 365 // -> Metric vom Bildschirm nehmen (wie EditEngine!) 366 // 367 368 if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 ) 369 { 370 OutputDevice* pDefaultDev = Application::GetDefaultDevice(); 371 MapMode aOld = pDefaultDev->GetMapMode(); 372 pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() ); 373 aMetric = pDefaultDev->GetFontMetric( aFont ); 374 pDefaultDev->SetMapMode( aOld ); 375 } 376 377 nAscentPixel = aMetric.GetAscent(); 378 if ( bPixelToLogic ) 379 nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height(); 380 381 Color aULineColor( ((const SvxUnderlineItem&)pPattern->GetItem( ATTR_FONT_UNDERLINE, pCondSet )).GetColor() ); 382 pDev->SetTextLineColor( aULineColor ); 383 384 Color aOLineColor( ((const SvxOverlineItem&)pPattern->GetItem( ATTR_FONT_OVERLINE, pCondSet )).GetColor() ); 385 pDev->SetOverlineColor( aOLineColor ); 386 387 // Zahlenformat 388 389 // sal_uLong nOld = nValueFormat; 390 nValueFormat = pPattern->GetNumberFormat( pOutput->pDoc->GetFormatTable(), pCondSet ); 391 392 /* s.u. 393 if (nValueFormat != nOld) 394 pLastCell = NULL; // immer neu formatieren 395 */ 396 // Raender 397 398 pMargin = (const SvxMarginItem*)&pPattern->GetItem( ATTR_MARGIN, pCondSet ); 399 if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT ) 400 nIndent = ((const SfxUInt16Item&)pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue(); 401 else 402 nIndent = 0; 403 404 // "Shrink to fit" 405 406 bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue(); 407 408 // zumindest die Text-Groesse muss neu geholt werden 409 //! unterscheiden, und den Text nicht neu vom Numberformatter holen? 410 411 pLastCell = NULL; 412 } 413 414 void ScDrawStringsVars::SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet ) 415 { 416 nMaxDigitWidth = 0; 417 nSignWidth = 0; 418 nDotWidth = 0; 419 nExpWidth = 0; 420 // wird gerufen, wenn sich die Font-Variablen nicht aendern (!StringDiffer) 421 422 pPattern = pNew; 423 pCondSet = pSet; //! noetig ??? 424 425 // Zahlenformat 426 427 sal_uLong nOld = nValueFormat; 428 // nValueFormat = pPattern->GetNumberFormat( pFormatter ); 429 const SfxPoolItem* pFormItem; 430 if ( !pCondSet || pCondSet->GetItemState(ATTR_VALUE_FORMAT,sal_True,&pFormItem) != SFX_ITEM_SET ) 431 pFormItem = &pPattern->GetItem(ATTR_VALUE_FORMAT); 432 const SfxPoolItem* pLangItem; 433 if ( !pCondSet || pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT,sal_True,&pLangItem) != SFX_ITEM_SET ) 434 pLangItem = &pPattern->GetItem(ATTR_LANGUAGE_FORMAT); 435 nValueFormat = pOutput->pDoc->GetFormatTable()->GetFormatForLanguageIfBuiltIn( 436 ((SfxUInt32Item*)pFormItem)->GetValue(), 437 ((SvxLanguageItem*)pLangItem)->GetLanguage() ); 438 439 if (nValueFormat != nOld) 440 pLastCell = NULL; // immer neu formatieren 441 442 // Raender 443 444 pMargin = (const SvxMarginItem*)&pPattern->GetItem( ATTR_MARGIN, pCondSet ); 445 446 if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT ) 447 nIndent = ((const SfxUInt16Item&)pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue(); 448 else 449 nIndent = 0; 450 451 // "Shrink to fit" 452 453 bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue(); 454 } 455 456 inline sal_Bool SameValue( ScBaseCell* pCell, ScBaseCell* pOldCell ) // pCell ist != 0 457 { 458 return pOldCell && pOldCell->GetCellType() == CELLTYPE_VALUE && 459 pCell->GetCellType() == CELLTYPE_VALUE && 460 ((ScValueCell*)pCell)->GetValue() == ((ScValueCell*)pOldCell)->GetValue(); 461 } 462 463 sal_Bool ScDrawStringsVars::SetText( ScBaseCell* pCell ) 464 { 465 sal_Bool bChanged = sal_False; 466 467 if (pCell) 468 { 469 if ( !SameValue( pCell, pLastCell ) ) 470 { 471 pLastCell = pCell; // Zelle merken 472 473 Color* pColor; 474 sal_uLong nFormat = GetValueFormat(); 475 ScCellFormat::GetString( pCell, 476 nFormat, aString, &pColor, 477 *pOutput->pDoc->GetFormatTable(), 478 pOutput->bShowNullValues, 479 pOutput->bShowFormulas, 480 ftCheck ); 481 482 if (aString.Len() > DRAWTEXT_MAX) 483 aString.Erase(DRAWTEXT_MAX); 484 485 if ( pColor && !pOutput->bSyntaxMode && !( pOutput->bUseStyleColor && pOutput->bForceAutoColor ) ) 486 { 487 OutputDevice* pDev = pOutput->pDev; 488 aFont.SetColor(*pColor); 489 pDev->SetFont( aFont ); // nur fuer Ausgabe 490 bChanged = sal_True; 491 pLastCell = NULL; // naechstes Mal wieder hierherkommen 492 } 493 494 TextChanged(); 495 } 496 // sonst String/Groesse behalten 497 } 498 else 499 { 500 aString.Erase(); 501 pLastCell = NULL; 502 aTextSize = Size(0,0); 503 nOriginalWidth = 0; 504 } 505 506 return bChanged; 507 } 508 509 void ScDrawStringsVars::SetHashText() 510 { 511 SetAutoText( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("###")) ); 512 } 513 514 void ScDrawStringsVars::SetTextToWidthOrHash( ScBaseCell* pCell, long nWidth ) 515 { 516 // #i113045# do the single-character width calculations in logic units 517 if (bPixelToLogic) 518 nWidth = pOutput->pRefDevice->PixelToLogic(Size(nWidth,0)).Width(); 519 520 if (!pCell) 521 return; 522 523 CellType eType = pCell->GetCellType(); 524 if (eType != CELLTYPE_VALUE && eType != CELLTYPE_FORMULA) 525 // must be a value or formula cell. 526 return; 527 528 if (eType == CELLTYPE_FORMULA) 529 { 530 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell); 531 if (pFCell->GetErrCode() != 0 || pOutput->bShowFormulas) 532 { 533 SetHashText(); // If the error string doesn't fit, always use "###". Also for "display formulas" (#i116691#) 534 return; 535 } 536 // If it's formula, the result must be a value. 537 if (!pFCell->IsValue()) 538 return; 539 } 540 541 sal_uLong nFormat = GetResultValueFormat(pCell); 542 if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0) 543 { 544 // Not 'General' number format. Set hash text and bail out. 545 SetHashText(); 546 return; 547 } 548 549 double fVal = (eType == CELLTYPE_VALUE) ? 550 static_cast<ScValueCell*>(pCell)->GetValue() : static_cast<ScFormulaCell*>(pCell)->GetValue(); 551 552 const SvNumberformat* pNumFormat = pOutput->pDoc->GetFormatTable()->GetEntry(nFormat); 553 if (!pNumFormat) 554 return; 555 556 long nMaxDigit = GetMaxDigitWidth(); 557 sal_uInt16 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit); 558 559 if (!pNumFormat->GetOutputString(fVal, nNumDigits, aString)) 560 // Failed to get output string. Bail out. 561 return; 562 563 sal_uInt8 nSignCount = 0, nDecimalCount = 0, nExpCount = 0; 564 xub_StrLen nLen = aString.Len(); 565 sal_Unicode cDecSep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator.getStr()[0]; 566 for (xub_StrLen i = 0; i < nLen; ++i) 567 { 568 sal_Unicode c = aString.GetChar(i); 569 if (c == sal_Unicode('-')) 570 ++nSignCount; 571 else if (c == cDecSep) 572 ++nDecimalCount; 573 else if (c == sal_Unicode('E')) 574 ++nExpCount; 575 } 576 577 // #i112250# A small value might be formatted as "0" when only counting the digits, 578 // but fit into the column when considering the smaller width of the decimal separator. 579 if (aString.EqualsAscii("0") && fVal != 0.0) 580 nDecimalCount = 1; 581 582 if (nDecimalCount) 583 nWidth += (nMaxDigit - GetDotWidth()) * nDecimalCount; 584 if (nSignCount) 585 nWidth += (nMaxDigit - GetSignWidth()) * nSignCount; 586 if (nExpCount) 587 nWidth += (nMaxDigit - GetExpWidth()) * nExpCount; 588 589 if (nDecimalCount || nSignCount || nExpCount) 590 { 591 // Re-calculate. 592 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit); 593 if (!pNumFormat->GetOutputString(fVal, nNumDigits, aString)) 594 // Failed to get output string. Bail out. 595 return; 596 } 597 598 long nActualTextWidth = pOutput->pFmtDevice->GetTextWidth(aString); 599 if (nActualTextWidth > nWidth) 600 { 601 // Even after the decimal adjustment the text doesn't fit. Give up. 602 SetHashText(); 603 return; 604 } 605 606 TextChanged(); 607 pLastCell = NULL; // #i113022# equal cell and format in another column may give different string 608 } 609 610 void ScDrawStringsVars::SetAutoText( const String& rAutoText ) 611 { 612 aString = rAutoText; 613 614 OutputDevice* pRefDevice = pOutput->pRefDevice; 615 OutputDevice* pFmtDevice = pOutput->pFmtDevice; 616 aTextSize.Width() = pFmtDevice->GetTextWidth( aString ); 617 aTextSize.Height() = pFmtDevice->GetTextHeight(); 618 619 if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER ) 620 { 621 double fMul = pOutput->GetStretch(); 622 aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5); 623 } 624 625 aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent(); 626 if ( GetOrient() != SVX_ORIENTATION_STANDARD ) 627 { 628 long nTemp = aTextSize.Height(); 629 aTextSize.Height() = aTextSize.Width(); 630 aTextSize.Width() = nTemp; 631 } 632 633 nOriginalWidth = aTextSize.Width(); 634 if ( bPixelToLogic ) 635 aTextSize = pRefDevice->LogicToPixel( aTextSize ); 636 637 pLastCell = NULL; // derselbe Text kann in der naechsten Zelle wieder passen 638 } 639 640 long ScDrawStringsVars::GetMaxDigitWidth() 641 { 642 if (nMaxDigitWidth > 0) 643 return nMaxDigitWidth; 644 645 sal_Char cZero = '0'; 646 for (sal_Char i = 0; i < 10; ++i) 647 { 648 sal_Char cDigit = cZero + i; 649 long n = pOutput->pFmtDevice->GetTextWidth(String(cDigit)); 650 nMaxDigitWidth = ::std::max(nMaxDigitWidth, n); 651 } 652 return nMaxDigitWidth; 653 } 654 655 long ScDrawStringsVars::GetSignWidth() 656 { 657 if (nSignWidth > 0) 658 return nSignWidth; 659 660 nSignWidth = pOutput->pFmtDevice->GetTextWidth(String('-')); 661 return nSignWidth; 662 } 663 664 long ScDrawStringsVars::GetDotWidth() 665 { 666 if (nDotWidth > 0) 667 return nDotWidth; 668 669 const ::rtl::OUString& sep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator; 670 nDotWidth = pOutput->pFmtDevice->GetTextWidth(sep); 671 return nDotWidth; 672 } 673 674 long ScDrawStringsVars::GetExpWidth() 675 { 676 if (nExpWidth > 0) 677 return nExpWidth; 678 679 nExpWidth = pOutput->pFmtDevice->GetTextWidth(String('E')); 680 return nExpWidth; 681 } 682 683 void ScDrawStringsVars::TextChanged() 684 { 685 OutputDevice* pRefDevice = pOutput->pRefDevice; 686 OutputDevice* pFmtDevice = pOutput->pFmtDevice; 687 aTextSize.Width() = pFmtDevice->GetTextWidth( aString ); 688 aTextSize.Height() = pFmtDevice->GetTextHeight(); 689 690 if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER ) 691 { 692 double fMul = pOutput->GetStretch(); 693 aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5); 694 } 695 696 aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent(); 697 if ( GetOrient() != SVX_ORIENTATION_STANDARD ) 698 { 699 long nTemp = aTextSize.Height(); 700 aTextSize.Height() = aTextSize.Width(); 701 aTextSize.Width() = nTemp; 702 } 703 704 nOriginalWidth = aTextSize.Width(); 705 if ( bPixelToLogic ) 706 aTextSize = pRefDevice->LogicToPixel( aTextSize ); 707 } 708 709 sal_Bool ScDrawStringsVars::HasEditCharacters() const 710 { 711 static const sal_Unicode pChars[] = 712 { 713 CHAR_NBSP, CHAR_SHY, CHAR_ZWSP, CHAR_LRM, CHAR_RLM, CHAR_NBHY, CHAR_ZWNBSP, 0 714 }; 715 return aString.SearchChar( pChars ) != STRING_NOTFOUND; 716 } 717 718 sal_uLong ScDrawStringsVars::GetResultValueFormat( const ScBaseCell* pCell ) const 719 { 720 // Get the effective number format, including formula result types. 721 // This assumes that a formula cell has already been calculated. 722 723 if ( (nValueFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) 724 return static_cast<const ScFormulaCell*>(pCell)->GetStandardFormat(*pOutput->pDoc->GetFormatTable(), nValueFormat); 725 else 726 return nValueFormat; 727 } 728 729 //================================================================== 730 731 double ScOutputData::GetStretch() 732 { 733 if ( pRefDevice->IsMapMode() ) 734 { 735 // #95920# If a non-trivial MapMode is set, its scale is now already 736 // taken into account in the OutputDevice's font handling 737 // (OutputDevice::ImplNewFont, see #95414#). 738 // The old handling below is only needed for pixel output. 739 return 1.0; 740 } 741 742 // calculation in double is faster than Fraction multiplication 743 // and doesn't overflow 744 745 if ( pRefDevice == pFmtDevice ) 746 { 747 MapMode aOld = pRefDevice->GetMapMode(); 748 return ((double)aOld.GetScaleY()) / ((double)aOld.GetScaleX()) * ((double)aZoomY) / ((double)aZoomX); 749 } 750 else 751 { 752 // when formatting for printer, device map mode has already been taken care of 753 return ((double)aZoomY) / ((double)aZoomX); 754 } 755 } 756 757 //================================================================== 758 759 // 760 // output strings 761 // 762 763 void lcl_DoHyperlinkResult( OutputDevice* pDev, const Rectangle& rRect, ScBaseCell* pCell ) 764 { 765 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() ); 766 767 String aCellText; 768 String aURL; 769 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) 770 { 771 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell); 772 if ( pFCell->IsHyperLinkCell() ) 773 pFCell->GetURLResult( aURL, aCellText ); 774 } 775 776 if ( aURL.Len() && pPDFData ) 777 { 778 vcl::PDFExtOutDevBookmarkEntry aBookmark; 779 aBookmark.nLinkId = pPDFData->CreateLink( rRect ); 780 aBookmark.aBookmark = aURL; 781 std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFData->GetBookmarks(); 782 rBookmarks.push_back( aBookmark ); 783 } 784 } 785 786 void ScOutputData::SetSyntaxColor( Font* pFont, ScBaseCell* pCell ) 787 { 788 if (pCell) 789 { 790 switch (pCell->GetCellType()) 791 { 792 case CELLTYPE_VALUE: 793 pFont->SetColor( *pValueColor ); 794 break; 795 case CELLTYPE_STRING: 796 pFont->SetColor( *pTextColor ); 797 break; 798 case CELLTYPE_FORMULA: 799 pFont->SetColor( *pFormulaColor ); 800 break; 801 default: 802 { 803 // added to avoid warnings 804 } 805 } 806 } 807 } 808 809 void lcl_SetEditColor( EditEngine& rEngine, const Color& rColor ) 810 { 811 ESelection aSel( 0, 0, rEngine.GetParagraphCount(), 0 ); 812 SfxItemSet aSet( rEngine.GetEmptyItemSet() ); 813 aSet.Put( SvxColorItem( rColor, EE_CHAR_COLOR ) ); 814 rEngine.QuickSetAttribs( aSet, aSel ); 815 // function is called with update mode set to FALSE 816 } 817 818 void ScOutputData::SetEditSyntaxColor( EditEngine& rEngine, ScBaseCell* pCell ) 819 { 820 if (pCell) 821 { 822 Color aColor; 823 switch (pCell->GetCellType()) 824 { 825 case CELLTYPE_VALUE: 826 aColor = *pValueColor; 827 break; 828 case CELLTYPE_STRING: 829 aColor = *pTextColor; 830 break; 831 case CELLTYPE_FORMULA: 832 aColor = *pFormulaColor; 833 break; 834 default: 835 { 836 // added to avoid warnings 837 } 838 } 839 lcl_SetEditColor( rEngine, aColor ); 840 } 841 } 842 843 sal_Bool ScOutputData::GetMergeOrigin( SCCOL nX, SCROW nY, SCSIZE nArrY, 844 SCCOL& rOverX, SCROW& rOverY, 845 sal_Bool bVisRowChanged ) 846 { 847 sal_Bool bDoMerge = sal_False; 848 sal_Bool bIsLeft = ( nX == nVisX1 ); 849 sal_Bool bIsTop = ( nY == nVisY1 ) || bVisRowChanged; 850 851 CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nX+1]; 852 if ( pInfo->bHOverlapped && pInfo->bVOverlapped ) 853 bDoMerge = bIsLeft && bIsTop; 854 else if ( pInfo->bHOverlapped ) 855 bDoMerge = bIsLeft; 856 else if ( pInfo->bVOverlapped ) 857 bDoMerge = bIsTop; 858 859 // weiter solange versteckt 860 /* if (!bDoMerge) 861 return sal_False; 862 */ 863 864 rOverX = nX; 865 rOverY = nY; 866 sal_Bool bHOver = pInfo->bHOverlapped; 867 sal_Bool bVOver = pInfo->bVOverlapped; 868 sal_Bool bHidden; 869 870 while (bHOver) // nY konstant 871 { 872 --rOverX; 873 bHidden = pDoc->ColHidden(rOverX, nTab); 874 if ( !bDoMerge && !bHidden ) 875 return sal_False; 876 877 if (rOverX >= nX1 && !bHidden) 878 { 879 // rVirtPosX -= pRowInfo[0].pCellInfo[rOverX+1].nWidth; 880 bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped; 881 bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped; 882 } 883 else 884 { 885 // if (!bClipVirt) 886 // rVirtPosX -= (long) (pDoc->GetColWidth( rOverX, nTab ) * nPPTX); 887 sal_uInt16 nOverlap = ((ScMergeFlagAttr*)pDoc->GetAttr( 888 rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue(); 889 bHOver = ((nOverlap & SC_MF_HOR) != 0); 890 bVOver = ((nOverlap & SC_MF_VER) != 0); 891 } 892 } 893 894 while (bVOver) 895 { 896 --rOverY; 897 bHidden = pDoc->RowHidden(rOverY, nTab); 898 if ( !bDoMerge && !bHidden ) 899 return sal_False; 900 901 if (nArrY>0) 902 --nArrY; // lokale Kopie ! 903 904 if (rOverX >= nX1 && rOverY >= nY1 && 905 !pDoc->ColHidden(rOverX, nTab) && 906 !pDoc->RowHidden(rOverY, nTab) && 907 pRowInfo[nArrY].nRowNo == rOverY) 908 { 909 // rVirtPosY -= pRowInfo[nArrY].nHeight; 910 bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped; 911 bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped; 912 } 913 else 914 { 915 // if (!bClipVirt) 916 // rVirtPosY -= (long) (pDoc->GetRowHeight( rOverY, nTab ) * nPPTY); 917 sal_uInt16 nOverlap = ((ScMergeFlagAttr*)pDoc->GetAttr( 918 rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue(); 919 bHOver = ((nOverlap & SC_MF_HOR) != 0); 920 bVOver = ((nOverlap & SC_MF_VER) != 0); 921 } 922 } 923 924 return sal_True; 925 } 926 927 inline sal_Bool StringDiffer( const ScPatternAttr*& rpOldPattern, const ScPatternAttr*& rpNewPattern ) 928 { 929 DBG_ASSERT( rpNewPattern, "pNewPattern" ); 930 931 if ( rpNewPattern == rpOldPattern ) 932 return sal_False; 933 else if ( !rpOldPattern ) 934 return sal_True; 935 else if ( &rpNewPattern->GetItem( ATTR_FONT ) != &rpOldPattern->GetItem( ATTR_FONT ) ) 936 return sal_True; 937 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT ) ) 938 return sal_True; 939 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT ) ) 940 return sal_True; 941 else if ( &rpNewPattern->GetItem( ATTR_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_HEIGHT ) ) 942 return sal_True; 943 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) ) 944 return sal_True; 945 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) ) 946 return sal_True; 947 else if ( &rpNewPattern->GetItem( ATTR_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_WEIGHT ) ) 948 return sal_True; 949 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) ) 950 return sal_True; 951 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) ) 952 return sal_True; 953 else if ( &rpNewPattern->GetItem( ATTR_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_FONT_POSTURE ) ) 954 return sal_True; 955 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_POSTURE ) ) 956 return sal_True; 957 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_POSTURE ) ) 958 return sal_True; 959 else if ( &rpNewPattern->GetItem( ATTR_FONT_UNDERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_UNDERLINE ) ) 960 return sal_True; 961 else if ( &rpNewPattern->GetItem( ATTR_FONT_OVERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_OVERLINE ) ) 962 return sal_True; 963 else if ( &rpNewPattern->GetItem( ATTR_FONT_WORDLINE ) != &rpOldPattern->GetItem( ATTR_FONT_WORDLINE ) ) 964 return sal_True; 965 else if ( &rpNewPattern->GetItem( ATTR_FONT_CROSSEDOUT ) != &rpOldPattern->GetItem( ATTR_FONT_CROSSEDOUT ) ) 966 return sal_True; 967 else if ( &rpNewPattern->GetItem( ATTR_FONT_CONTOUR ) != &rpOldPattern->GetItem( ATTR_FONT_CONTOUR ) ) 968 return sal_True; 969 else if ( &rpNewPattern->GetItem( ATTR_FONT_SHADOWED ) != &rpOldPattern->GetItem( ATTR_FONT_SHADOWED ) ) 970 return sal_True; 971 else if ( &rpNewPattern->GetItem( ATTR_FONT_COLOR ) != &rpOldPattern->GetItem( ATTR_FONT_COLOR ) ) 972 return sal_True; 973 else if ( &rpNewPattern->GetItem( ATTR_HOR_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY ) ) 974 return sal_True; 975 else if ( &rpNewPattern->GetItem( ATTR_VER_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY ) ) 976 return sal_True; 977 else if ( &rpNewPattern->GetItem( ATTR_STACKED ) != &rpOldPattern->GetItem( ATTR_STACKED ) ) 978 return sal_True; 979 else if ( &rpNewPattern->GetItem( ATTR_LINEBREAK ) != &rpOldPattern->GetItem( ATTR_LINEBREAK ) ) 980 return sal_True; 981 else if ( &rpNewPattern->GetItem( ATTR_MARGIN ) != &rpOldPattern->GetItem( ATTR_MARGIN ) ) 982 return sal_True; 983 else if ( &rpNewPattern->GetItem( ATTR_ROTATE_VALUE ) != &rpOldPattern->GetItem( ATTR_ROTATE_VALUE ) ) 984 return sal_True; 985 else if ( &rpNewPattern->GetItem( ATTR_FORBIDDEN_RULES ) != &rpOldPattern->GetItem( ATTR_FORBIDDEN_RULES ) ) 986 return sal_True; 987 else if ( &rpNewPattern->GetItem( ATTR_FONT_EMPHASISMARK ) != &rpOldPattern->GetItem( ATTR_FONT_EMPHASISMARK ) ) 988 return sal_True; 989 else if ( &rpNewPattern->GetItem( ATTR_FONT_RELIEF ) != &rpOldPattern->GetItem( ATTR_FONT_RELIEF ) ) 990 return sal_True; 991 else if ( &rpNewPattern->GetItem( ATTR_BACKGROUND ) != &rpOldPattern->GetItem( ATTR_BACKGROUND ) ) 992 return sal_True; // needed with automatic text color 993 else 994 { 995 rpOldPattern = rpNewPattern; 996 return sal_False; 997 } 998 } 999 1000 inline void lcl_CreateInterpretProgress( sal_Bool& bProgress, ScDocument* pDoc, 1001 ScFormulaCell* pFCell ) 1002 { 1003 if ( !bProgress && pFCell->GetDirty() ) 1004 { 1005 ScProgress::CreateInterpretProgress( pDoc, sal_True ); 1006 bProgress = sal_True; 1007 } 1008 } 1009 1010 inline sal_uInt8 GetScriptType( ScDocument* pDoc, ScBaseCell* pCell, 1011 const ScPatternAttr* pPattern, 1012 const SfxItemSet* pCondSet ) 1013 { 1014 return pDoc->GetCellScriptType( pCell, pPattern->GetNumberFormat( pDoc->GetFormatTable(), pCondSet ) ); 1015 } 1016 1017 inline sal_Bool IsAmbiguousScript( sal_uInt8 nScript ) 1018 { 1019 return ( nScript != SCRIPTTYPE_LATIN && 1020 nScript != SCRIPTTYPE_ASIAN && 1021 nScript != SCRIPTTYPE_COMPLEX ); 1022 } 1023 1024 sal_Bool ScOutputData::IsEmptyCellText( RowInfo* pThisRowInfo, SCCOL nX, SCROW nY ) 1025 { 1026 // pThisRowInfo may be NULL 1027 1028 sal_Bool bEmpty; 1029 if ( pThisRowInfo && nX <= nX2 ) 1030 bEmpty = pThisRowInfo->pCellInfo[nX+1].bEmptyCellText; 1031 else 1032 bEmpty = ( pDoc->GetCell( ScAddress( nX, nY, nTab ) ) == NULL ); 1033 1034 if ( !bEmpty && ( nX < nX1 || nX > nX2 || !pThisRowInfo ) ) 1035 { 1036 // for the range nX1..nX2 in RowInfo, cell protection attribute is already evaluated 1037 // into bEmptyCellText in ScDocument::FillInfo / lcl_HidePrint (printfun) 1038 1039 sal_Bool bIsPrint = ( eType == OUTTYPE_PRINTER ); 1040 1041 if ( bIsPrint || bTabProtected ) 1042 { 1043 const ScProtectionAttr* pAttr = (const ScProtectionAttr*) 1044 pDoc->GetEffItem( nX, nY, nTab, ATTR_PROTECTION ); 1045 if ( bIsPrint && pAttr->GetHidePrint() ) 1046 bEmpty = sal_True; 1047 else if ( bTabProtected ) 1048 { 1049 if ( pAttr->GetHideCell() ) 1050 bEmpty = sal_True; 1051 else if ( bShowFormulas && pAttr->GetHideFormula() ) 1052 { 1053 ScBaseCell* pCell = pDoc->GetCell( ScAddress( nX, nY, nTab ) ); 1054 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) 1055 bEmpty = sal_True; 1056 } 1057 } 1058 } 1059 } 1060 return bEmpty; 1061 } 1062 1063 void ScOutputData::GetVisibleCell( SCCOL nCol, SCROW nRow, SCTAB nTabP, ScBaseCell*& rpCell ) 1064 { 1065 pDoc->GetCell( nCol, nRow, nTabP, rpCell ); 1066 if ( rpCell && IsEmptyCellText( NULL, nCol, nRow ) ) 1067 rpCell = NULL; 1068 } 1069 1070 sal_Bool ScOutputData::IsAvailable( SCCOL nX, SCROW nY ) 1071 { 1072 // apply the same logic here as in DrawStrings/DrawEdit: 1073 // Stop at non-empty or merged or overlapped cell, 1074 // where a note is empty as well as a cell that's hidden by protection settings 1075 1076 const ScBaseCell* pCell = pDoc->GetCell( ScAddress( nX, nY, nTab ) ); 1077 if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE && !IsEmptyCellText( NULL, nX, nY ) ) 1078 { 1079 return sal_False; 1080 } 1081 1082 const ScPatternAttr* pPattern = pDoc->GetPattern( nX, nY, nTab ); 1083 if ( ((const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE)).IsMerged() || 1084 ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).IsOverlapped() ) 1085 { 1086 return sal_False; 1087 } 1088 1089 return sal_True; 1090 } 1091 1092 // nX, nArrY: loop variables from DrawStrings / DrawEdit 1093 // nPosX, nPosY: corresponding positions for nX, nArrY 1094 // nCellX, nCellY: position of the cell that contains the text 1095 // nNeeded: Text width, including margin 1096 // rPattern: cell format at nCellX, nCellY 1097 // nHorJustify: horizontal alignment (visual) to determine which cells to use for long strings 1098 // bCellIsValue: if set, don't extend into empty cells 1099 // bBreak: if set, don't extend, and don't set clip marks (but rLeftClip/rRightClip is set) 1100 // bOverwrite: if set, also extend into non-empty cells (for rotated text) 1101 // rParam output: various area parameters. 1102 1103 void ScOutputData::GetOutputArea( SCCOL nX, SCSIZE nArrY, long nPosX, long nPosY, 1104 SCCOL nCellX, SCROW nCellY, long nNeeded, 1105 const ScPatternAttr& rPattern, 1106 sal_uInt16 nHorJustify, bool bCellIsValue, 1107 bool bBreak, bool bOverwrite, 1108 OutputAreaParam& rParam ) 1109 { 1110 // rThisRowInfo may be for a different row than nCellY, is still used for clip marks 1111 RowInfo& rThisRowInfo = pRowInfo[nArrY]; 1112 1113 long nLayoutSign = bLayoutRTL ? -1 : 1; 1114 1115 long nCellPosX = nPosX; // find nCellX position, starting at nX/nPosX 1116 SCCOL nCompCol = nX; 1117 while ( nCellX > nCompCol ) 1118 { 1119 //! extra member function for width? 1120 long nColWidth = ( nCompCol <= nX2 ) ? 1121 pRowInfo[0].pCellInfo[nCompCol+1].nWidth : 1122 (long) ( pDoc->GetColWidth( nCompCol, nTab ) * nPPTX ); 1123 nCellPosX += nColWidth * nLayoutSign; 1124 ++nCompCol; 1125 } 1126 while ( nCellX < nCompCol ) 1127 { 1128 --nCompCol; 1129 long nColWidth = ( nCompCol <= nX2 ) ? 1130 pRowInfo[0].pCellInfo[nCompCol+1].nWidth : 1131 (long) ( pDoc->GetColWidth( nCompCol, nTab ) * nPPTX ); 1132 nCellPosX -= nColWidth * nLayoutSign; 1133 } 1134 1135 long nCellPosY = nPosY; // find nCellY position, starting at nArrY/nPosY 1136 SCSIZE nCompArr = nArrY; 1137 SCROW nCompRow = pRowInfo[nCompArr].nRowNo; 1138 while ( nCellY > nCompRow ) 1139 { 1140 if ( nCompArr + 1 < nArrCount ) 1141 { 1142 nCellPosY += pRowInfo[nCompArr].nHeight; 1143 ++nCompArr; 1144 nCompRow = pRowInfo[nCompArr].nRowNo; 1145 } 1146 else 1147 { 1148 sal_uInt16 nDocHeight = pDoc->GetRowHeight( nCompRow, nTab ); 1149 if ( nDocHeight ) 1150 nCellPosY += (long) ( nDocHeight * nPPTY ); 1151 ++nCompRow; 1152 } 1153 } 1154 nCellPosY -= (long) pDoc->GetScaledRowHeight( nCellY, nCompRow-1, nTab, nPPTY ); 1155 1156 const ScMergeAttr* pMerge = (const ScMergeAttr*)&rPattern.GetItem( ATTR_MERGE ); 1157 sal_Bool bMerged = pMerge->IsMerged(); 1158 long nMergeCols = pMerge->GetColMerge(); 1159 if ( nMergeCols == 0 ) 1160 nMergeCols = 1; 1161 long nMergeRows = pMerge->GetRowMerge(); 1162 if ( nMergeRows == 0 ) 1163 nMergeRows = 1; 1164 1165 long i; 1166 long nMergeSizeX = 0; 1167 for ( i=0; i<nMergeCols; i++ ) 1168 { 1169 long nColWidth = ( nCellX+i <= nX2 ) ? 1170 pRowInfo[0].pCellInfo[nCellX+i+1].nWidth : 1171 (long) ( pDoc->GetColWidth( sal::static_int_cast<SCCOL>(nCellX+i), nTab ) * nPPTX ); 1172 nMergeSizeX += nColWidth; 1173 } 1174 long nMergeSizeY = 0; 1175 short nDirect = 0; 1176 if ( rThisRowInfo.nRowNo == nCellY ) 1177 { 1178 // take first row's height from row info 1179 nMergeSizeY += rThisRowInfo.nHeight; 1180 nDirect = 1; // skip in loop 1181 } 1182 // following rows always from document 1183 nMergeSizeY += (long) pDoc->GetScaledRowHeight( nCellY+nDirect, nCellY+nMergeRows-1, nTab, nPPTY); 1184 1185 --nMergeSizeX; // leave out the grid horizontally, also for alignment (align between grid lines) 1186 1187 rParam.mnColWidth = nMergeSizeX; // store the actual column width. 1188 1189 // 1190 // construct the rectangles using logical left/right values (justify is called at the end) 1191 // 1192 1193 // rAlignRect is the single cell or merged area, used for alignment. 1194 1195 rParam.maAlignRect.Left() = nCellPosX; 1196 rParam.maAlignRect.Right() = nCellPosX + ( nMergeSizeX - 1 ) * nLayoutSign; 1197 rParam.maAlignRect.Top() = nCellPosY; 1198 rParam.maAlignRect.Bottom() = nCellPosY + nMergeSizeY - 1; 1199 1200 // rClipRect is all cells that are used for output. 1201 // For merged cells this is the same as rAlignRect, otherwise neighboring cells can also be used. 1202 1203 rParam.maClipRect = rParam.maAlignRect; 1204 if ( nNeeded > nMergeSizeX ) 1205 { 1206 SvxCellHorJustify eHorJust = (SvxCellHorJustify)nHorJustify; 1207 1208 long nMissing = nNeeded - nMergeSizeX; 1209 long nLeftMissing = 0; 1210 long nRightMissing = 0; 1211 switch ( eHorJust ) 1212 { 1213 case SVX_HOR_JUSTIFY_LEFT: 1214 nRightMissing = nMissing; 1215 break; 1216 case SVX_HOR_JUSTIFY_RIGHT: 1217 nLeftMissing = nMissing; 1218 break; 1219 case SVX_HOR_JUSTIFY_CENTER: 1220 nLeftMissing = nMissing / 2; 1221 nRightMissing = nMissing - nLeftMissing; 1222 break; 1223 default: 1224 { 1225 // added to avoid warnings 1226 } 1227 } 1228 1229 // nLeftMissing, nRightMissing are logical, eHorJust values are visual 1230 if ( bLayoutRTL ) 1231 ::std::swap( nLeftMissing, nRightMissing ); 1232 1233 SCCOL nRightX = nCellX; 1234 SCCOL nLeftX = nCellX; 1235 if ( !bMerged && !bCellIsValue && !bBreak ) 1236 { 1237 // look for empty cells into which the text can be extended 1238 1239 while ( nRightMissing > 0 && nRightX < MAXCOL && ( bOverwrite || IsAvailable( nRightX+1, nCellY ) ) ) 1240 { 1241 ++nRightX; 1242 long nAdd = (long) ( pDoc->GetColWidth( nRightX, nTab ) * nPPTX ); 1243 nRightMissing -= nAdd; 1244 rParam.maClipRect.Right() += nAdd * nLayoutSign; 1245 1246 if ( rThisRowInfo.nRowNo == nCellY && nRightX >= nX1 && nRightX <= nX2 ) 1247 rThisRowInfo.pCellInfo[nRightX].bHideGrid = sal_True; 1248 } 1249 1250 while ( nLeftMissing > 0 && nLeftX > 0 && ( bOverwrite || IsAvailable( nLeftX-1, nCellY ) ) ) 1251 { 1252 if ( rThisRowInfo.nRowNo == nCellY && nLeftX >= nX1 && nLeftX <= nX2 ) 1253 rThisRowInfo.pCellInfo[nLeftX].bHideGrid = sal_True; 1254 1255 --nLeftX; 1256 long nAdd = (long) ( pDoc->GetColWidth( nLeftX, nTab ) * nPPTX ); 1257 nLeftMissing -= nAdd; 1258 rParam.maClipRect.Left() -= nAdd * nLayoutSign; 1259 } 1260 } 1261 1262 // Set flag and reserve space for clipping mark triangle, 1263 // even if rThisRowInfo isn't for nCellY (merged cells). 1264 if ( nRightMissing > 0 && bMarkClipped && nRightX >= nX1 && nRightX <= nX2 && !bBreak && !bCellIsValue ) 1265 { 1266 rThisRowInfo.pCellInfo[nRightX+1].nClipMark |= SC_CLIPMARK_RIGHT; 1267 bAnyClipped = sal_True; 1268 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX ); 1269 rParam.maClipRect.Right() -= nMarkPixel * nLayoutSign; 1270 } 1271 if ( nLeftMissing > 0 && bMarkClipped && nLeftX >= nX1 && nLeftX <= nX2 && !bBreak && !bCellIsValue ) 1272 { 1273 rThisRowInfo.pCellInfo[nLeftX+1].nClipMark |= SC_CLIPMARK_LEFT; 1274 bAnyClipped = sal_True; 1275 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX ); 1276 rParam.maClipRect.Left() += nMarkPixel * nLayoutSign; 1277 } 1278 1279 rParam.mbLeftClip = ( nLeftMissing > 0 ); 1280 rParam.mbRightClip = ( nRightMissing > 0 ); 1281 } 1282 else 1283 { 1284 rParam.mbLeftClip = rParam.mbRightClip = sal_False; 1285 1286 // leave space for AutoFilter on screen 1287 // (for automatic line break: only if not formatting for printer, as in ScColumn::GetNeededSize) 1288 1289 if ( eType==OUTTYPE_WINDOW && 1290 ( static_cast<const ScMergeFlagAttr&>(rPattern.GetItem(ATTR_MERGE_FLAG)).GetValue() & SC_MF_AUTO ) && 1291 ( !bBreak || pRefDevice == pFmtDevice ) ) 1292 { 1293 // filter drop-down width is now independent from row height 1294 const long nFilter = DROPDOWN_BITMAP_SIZE; 1295 sal_Bool bFit = ( nNeeded + nFilter <= nMergeSizeX ); 1296 if ( bFit || bCellIsValue ) 1297 { 1298 // content fits even in the remaining area without the filter button 1299 // -> align within that remaining area 1300 1301 rParam.maAlignRect.Right() -= nFilter * nLayoutSign; 1302 rParam.maClipRect.Right() -= nFilter * nLayoutSign; 1303 1304 // if a number doesn't fit, don't hide part of the number behind the button 1305 // -> set clip flags, so "###" replacement is used (but also within the smaller area) 1306 1307 if ( !bFit ) 1308 rParam.mbLeftClip = rParam.mbRightClip = sal_True; 1309 } 1310 } 1311 } 1312 1313 // justify both rectangles for alignment calculation, use with DrawText etc. 1314 1315 rParam.maAlignRect.Justify(); 1316 rParam.maClipRect.Justify(); 1317 1318 #if 0 1319 //! Test !!! 1320 pDev->Push(); 1321 pDev->SetLineColor(); 1322 pDev->SetFillColor( COL_LIGHTGREEN ); 1323 pDev->DrawRect( pDev->PixelToLogic(rParam.maClipRect) ); 1324 pDev->DrawRect( rParam.maClipRect ); // print preview 1325 pDev->Pop(); 1326 //! Test !!! 1327 #endif 1328 } 1329 1330 void ScOutputData::DrawStrings( sal_Bool bPixelToLogic ) 1331 { 1332 DBG_ASSERT( pDev == pRefDevice || 1333 pDev->GetMapMode().GetMapUnit() == pRefDevice->GetMapMode().GetMapUnit(), 1334 "DrawStrings: unterschiedliche MapUnits ?!?!" ); 1335 1336 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() ); 1337 1338 sal_Bool bWasIdleDisabled = pDoc->IsIdleDisabled(); 1339 pDoc->DisableIdle( sal_True ); 1340 Size aMinSize = pRefDevice->PixelToLogic(Size(0,100)); // erst darueber wird ausgegeben 1341 // sal_uInt32 nMinHeight = aMinSize.Height() / 200; // 1/2 Pixel 1342 1343 ScDrawStringsVars aVars( this, bPixelToLogic ); 1344 1345 sal_Bool bProgress = sal_False; 1346 1347 long nInitPosX = nScrX; 1348 if ( bLayoutRTL ) 1349 nInitPosX += nMirrorW - 1; // pixels 1350 long nLayoutSign = bLayoutRTL ? -1 : 1; 1351 1352 SCCOL nLastContentCol = MAXCOL; 1353 if ( nX2 < MAXCOL ) 1354 nLastContentCol = sal::static_int_cast<SCCOL>( 1355 nLastContentCol - pDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) ); 1356 SCCOL nLoopStartX = nX1; 1357 if ( nX1 > 0 ) 1358 --nLoopStartX; // start before nX1 for rest of long text to the left 1359 1360 // variables for GetOutputArea 1361 OutputAreaParam aAreaParam; 1362 sal_Bool bCellIsValue = sal_False; 1363 long nNeededWidth = 0; 1364 SvxCellHorJustify eOutHorJust = SVX_HOR_JUSTIFY_STANDARD; 1365 const ScPatternAttr* pPattern = NULL; 1366 const SfxItemSet* pCondSet = NULL; 1367 const ScPatternAttr* pOldPattern = NULL; 1368 const SfxItemSet* pOldCondSet = NULL; 1369 sal_uInt8 nOldScript = 0; 1370 1371 long nPosY = nScrY; 1372 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++) 1373 { 1374 RowInfo* pThisRowInfo = &pRowInfo[nArrY]; 1375 if ( pThisRowInfo->bChanged ) 1376 { 1377 SCROW nY = pThisRowInfo->nRowNo; 1378 // long nCellHeight = (long) pThisRowInfo->nHeight; 1379 long nPosX = nInitPosX; 1380 if ( nLoopStartX < nX1 ) 1381 nPosX -= pRowInfo[0].pCellInfo[nLoopStartX+1].nWidth * nLayoutSign; 1382 for (SCCOL nX=nLoopStartX; nX<=nX2; nX++) 1383 { 1384 sal_Bool bMergeEmpty = sal_False; 1385 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1]; 1386 sal_Bool bEmpty = nX < nX1 || pInfo->bEmptyCellText; 1387 1388 SCCOL nCellX = nX; // position where the cell really starts 1389 SCROW nCellY = nY; 1390 sal_Bool bDoCell = sal_False; 1391 sal_Bool bNeedEdit = sal_False; 1392 1393 // 1394 // Part of a merged cell? 1395 // 1396 1397 sal_Bool bOverlapped = ( pInfo->bHOverlapped || pInfo->bVOverlapped ); 1398 if ( bOverlapped ) 1399 { 1400 bEmpty = sal_True; 1401 1402 SCCOL nOverX; // start of the merged cells 1403 SCROW nOverY; 1404 sal_Bool bVisChanged = !pRowInfo[nArrY-1].bChanged; 1405 if (GetMergeOrigin( nX,nY, nArrY, nOverX,nOverY, bVisChanged )) 1406 { 1407 nCellX = nOverX; 1408 nCellY = nOverY; 1409 bDoCell = sal_True; 1410 } 1411 else 1412 bMergeEmpty = sal_True; 1413 } 1414 1415 // 1416 // Rest of a long text further to the left? 1417 // 1418 1419 if ( bEmpty && !bMergeEmpty && nX < nX1 && !bOverlapped ) 1420 { 1421 SCCOL nTempX=nX1; 1422 while (nTempX > 0 && IsEmptyCellText( pThisRowInfo, nTempX, nY )) 1423 --nTempX; 1424 1425 if ( nTempX < nX1 && 1426 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) && 1427 !pDoc->HasAttrib( nTempX,nY,nTab, nX1,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) ) 1428 { 1429 nCellX = nTempX; 1430 bDoCell = sal_True; 1431 } 1432 } 1433 1434 // 1435 // Rest of a long text further to the right? 1436 // 1437 1438 if ( bEmpty && !bMergeEmpty && nX == nX2 && !bOverlapped ) 1439 { 1440 // don't have to look further than nLastContentCol 1441 1442 SCCOL nTempX=nX; 1443 while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY )) 1444 ++nTempX; 1445 1446 if ( nTempX > nX && 1447 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) && 1448 !pDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) ) 1449 { 1450 nCellX = nTempX; 1451 bDoCell = sal_True; 1452 } 1453 } 1454 1455 // 1456 // normal visible cell 1457 // 1458 1459 if (!bEmpty) 1460 bDoCell = sal_True; 1461 1462 // 1463 // don't output the cell that's being edited 1464 // 1465 1466 if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow ) 1467 bDoCell = sal_False; 1468 1469 // 1470 // output the cell text 1471 // 1472 1473 ScBaseCell* pCell = NULL; 1474 if (bDoCell) 1475 { 1476 if ( nCellY == nY && nCellX == nX && nCellX >= nX1 && nCellX <= nX2 ) 1477 pCell = pThisRowInfo->pCellInfo[nCellX+1].pCell; 1478 else 1479 GetVisibleCell( nCellX, nCellY, nTab, pCell ); // get from document 1480 if ( !pCell ) 1481 bDoCell = sal_False; 1482 else if ( pCell->GetCellType() == CELLTYPE_EDIT ) 1483 bNeedEdit = sal_True; 1484 } 1485 if (bDoCell && !bNeedEdit) 1486 { 1487 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 ) 1488 { 1489 CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1]; 1490 pPattern = rCellInfo.pPatternAttr; 1491 pCondSet = rCellInfo.pConditionSet; 1492 1493 if ( !pPattern ) 1494 { 1495 // #i68085# pattern from cell info for hidden columns is null, 1496 // test for null is quicker than using column flags 1497 pPattern = pDoc->GetPattern( nCellX, nCellY, nTab ); 1498 pCondSet = pDoc->GetCondResult( nCellX, nCellY, nTab ); 1499 } 1500 } 1501 else // get from document 1502 { 1503 pPattern = pDoc->GetPattern( nCellX, nCellY, nTab ); 1504 pCondSet = pDoc->GetCondResult( nCellX, nCellY, nTab ); 1505 } 1506 1507 sal_uInt8 nScript = GetScriptType( pDoc, pCell, pPattern, pCondSet ); 1508 if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType(); 1509 if ( pPattern != pOldPattern || pCondSet != pOldCondSet || 1510 nScript != nOldScript || bSyntaxMode ) 1511 { 1512 if ( StringDiffer(pOldPattern,pPattern) || 1513 pCondSet != pOldCondSet || nScript != nOldScript || bSyntaxMode ) 1514 aVars.SetPattern( pPattern, pCondSet, pCell, nScript ); 1515 else 1516 aVars.SetPatternSimple( pPattern, pCondSet ); 1517 pOldPattern = pPattern; 1518 pOldCondSet = pCondSet; 1519 nOldScript = nScript; 1520 } 1521 1522 // use edit engine for rotated, stacked or mixed-script text 1523 if ( aVars.GetOrient() == SVX_ORIENTATION_STACKED || 1524 aVars.IsRotated() || IsAmbiguousScript(nScript) ) 1525 bNeedEdit = sal_True; 1526 } 1527 if (bDoCell && !bNeedEdit) 1528 { 1529 sal_Bool bFormulaCell = (pCell->GetCellType() == CELLTYPE_FORMULA ); 1530 if ( bFormulaCell ) 1531 lcl_CreateInterpretProgress( bProgress, pDoc, (ScFormulaCell*)pCell ); 1532 if ( aVars.SetText(pCell) ) 1533 pOldPattern = NULL; 1534 bNeedEdit = aVars.HasEditCharacters() || 1535 (bFormulaCell && ((ScFormulaCell*)pCell)->IsMultilineResult()); 1536 } 1537 long nTotalMargin = 0; 1538 if (bDoCell && !bNeedEdit) 1539 { 1540 CellType eCellType = pCell->GetCellType(); 1541 bCellIsValue = ( eCellType == CELLTYPE_VALUE ); 1542 if ( eCellType == CELLTYPE_FORMULA ) 1543 { 1544 ScFormulaCell* pFCell = (ScFormulaCell*)pCell; 1545 bCellIsValue = pFCell->IsRunning() || pFCell->IsValue(); 1546 } 1547 1548 eOutHorJust = ( aVars.GetHorJust() != SVX_HOR_JUSTIFY_STANDARD ) ? 1549 aVars.GetHorJust() : 1550 ( bCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT ); 1551 1552 if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT ) 1553 eOutHorJust = SVX_HOR_JUSTIFY_LEFT; // repeat is not yet implemented 1554 1555 sal_Bool bBreak = ( aVars.GetLineBreak() || aVars.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK ); 1556 1557 // #i111387# #o11817313# disable automatic line breaks only for "General" number format 1558 if ( bBreak && bCellIsValue && ( aVars.GetResultValueFormat(pCell) % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 ) 1559 bBreak = sal_False; 1560 1561 sal_Bool bRepeat = aVars.IsRepeat() && !bBreak; 1562 sal_Bool bShrink = aVars.IsShrink() && !bBreak && !bRepeat; 1563 1564 nTotalMargin = 1565 static_cast<long>(aVars.GetLeftTotal() * nPPTX) + 1566 static_cast<long>(aVars.GetMargin()->GetRightMargin() * nPPTX); 1567 1568 nNeededWidth = aVars.GetTextSize().Width() + nTotalMargin; 1569 1570 // GetOutputArea gives justfied rectangles 1571 GetOutputArea( nX, nArrY, nPosX, nPosY, nCellX, nCellY, nNeededWidth, 1572 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust), 1573 bCellIsValue || bRepeat || bShrink, bBreak, sal_False, 1574 aAreaParam ); 1575 1576 if ( bShrink ) 1577 { 1578 if ( aVars.GetOrient() != SVX_ORIENTATION_STANDARD ) 1579 { 1580 // Only horizontal scaling is handled here. 1581 // DrawEdit is used to vertically scale 90 deg rotated text. 1582 bNeedEdit = sal_True; 1583 } 1584 else if ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) // horizontal 1585 { 1586 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin; 1587 long nScaleSize = aVars.GetTextSize().Width(); // without margin 1588 1589 if ( nScaleSize > 0 ) // 0 if the text is empty (formulas, number formats) 1590 { 1591 long nScale = ( nAvailable * 100 ) / nScaleSize; 1592 1593 aVars.SetShrinkScale( nScale, nOldScript ); 1594 long nNewSize = aVars.GetTextSize().Width(); 1595 1596 sal_uInt16 nShrinkAgain = 0; 1597 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX ) 1598 { 1599 // If the text is still too large, reduce the scale again by 10%, until it fits, 1600 // at most 7 times (it's less than 50% of the calculated scale then). 1601 1602 nScale = ( nScale * 9 ) / 10; 1603 aVars.SetShrinkScale( nScale, nOldScript ); 1604 nNewSize = aVars.GetTextSize().Width(); 1605 ++nShrinkAgain; 1606 } 1607 // If even at half the size the font still isn't rendered smaller, 1608 // fall back to normal clipping (showing ### for numbers). 1609 if ( nNewSize <= nAvailable ) 1610 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = sal_False; 1611 1612 pOldPattern = NULL; 1613 } 1614 } 1615 } 1616 1617 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip ) 1618 { 1619 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin; 1620 long nRepeatSize = aVars.GetTextSize().Width(); // without margin 1621 // When formatting for the printer, the text sizes don't always add up. 1622 // Round down (too few repetitions) rather than exceeding the cell size then: 1623 if ( pFmtDevice != pRefDevice ) 1624 ++nRepeatSize; 1625 if ( nRepeatSize > 0 ) 1626 { 1627 long nRepeatCount = nAvailable / nRepeatSize; 1628 if ( nRepeatCount > 1 ) 1629 { 1630 String aCellStr = aVars.GetString(); 1631 String aRepeated = aCellStr; 1632 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ ) 1633 aRepeated.Append( aCellStr ); 1634 aVars.SetAutoText( aRepeated ); 1635 } 1636 } 1637 } 1638 1639 // use edit engine if automatic line breaks are needed 1640 if ( bBreak ) 1641 { 1642 if ( aVars.GetOrient() == SVX_ORIENTATION_STANDARD ) 1643 bNeedEdit = ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ); 1644 else 1645 { 1646 long nHeight = aVars.GetTextSize().Height() + 1647 (long)(aVars.GetMargin()->GetTopMargin()*nPPTY) + 1648 (long)(aVars.GetMargin()->GetBottomMargin()*nPPTY); 1649 bNeedEdit = ( nHeight > aAreaParam.maClipRect.GetHeight() ); 1650 } 1651 } 1652 } 1653 if (bNeedEdit) 1654 { 1655 // mark the cell in CellInfo to be drawn in DrawEdit: 1656 // Cells to the left are marked directly, cells to the 1657 // right are handled by the flag for nX2 1658 SCCOL nMarkX = ( nCellX <= nX2 ) ? nCellX : nX2; 1659 RowInfo* pMarkRowInfo = ( nCellY == nY ) ? pThisRowInfo : &pRowInfo[0]; 1660 pMarkRowInfo->pCellInfo[nMarkX+1].bEditEngine = sal_True; 1661 bDoCell = sal_False; // don't draw here 1662 } 1663 if ( bDoCell ) 1664 { 1665 if ( bCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) ) 1666 { 1667 // Adjust the decimals to fit the available column width. 1668 aVars.SetTextToWidthOrHash(pCell, aAreaParam.mnColWidth - nTotalMargin); 1669 nNeededWidth = aVars.GetTextSize().Width() + 1670 (long) ( aVars.GetLeftTotal() * nPPTX ) + 1671 (long) ( aVars.GetMargin()->GetRightMargin() * nPPTX ); 1672 if ( nNeededWidth <= aAreaParam.maClipRect.GetWidth() ) 1673 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = sal_False; 1674 1675 // If the "###" replacement doesn't fit into the cells, no clip marks 1676 // are shown, as the "###" already denotes too little space. 1677 // The rectangles from the first GetOutputArea call remain valid. 1678 } 1679 1680 long nJustPosX = aAreaParam.maAlignRect.Left(); // "justified" - effect of alignment will be added 1681 long nJustPosY = aAreaParam.maAlignRect.Top(); 1682 long nAvailWidth = aAreaParam.maAlignRect.GetWidth(); 1683 long nOutHeight = aAreaParam.maAlignRect.GetHeight(); 1684 1685 sal_Bool bOutside = ( aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW ); 1686 if ( aAreaParam.maClipRect.Left() < nScrX ) 1687 { 1688 aAreaParam.maClipRect.Left() = nScrX; 1689 aAreaParam.mbLeftClip = sal_True; 1690 } 1691 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW ) 1692 { 1693 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one? 1694 aAreaParam.mbRightClip = sal_True; 1695 } 1696 1697 sal_Bool bHClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip; 1698 sal_Bool bVClip = sal_False; 1699 1700 if ( aAreaParam.maClipRect.Top() < nScrY ) 1701 { 1702 aAreaParam.maClipRect.Top() = nScrY; 1703 bVClip = sal_True; 1704 } 1705 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH ) 1706 { 1707 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one? 1708 bVClip = sal_True; 1709 } 1710 1711 // 1712 // horizontalen Platz testen 1713 // 1714 1715 sal_Bool bRightAdjusted = sal_False; // to correct text width calculation later 1716 sal_Bool bNeedEditEngine = sal_False; 1717 if ( !bNeedEditEngine && !bOutside ) 1718 { 1719 switch (eOutHorJust) 1720 { 1721 case SVX_HOR_JUSTIFY_LEFT: 1722 nJustPosX += (long) ( aVars.GetLeftTotal() * nPPTX ); 1723 break; 1724 case SVX_HOR_JUSTIFY_RIGHT: 1725 nJustPosX += nAvailWidth - aVars.GetTextSize().Width() - 1726 (long) ( aVars.GetMargin()->GetRightMargin() * nPPTX ); 1727 bRightAdjusted = sal_True; 1728 break; 1729 case SVX_HOR_JUSTIFY_CENTER: 1730 nJustPosX += ( nAvailWidth - aVars.GetTextSize().Width() + 1731 (long) ( aVars.GetLeftTotal() * nPPTX ) - 1732 (long) ( aVars.GetMargin()->GetRightMargin() * nPPTX ) ) / 2; 1733 break; 1734 default: 1735 { 1736 // added to avoid warnings 1737 } 1738 } 1739 1740 long nTestClipHeight = aVars.GetTextSize().Height(); 1741 switch (aVars.GetVerJust()) 1742 { 1743 case SVX_VER_JUSTIFY_TOP: 1744 { 1745 long nTop = (long)( aVars.GetMargin()->GetTopMargin() * nPPTY ); 1746 nJustPosY += nTop; 1747 nTestClipHeight += nTop; 1748 } 1749 break; 1750 case SVX_VER_JUSTIFY_BOTTOM: 1751 { 1752 long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * nPPTY ); 1753 nJustPosY += nOutHeight - aVars.GetTextSize().Height() - nBot; 1754 nTestClipHeight += nBot; 1755 } 1756 break; 1757 case SVX_VER_JUSTIFY_CENTER: 1758 { 1759 long nTop = (long)( aVars.GetMargin()->GetTopMargin() * nPPTY ); 1760 long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * nPPTY ); 1761 nJustPosY += ( nOutHeight + nTop - 1762 aVars.GetTextSize().Height() - nBot ) / 2; 1763 nTestClipHeight += Abs( nTop - nBot ); 1764 } 1765 break; 1766 default: 1767 { 1768 // added to avoid warnings 1769 } 1770 } 1771 1772 if ( nTestClipHeight > nOutHeight ) 1773 { 1774 // kein vertikales Clipping beim Drucken von Zellen mit 1775 // optimaler Hoehe, ausser bei Groesse in bedingter Formatierung 1776 if ( eType != OUTTYPE_PRINTER || 1777 ( pDoc->GetRowFlags( nCellY, nTab ) & CR_MANUALSIZE ) || 1778 ( aVars.HasCondHeight() ) ) 1779 bVClip = sal_True; 1780 } 1781 1782 if ( bHClip || bVClip ) 1783 { 1784 // nur die betroffene Dimension clippen, 1785 // damit bei nicht-proportionalem Resize nicht alle 1786 // rechtsbuendigen Zahlen abgeschnitten werden: 1787 1788 if (!bHClip) 1789 { 1790 aAreaParam.maClipRect.Left() = nScrX; 1791 aAreaParam.maClipRect.Right() = nScrX+nScrW; 1792 } 1793 if (!bVClip) 1794 { 1795 aAreaParam.maClipRect.Top() = nScrY; 1796 aAreaParam.maClipRect.Bottom() = nScrY+nScrH; 1797 } 1798 1799 // aClipRect is not used after SetClipRegion/IntersectClipRegion, 1800 // so it can be modified here 1801 if (bPixelToLogic) 1802 aAreaParam.maClipRect = pRefDevice->PixelToLogic( aAreaParam.maClipRect ); 1803 1804 if (bMetaFile) 1805 { 1806 pDev->Push(); 1807 pDev->IntersectClipRegion( aAreaParam.maClipRect ); 1808 } 1809 else 1810 pDev->SetClipRegion( Region( aAreaParam.maClipRect ) ); 1811 } 1812 1813 Point aURLStart( nJustPosX, nJustPosY ); // copy before modifying for orientation 1814 1815 switch (aVars.GetOrient()) 1816 { 1817 case SVX_ORIENTATION_STANDARD: 1818 nJustPosY += aVars.GetAscent(); 1819 break; 1820 case SVX_ORIENTATION_TOPBOTTOM: 1821 nJustPosX += aVars.GetTextSize().Width() - aVars.GetAscent(); 1822 break; 1823 case SVX_ORIENTATION_BOTTOMTOP: 1824 nJustPosY += aVars.GetTextSize().Height(); 1825 nJustPosX += aVars.GetAscent(); 1826 break; 1827 default: 1828 { 1829 // added to avoid warnings 1830 } 1831 } 1832 1833 // When clipping, the visible part is now completely defined by the alignment, 1834 // there's no more special handling to show the right part of RTL text. 1835 1836 Point aDrawTextPos( nJustPosX, nJustPosY ); 1837 if ( bPixelToLogic ) 1838 { 1839 // undo text width adjustment in pixels 1840 if (bRightAdjusted) 1841 aDrawTextPos.X() += aVars.GetTextSize().Width(); 1842 1843 aDrawTextPos = pRefDevice->PixelToLogic( aDrawTextPos ); 1844 1845 // redo text width adjustment in logic units 1846 if (bRightAdjusted) 1847 aDrawTextPos.X() -= aVars.GetOriginalWidth(); 1848 } 1849 1850 // in Metafiles immer DrawTextArray, damit die Positionen mit 1851 // aufgezeichnet werden (fuer nicht-proportionales Resize): 1852 1853 String aString = aVars.GetString(); 1854 if (bMetaFile || pFmtDevice != pDev || aZoomX != aZoomY) 1855 { 1856 sal_Int32* pDX = new sal_Int32[aString.Len()]; 1857 pFmtDevice->GetTextArray( aString, pDX ); 1858 1859 if ( !pRefDevice->GetConnectMetaFile() || 1860 pRefDevice->GetOutDevType() == OUTDEV_PRINTER ) 1861 { 1862 double fMul = GetStretch(); 1863 xub_StrLen nLen = aString.Len(); 1864 for (xub_StrLen i=0; i<nLen; i++) 1865 pDX[i] = (long)(pDX[i] / fMul + 0.5); 1866 } 1867 1868 pDev->DrawTextArray( aDrawTextPos, aString, pDX ); 1869 delete[] pDX; 1870 } 1871 else 1872 pDev->DrawText( aDrawTextPos, aString ); 1873 1874 if ( bHClip || bVClip ) 1875 { 1876 if (bMetaFile) 1877 pDev->Pop(); 1878 else 1879 pDev->SetClipRegion(); 1880 } 1881 1882 // PDF: whole-cell hyperlink from formula? 1883 sal_Bool bHasURL = pPDFData && pCell && pCell->GetCellType() == CELLTYPE_FORMULA && 1884 static_cast<ScFormulaCell*>(pCell)->IsHyperLinkCell(); 1885 if ( bHasURL ) 1886 { 1887 Rectangle aURLRect( aURLStart, aVars.GetTextSize() ); 1888 lcl_DoHyperlinkResult( pDev, aURLRect, pCell ); 1889 } 1890 } 1891 } 1892 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign; 1893 } 1894 } 1895 nPosY += pRowInfo[nArrY].nHeight; 1896 } 1897 if ( bProgress ) 1898 ScProgress::DeleteInterpretProgress(); 1899 pDoc->DisableIdle( bWasIdleDisabled ); 1900 } 1901 1902 // ------------------------------------------------------------------------------- 1903 1904 ScFieldEditEngine* ScOutputData::CreateOutputEditEngine() 1905 { 1906 ScFieldEditEngine* pEngine = new ScFieldEditEngine( pDoc->GetEnginePool() ); 1907 pEngine->SetUpdateMode( sal_False ); 1908 // a RefDevice always has to be set, otherwise EditEngine would create a VirtualDevice 1909 pEngine->SetRefDevice( pFmtDevice ); 1910 sal_uInt32 nCtrl = pEngine->GetControlWord(); 1911 if ( bShowSpellErrors ) 1912 nCtrl |= EE_CNTRL_ONLINESPELLING; 1913 if ( eType == OUTTYPE_PRINTER ) 1914 nCtrl &= ~EE_CNTRL_MARKFIELDS; 1915 if ( eType == OUTTYPE_WINDOW && pRefDevice == pFmtDevice ) 1916 nCtrl &= ~EE_CNTRL_FORMAT100; // use the actual MapMode 1917 pEngine->SetControlWord( nCtrl ); 1918 pDoc->ApplyAsianEditSettings( *pEngine ); 1919 pEngine->EnableAutoColor( bUseStyleColor ); 1920 pEngine->SetDefaultHorizontalTextDirection( (EEHorizontalTextDirection)pDoc->GetEditTextDirection( nTab ) ); 1921 return pEngine; 1922 } 1923 1924 void lcl_ClearEdit( EditEngine& rEngine ) // Text und Attribute 1925 { 1926 rEngine.SetUpdateMode( sal_False ); 1927 1928 rEngine.SetText(EMPTY_STRING); 1929 // keine Para-Attribute uebrigbehalten... 1930 const SfxItemSet& rPara = rEngine.GetParaAttribs(0); 1931 if (rPara.Count()) 1932 rEngine.SetParaAttribs( 0, 1933 SfxItemSet( *rPara.GetPool(), rPara.GetRanges() ) ); 1934 } 1935 1936 sal_Bool lcl_SafeIsValue( ScBaseCell* pCell ) 1937 { 1938 if (!pCell) 1939 return sal_False; 1940 1941 sal_Bool bRet = sal_False; 1942 switch ( pCell->GetCellType() ) 1943 { 1944 case CELLTYPE_VALUE: 1945 bRet = sal_True; 1946 break; 1947 case CELLTYPE_FORMULA: 1948 { 1949 ScFormulaCell* pFCell = (ScFormulaCell*)pCell; 1950 if ( pFCell->IsRunning() || pFCell->IsValue() ) 1951 bRet = sal_True; 1952 } 1953 break; 1954 default: 1955 { 1956 // added to avoid warnings 1957 } 1958 } 1959 return bRet; 1960 } 1961 1962 void lcl_ScaleFonts( EditEngine& rEngine, long nPercent ) 1963 { 1964 sal_Bool bUpdateMode = rEngine.GetUpdateMode(); 1965 if ( bUpdateMode ) 1966 rEngine.SetUpdateMode( sal_False ); 1967 1968 sal_uInt16 nParCount = rEngine.GetParagraphCount(); 1969 for (sal_uInt16 nPar=0; nPar<nParCount; nPar++) 1970 { 1971 SvUShorts aPortions; 1972 rEngine.GetPortions( nPar, aPortions ); 1973 1974 sal_uInt16 nPCount = aPortions.Count(); 1975 sal_uInt16 nStart = 0; 1976 for ( sal_uInt16 nPos=0; nPos<nPCount; nPos++ ) 1977 { 1978 sal_uInt16 nEnd = aPortions.GetObject( nPos ); 1979 ESelection aSel( nPar, nStart, nPar, nEnd ); 1980 SfxItemSet aAttribs = rEngine.GetAttribs( aSel ); 1981 1982 long nWestern = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT)).GetHeight(); 1983 long nCJK = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CJK)).GetHeight(); 1984 long nCTL = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CTL)).GetHeight(); 1985 1986 nWestern = ( nWestern * nPercent ) / 100; 1987 nCJK = ( nCJK * nPercent ) / 100; 1988 nCTL = ( nCTL * nPercent ) / 100; 1989 1990 aAttribs.Put( SvxFontHeightItem( nWestern, 100, EE_CHAR_FONTHEIGHT ) ); 1991 aAttribs.Put( SvxFontHeightItem( nCJK, 100, EE_CHAR_FONTHEIGHT_CJK ) ); 1992 aAttribs.Put( SvxFontHeightItem( nCTL, 100, EE_CHAR_FONTHEIGHT_CTL ) ); 1993 1994 rEngine.QuickSetAttribs( aAttribs, aSel ); //! remove paragraph attributes from aAttribs? 1995 1996 nStart = nEnd; 1997 } 1998 } 1999 2000 if ( bUpdateMode ) 2001 rEngine.SetUpdateMode( sal_True ); 2002 } 2003 2004 long lcl_GetEditSize( EditEngine& rEngine, sal_Bool bWidth, sal_Bool bSwap, long nAttrRotate ) 2005 { 2006 if ( bSwap ) 2007 bWidth = !bWidth; 2008 2009 if ( nAttrRotate ) 2010 { 2011 long nRealWidth = (long) rEngine.CalcTextWidth(); 2012 long nRealHeight = rEngine.GetTextHeight(); 2013 2014 // assuming standard mode, otherwise width isn't used 2015 2016 double nRealOrient = nAttrRotate * F_PI18000; // 1/100th degrees 2017 double nAbsCos = fabs( cos( nRealOrient ) ); 2018 double nAbsSin = fabs( sin( nRealOrient ) ); 2019 if ( bWidth ) 2020 return (long) ( nRealWidth * nAbsCos + nRealHeight * nAbsSin ); 2021 else 2022 return (long) ( nRealHeight * nAbsCos + nRealWidth * nAbsSin ); 2023 } 2024 else if ( bWidth ) 2025 return (long) rEngine.CalcTextWidth(); 2026 else 2027 return rEngine.GetTextHeight(); 2028 } 2029 2030 2031 void ScOutputData::ShrinkEditEngine( EditEngine& rEngine, const Rectangle& rAlignRect, 2032 long nLeftM, long nTopM, long nRightM, long nBottomM, 2033 sal_Bool bWidth, sal_uInt16 nOrient, long nAttrRotate, sal_Bool bPixelToLogic, 2034 long& rEngineWidth, long& rEngineHeight, long& rNeededPixel, bool& rLeftClip, bool& rRightClip ) 2035 { 2036 if ( !bWidth ) 2037 { 2038 // vertical 2039 2040 long nScaleSize = bPixelToLogic ? 2041 pRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight; 2042 2043 // Don't scale if it fits already. 2044 // Allowing to extend into the margin, to avoid scaling at optimal height. 2045 if ( nScaleSize <= rAlignRect.GetHeight() ) 2046 return; 2047 2048 sal_Bool bSwap = ( nOrient == SVX_ORIENTATION_TOPBOTTOM || nOrient == SVX_ORIENTATION_BOTTOMTOP ); 2049 long nAvailable = rAlignRect.GetHeight() - nTopM - nBottomM; 2050 long nScale = ( nAvailable * 100 ) / nScaleSize; 2051 2052 lcl_ScaleFonts( rEngine, nScale ); 2053 rEngineHeight = lcl_GetEditSize( rEngine, sal_False, bSwap, nAttrRotate ); 2054 long nNewSize = bPixelToLogic ? 2055 pRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight; 2056 2057 sal_uInt16 nShrinkAgain = 0; 2058 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX ) 2059 { 2060 // further reduce, like in DrawStrings 2061 lcl_ScaleFonts( rEngine, 90 ); // reduce by 10% 2062 rEngineHeight = lcl_GetEditSize( rEngine, sal_False, bSwap, nAttrRotate ); 2063 nNewSize = bPixelToLogic ? 2064 pRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight; 2065 ++nShrinkAgain; 2066 } 2067 2068 // sizes for further processing (alignment etc): 2069 rEngineWidth = lcl_GetEditSize( rEngine, sal_True, bSwap, nAttrRotate ); 2070 long nPixelWidth = bPixelToLogic ? 2071 pRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth; 2072 rNeededPixel = nPixelWidth + nLeftM + nRightM; 2073 } 2074 else if ( rLeftClip || rRightClip ) 2075 { 2076 // horizontal 2077 2078 long nAvailable = rAlignRect.GetWidth() - nLeftM - nRightM; 2079 long nScaleSize = rNeededPixel - nLeftM - nRightM; // without margin 2080 2081 if ( nScaleSize <= nAvailable ) 2082 return; 2083 2084 long nScale = ( nAvailable * 100 ) / nScaleSize; 2085 2086 lcl_ScaleFonts( rEngine, nScale ); 2087 rEngineWidth = lcl_GetEditSize( rEngine, sal_True, sal_False, nAttrRotate ); 2088 long nNewSize = bPixelToLogic ? 2089 pRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth; 2090 2091 sal_uInt16 nShrinkAgain = 0; 2092 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX ) 2093 { 2094 // further reduce, like in DrawStrings 2095 lcl_ScaleFonts( rEngine, 90 ); // reduce by 10% 2096 rEngineWidth = lcl_GetEditSize( rEngine, sal_True, sal_False, nAttrRotate ); 2097 nNewSize = bPixelToLogic ? 2098 pRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth; 2099 ++nShrinkAgain; 2100 } 2101 if ( nNewSize <= nAvailable ) 2102 rLeftClip = rRightClip = sal_False; 2103 2104 // sizes for further processing (alignment etc): 2105 rNeededPixel = nNewSize + nLeftM + nRightM; 2106 rEngineHeight = lcl_GetEditSize( rEngine, sal_False, sal_False, nAttrRotate ); 2107 } 2108 } 2109 2110 void ScOutputData::DrawEdit(sal_Bool bPixelToLogic) 2111 { 2112 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() ); 2113 2114 Size aMinSize = pRefDevice->PixelToLogic(Size(0,100)); // erst darueber wird ausgegeben 2115 // sal_uInt32 nMinHeight = aMinSize.Height() / 200; // 1/2 Pixel 2116 2117 ScModule* pScMod = SC_MOD(); 2118 sal_Int32 nConfBackColor = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; 2119 // #105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True) 2120 sal_Bool bCellContrast = bUseStyleColor && 2121 Application::GetSettings().GetStyleSettings().GetHighContrastMode(); 2122 2123 ScFieldEditEngine* pEngine = NULL; 2124 sal_Bool bHyphenatorSet = sal_False; 2125 const ScPatternAttr* pOldPattern = NULL; 2126 const SfxItemSet* pOldCondSet = NULL; 2127 ScBaseCell* pCell = NULL; 2128 2129 Size aRefOne = pRefDevice->PixelToLogic(Size(1,1)); 2130 2131 long nInitPosX = nScrX; 2132 if ( bLayoutRTL ) 2133 { 2134 #if 0 2135 Size aOnePixel = pDev->PixelToLogic(Size(1,1)); 2136 long nOneX = aOnePixel.Width(); 2137 nInitPosX += nMirrorW - nOneX; 2138 #endif 2139 nInitPosX += nMirrorW - 1; 2140 } 2141 long nLayoutSign = bLayoutRTL ? -1 : 1; 2142 2143 //! store nLastContentCol as member! 2144 SCCOL nLastContentCol = MAXCOL; 2145 if ( nX2 < MAXCOL ) 2146 nLastContentCol = sal::static_int_cast<SCCOL>( 2147 nLastContentCol - pDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) ); 2148 2149 long nRowPosY = nScrY; 2150 for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 fuer Reste von zusammengefassten 2151 { 2152 RowInfo* pThisRowInfo = &pRowInfo[nArrY]; 2153 // long nCellHeight = (long) pThisRowInfo->nHeight; 2154 if (nArrY==1) nRowPosY = nScrY; // vorher wird einzeln berechnet 2155 2156 if ( pThisRowInfo->bChanged || nArrY==0 ) 2157 { 2158 long nPosX = 0; 2159 for (SCCOL nX=0; nX<=nX2; nX++) // wegen Ueberhaengen 2160 { 2161 if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually 2162 2163 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1]; 2164 if (pInfo->bEditEngine) 2165 { 2166 SCROW nY = pThisRowInfo->nRowNo; 2167 2168 SCCOL nCellX = nX; // position where the cell really starts 2169 SCROW nCellY = nY; 2170 sal_Bool bDoCell = sal_False; 2171 2172 long nPosY = nRowPosY; 2173 if ( nArrY == 0 ) 2174 { 2175 nPosY = nScrY; 2176 nY = pRowInfo[1].nRowNo; 2177 SCCOL nOverX; // start of the merged cells 2178 SCROW nOverY; 2179 if (GetMergeOrigin( nX,nY, 1, nOverX,nOverY, sal_True )) 2180 { 2181 nCellX = nOverX; 2182 nCellY = nOverY; 2183 bDoCell = sal_True; 2184 } 2185 } 2186 else if ( nX == nX2 && !pThisRowInfo->pCellInfo[nX+1].pCell ) 2187 { 2188 // Rest of a long text further to the right? 2189 2190 SCCOL nTempX=nX; 2191 while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY )) 2192 ++nTempX; 2193 2194 if ( nTempX > nX && 2195 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) && 2196 !pDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) ) 2197 { 2198 nCellX = nTempX; 2199 bDoCell = sal_True; 2200 } 2201 } 2202 else 2203 { 2204 bDoCell = sal_True; 2205 } 2206 2207 if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow ) 2208 bDoCell = sal_False; 2209 2210 const ScPatternAttr* pPattern = NULL; 2211 const SfxItemSet* pCondSet = NULL; 2212 if (bDoCell) 2213 { 2214 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 && 2215 !pDoc->ColHidden(nCellX, nTab) ) 2216 { 2217 CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1]; 2218 pPattern = rCellInfo.pPatternAttr; 2219 pCondSet = rCellInfo.pConditionSet; 2220 pCell = rCellInfo.pCell; 2221 } 2222 else // get from document 2223 { 2224 pPattern = pDoc->GetPattern( nCellX, nCellY, nTab ); 2225 pCondSet = pDoc->GetCondResult( nCellX, nCellY, nTab ); 2226 GetVisibleCell( nCellX, nCellY, nTab, pCell ); 2227 } 2228 if ( !pCell ) 2229 bDoCell = sal_False; 2230 } 2231 if (bDoCell) 2232 { 2233 sal_Bool bHidden = sal_False; 2234 2235 // 2236 // Create EditEngine 2237 // 2238 2239 if (!pEngine) 2240 pEngine = CreateOutputEditEngine(); 2241 else 2242 lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False) 2243 2244 sal_Bool bCellIsValue = lcl_SafeIsValue(pCell); 2245 2246 SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&) 2247 pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet)).GetValue(); 2248 sal_Bool bBreak = ( eHorJust == SVX_HOR_JUSTIFY_BLOCK ) || 2249 ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue(); 2250 sal_Bool bRepeat = ( eHorJust == SVX_HOR_JUSTIFY_REPEAT && !bBreak ); 2251 sal_Bool bShrink = !bBreak && !bRepeat && static_cast<const SfxBoolItem&> 2252 (pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue(); 2253 SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet ); 2254 long nAttrRotate = ((const SfxInt32Item&)pPattern-> 2255 GetItem(ATTR_ROTATE_VALUE, pCondSet)).GetValue(); 2256 if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT ) 2257 { 2258 // ignore orientation/rotation if "repeat" is active 2259 eOrient = SVX_ORIENTATION_STANDARD; 2260 nAttrRotate = 0; 2261 2262 // #i31843# "repeat" with "line breaks" is treated as default alignment 2263 // (but rotation is still disabled) 2264 if ( bBreak ) 2265 eHorJust = SVX_HOR_JUSTIFY_STANDARD; 2266 } 2267 if ( eOrient==SVX_ORIENTATION_STANDARD && nAttrRotate ) 2268 { 2269 //! Flag setzen, um die Zelle in DrawRotated wiederzufinden ? 2270 //! (oder Flag schon bei DrawBackground, dann hier keine Abfrage) 2271 bHidden = sal_True; // gedreht wird getrennt ausgegeben 2272 } 2273 2274 sal_Bool bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED && 2275 ((const SfxBoolItem&)pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() ); 2276 if ( bAsianVertical ) 2277 { 2278 // in asian mode, use EditEngine::SetVertical instead of EE_CNTRL_ONECHARPERLINE 2279 eOrient = SVX_ORIENTATION_STANDARD; 2280 // default alignment for asian vertical mode is top-right 2281 if ( eHorJust == SVX_HOR_JUSTIFY_STANDARD ) 2282 eHorJust = SVX_HOR_JUSTIFY_RIGHT; 2283 } 2284 2285 SvxCellHorJustify eOutHorJust = 2286 ( eHorJust != SVX_HOR_JUSTIFY_STANDARD ) ? eHorJust : 2287 ( bCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT ); 2288 2289 if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT ) 2290 eOutHorJust = SVX_HOR_JUSTIFY_LEFT; // repeat is not yet implemented 2291 2292 2293 //! if ( !bHidden && eType == OUTTYPE_PRINTER && 2294 //! pDev->GetOutDevType() == OUTDEV_WINDOW && 2295 //! ((const SvxFontHeightItem&)pPattern-> 2296 //! GetItem(ATTR_FONT_HEIGHT)).GetHeight() <= nMinHeight ) 2297 //! { 2298 //! Point aPos( nStartX, nStartY ); 2299 //! pDev->DrawPixel( aPos, 2300 //! ((const SvxColorItem&)pPattern-> 2301 //! GetItem( ATTR_FONT_COLOR )).GetValue() ); 2302 //! bHidden = sal_True; 2303 //! } 2304 2305 if (!bHidden) 2306 { 2307 //! mirror margin values for RTL? 2308 //! move margin down to after final GetOutputArea call 2309 2310 const SvxMarginItem* pMargin = (const SvxMarginItem*) 2311 &pPattern->GetItem(ATTR_MARGIN, pCondSet); 2312 sal_uInt16 nIndent = 0; 2313 if ( eHorJust == SVX_HOR_JUSTIFY_LEFT ) 2314 nIndent = ((const SfxUInt16Item&)pPattern-> 2315 GetItem(ATTR_INDENT, pCondSet)).GetValue(); 2316 2317 long nLeftM = (long) ( (pMargin->GetLeftMargin() + nIndent) * nPPTX ); 2318 long nTopM = (long) ( pMargin->GetTopMargin() * nPPTY ); 2319 long nRightM = (long) ( pMargin->GetRightMargin() * nPPTX ); 2320 long nBottomM = (long) ( pMargin->GetBottomMargin() * nPPTY ); 2321 2322 SCCOL nXForPos = nX; 2323 if ( nXForPos < nX1 ) 2324 { 2325 nXForPos = nX1; 2326 nPosX = nInitPosX; 2327 } 2328 SCSIZE nArrYForPos = nArrY; 2329 if ( nArrYForPos < 1 ) 2330 { 2331 nArrYForPos = 1; 2332 nPosY = nScrY; 2333 } 2334 2335 OutputAreaParam aAreaParam; 2336 2337 // 2338 // Initial page size - large for normal text, cell size for automatic line breaks 2339 // 2340 2341 Size aPaperSize = Size( 1000000, 1000000 ); 2342 if ( bBreak || eOrient == SVX_ORIENTATION_STACKED || bAsianVertical ) 2343 { 2344 //! also stacked, AsianVertical 2345 2346 // call GetOutputArea with nNeeded=0, to get only the cell width 2347 2348 //! handle nArrY == 0 2349 GetOutputArea( nXForPos, nArrYForPos, nPosX, nPosY, nCellX, nCellY, 0, 2350 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust), 2351 bCellIsValue, true, false, aAreaParam ); 2352 2353 //! special ScEditUtil handling if formatting for printer 2354 2355 if ( eOrient == SVX_ORIENTATION_TOPBOTTOM || eOrient == SVX_ORIENTATION_BOTTOMTOP ) 2356 aPaperSize.Width() = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM; 2357 else 2358 aPaperSize.Width() = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM; 2359 2360 if (bAsianVertical && bBreak) 2361 { 2362 // add some extra height (default margin value) for safety 2363 // as long as GetEditArea isn't used below 2364 long nExtraHeight = (long)( 20 * nPPTY ); 2365 aPaperSize.Height() = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM + nExtraHeight; 2366 } 2367 } 2368 if (bPixelToLogic) 2369 { 2370 Size aLogicSize = pRefDevice->PixelToLogic(aPaperSize); 2371 if ( bBreak && !bAsianVertical && pRefDevice != pFmtDevice ) 2372 { 2373 // #i85342# screen display and formatting for printer, 2374 // use same GetEditArea call as in ScViewData::SetEditEngine 2375 2376 Fraction aFract(1,1); 2377 Rectangle aUtilRect = ScEditUtil( pDoc, nCellX, nCellY, nTab, Point(0,0), pFmtDevice, 2378 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( pPattern, sal_False ); 2379 aLogicSize.Width() = aUtilRect.GetWidth(); 2380 } 2381 pEngine->SetPaperSize(aLogicSize); 2382 } 2383 else 2384 pEngine->SetPaperSize(aPaperSize); 2385 2386 // 2387 // Fill the EditEngine (cell attributes and text) 2388 // 2389 2390 SvxCellVerJustify eVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&) 2391 pPattern->GetItem(ATTR_VER_JUSTIFY, pCondSet)).GetValue(); 2392 2393 // default alignment for asian vertical mode is top-right 2394 if ( bAsianVertical && eVerJust == SVX_VER_JUSTIFY_STANDARD ) 2395 eVerJust = SVX_VER_JUSTIFY_TOP; 2396 2397 // syntax highlighting mode is ignored here 2398 // StringDiffer doesn't look at hyphenate, language items 2399 if ( pPattern != pOldPattern || pCondSet != pOldCondSet ) 2400 { 2401 SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() ); 2402 pPattern->FillEditItemSet( pSet, pCondSet ); 2403 2404 pEngine->SetDefaults( pSet ); 2405 pOldPattern = pPattern; 2406 pOldCondSet = pCondSet; 2407 2408 sal_uLong nControl = pEngine->GetControlWord(); 2409 if (eOrient==SVX_ORIENTATION_STACKED) 2410 nControl |= EE_CNTRL_ONECHARPERLINE; 2411 else 2412 nControl &= ~EE_CNTRL_ONECHARPERLINE; 2413 pEngine->SetControlWord( nControl ); 2414 2415 if ( !bHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) 2416 { 2417 // set hyphenator the first time it is needed 2418 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() ); 2419 pEngine->SetHyphenator( xXHyphenator ); 2420 bHyphenatorSet = sal_True; 2421 } 2422 2423 Color aBackCol = ((const SvxBrushItem&) 2424 pPattern->GetItem( ATTR_BACKGROUND, pCondSet )).GetColor(); 2425 if ( bUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) ) 2426 aBackCol.SetColor( nConfBackColor ); 2427 pEngine->SetBackgroundColor( aBackCol ); 2428 } 2429 2430 // horizontal alignment now may depend on cell content 2431 // (for values with number formats with mixed script types) 2432 // -> always set adjustment 2433 2434 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT; 2435 if (eOrient==SVX_ORIENTATION_STACKED) 2436 eSvxAdjust = SVX_ADJUST_CENTER; 2437 else if (bBreak) 2438 { 2439 if (eOrient==SVX_ORIENTATION_STANDARD && !bAsianVertical) 2440 switch (eHorJust) 2441 { 2442 case SVX_HOR_JUSTIFY_STANDARD: 2443 eSvxAdjust = bCellIsValue ? SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT; 2444 break; 2445 case SVX_HOR_JUSTIFY_LEFT: 2446 case SVX_HOR_JUSTIFY_REPEAT: // nicht implementiert 2447 eSvxAdjust = SVX_ADJUST_LEFT; 2448 break; 2449 case SVX_HOR_JUSTIFY_RIGHT: 2450 eSvxAdjust = SVX_ADJUST_RIGHT; 2451 break; 2452 case SVX_HOR_JUSTIFY_CENTER: 2453 eSvxAdjust = SVX_ADJUST_CENTER; 2454 break; 2455 case SVX_HOR_JUSTIFY_BLOCK: 2456 eSvxAdjust = SVX_ADJUST_BLOCK; 2457 break; 2458 } 2459 else 2460 switch (eVerJust) 2461 { 2462 case SVX_VER_JUSTIFY_TOP: 2463 eSvxAdjust = (eOrient==SVX_ORIENTATION_TOPBOTTOM || bAsianVertical) ? 2464 SVX_ADJUST_LEFT : SVX_ADJUST_RIGHT; 2465 break; 2466 case SVX_VER_JUSTIFY_CENTER: 2467 eSvxAdjust = SVX_ADJUST_CENTER; 2468 break; 2469 case SVX_VER_JUSTIFY_BOTTOM: 2470 case SVX_HOR_JUSTIFY_STANDARD: 2471 eSvxAdjust = (eOrient==SVX_ORIENTATION_TOPBOTTOM || bAsianVertical) ? 2472 SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT; 2473 break; 2474 } 2475 } 2476 pEngine->SetDefaultItem( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) ); 2477 2478 // Read content from cell 2479 2480 sal_Bool bWrapFields = sal_False; 2481 if (pCell) 2482 { 2483 if (pCell->GetCellType() == CELLTYPE_EDIT) 2484 { 2485 const EditTextObject* pData; 2486 ((ScEditCell*)pCell)->GetData(pData); 2487 2488 if (pData) 2489 { 2490 pEngine->SetText(*pData); 2491 2492 if ( bBreak && !bAsianVertical && pData->HasField() ) 2493 { 2494 // Fields aren't wrapped, so clipping is enabled to prevent 2495 // a field from being drawn beyond the cell size 2496 2497 bWrapFields = sal_True; 2498 } 2499 } 2500 else 2501 { 2502 DBG_ERROR("pData == 0"); 2503 } 2504 } 2505 else 2506 { 2507 sal_uLong nFormat = pPattern->GetNumberFormat( 2508 pDoc->GetFormatTable(), pCondSet ); 2509 String aString; 2510 Color* pColor; 2511 ScCellFormat::GetString( pCell, 2512 nFormat,aString, &pColor, 2513 *pDoc->GetFormatTable(), 2514 bShowNullValues, 2515 bShowFormulas, 2516 ftCheck ); 2517 2518 pEngine->SetText(aString); 2519 if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) ) 2520 lcl_SetEditColor( *pEngine, *pColor ); 2521 } 2522 2523 if ( bSyntaxMode ) 2524 SetEditSyntaxColor( *pEngine, pCell ); 2525 else if ( bUseStyleColor && bForceAutoColor ) 2526 lcl_SetEditColor( *pEngine, COL_AUTO ); //! or have a flag at EditEngine 2527 } 2528 else 2529 { 2530 DBG_ERROR("pCell == NULL"); 2531 } 2532 2533 pEngine->SetVertical( bAsianVertical ); 2534 pEngine->SetUpdateMode( sal_True ); // after SetText, before CalcTextWidth/GetTextHeight 2535 2536 // 2537 // Get final output area using the calculated width 2538 // 2539 2540 long nEngineWidth; 2541 if ( bBreak && eOrient != SVX_ORIENTATION_STACKED && !bAsianVertical ) 2542 nEngineWidth = 0; 2543 else 2544 nEngineWidth = (long) pEngine->CalcTextWidth(); 2545 long nEngineHeight = pEngine->GetTextHeight(); 2546 2547 if (eOrient != SVX_ORIENTATION_STANDARD && 2548 eOrient != SVX_ORIENTATION_STACKED) 2549 { 2550 long nTemp = nEngineWidth; 2551 nEngineWidth = nEngineHeight; 2552 nEngineHeight = nTemp; 2553 } 2554 2555 if (eOrient == SVX_ORIENTATION_STACKED) 2556 nEngineWidth = nEngineWidth * 11 / 10; 2557 2558 long nNeededPixel = nEngineWidth; 2559 if (bPixelToLogic) 2560 nNeededPixel = pRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width(); 2561 nNeededPixel += nLeftM + nRightM; 2562 2563 if ( ( !bBreak && eOrient != SVX_ORIENTATION_STACKED ) || bAsianVertical || bShrink ) 2564 { 2565 // for break, the first GetOutputArea call is sufficient 2566 GetOutputArea( nXForPos, nArrYForPos, nPosX, nPosY, nCellX, nCellY, nNeededPixel, 2567 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust), 2568 bCellIsValue || bRepeat || bShrink, false, false, aAreaParam ); 2569 2570 if ( bShrink ) 2571 { 2572 sal_Bool bWidth = ( eOrient == SVX_ORIENTATION_STANDARD && !bAsianVertical ); 2573 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, 2574 nLeftM, nTopM, nRightM, nBottomM, bWidth, 2575 sal::static_int_cast<sal_uInt16>(eOrient), 0, bPixelToLogic, 2576 nEngineWidth, nEngineHeight, nNeededPixel, 2577 aAreaParam.mbLeftClip, aAreaParam.mbRightClip ); 2578 } 2579 2580 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && pEngine->GetParagraphCount() == 1 ) 2581 { 2582 // First check if twice the space for the formatted text is available 2583 // (otherwise just keep it unchanged). 2584 2585 long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin 2586 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM; 2587 if ( nAvailable >= 2 * nFormatted ) 2588 { 2589 // "repeat" is handled with unformatted text (for performance reasons) 2590 String aCellStr = pEngine->GetText(); 2591 pEngine->SetText( aCellStr ); 2592 2593 long nRepeatSize = (long) pEngine->CalcTextWidth(); 2594 if (bPixelToLogic) 2595 nRepeatSize = pRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width(); 2596 if ( pFmtDevice != pRefDevice ) 2597 ++nRepeatSize; 2598 if ( nRepeatSize > 0 ) 2599 { 2600 long nRepeatCount = nAvailable / nRepeatSize; 2601 if ( nRepeatCount > 1 ) 2602 { 2603 String aRepeated = aCellStr; 2604 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ ) 2605 aRepeated.Append( aCellStr ); 2606 pEngine->SetText( aRepeated ); 2607 2608 nEngineHeight = pEngine->GetTextHeight(); 2609 nEngineWidth = (long) pEngine->CalcTextWidth(); 2610 if (bPixelToLogic) 2611 nNeededPixel = pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width(); 2612 else 2613 nNeededPixel = nEngineWidth; 2614 nNeededPixel += nLeftM + nRightM; 2615 } 2616 } 2617 } 2618 } 2619 2620 if ( bCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) ) 2621 { 2622 pEngine->SetText( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("###")) ); 2623 nEngineWidth = (long) pEngine->CalcTextWidth(); 2624 if (bPixelToLogic) 2625 nNeededPixel = pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width(); 2626 else 2627 nNeededPixel = nEngineWidth; 2628 nNeededPixel += nLeftM + nRightM; 2629 2630 // No clip marks if "###" doesn't fit (same as in DrawStrings) 2631 } 2632 2633 if ( eOutHorJust != SVX_HOR_JUSTIFY_LEFT && eOrient == SVX_ORIENTATION_STANDARD ) 2634 { 2635 aPaperSize.Width() = nNeededPixel + 1; 2636 if (bPixelToLogic) 2637 pEngine->SetPaperSize(pRefDevice->PixelToLogic(aPaperSize)); 2638 else 2639 pEngine->SetPaperSize(aPaperSize); 2640 } 2641 } 2642 2643 long nStartX = aAreaParam.maAlignRect.Left(); 2644 long nStartY = aAreaParam.maAlignRect.Top(); 2645 long nCellWidth = aAreaParam.maAlignRect.GetWidth(); 2646 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM; 2647 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM; 2648 2649 if ( bBreak || eOrient != SVX_ORIENTATION_STANDARD || bAsianVertical ) 2650 { 2651 // text with automatic breaks is aligned only within the 2652 // edit engine's paper size, the output of the whole area 2653 // is always left-aligned 2654 2655 nStartX += nLeftM; 2656 } 2657 else 2658 { 2659 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT ) 2660 nStartX -= nNeededPixel - nCellWidth + nRightM + 1; 2661 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER ) 2662 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2; 2663 else 2664 nStartX += nLeftM; 2665 } 2666 2667 sal_Bool bOutside = ( aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW ); 2668 if ( aAreaParam.maClipRect.Left() < nScrX ) 2669 { 2670 aAreaParam.maClipRect.Left() = nScrX; 2671 aAreaParam.mbLeftClip = true; 2672 } 2673 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW ) 2674 { 2675 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one? 2676 aAreaParam.mbRightClip = true; 2677 } 2678 2679 if ( !bHidden && !bOutside ) 2680 { 2681 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip; 2682 sal_Bool bSimClip = sal_False; 2683 2684 if ( bWrapFields ) 2685 { 2686 // Fields in a cell with automatic breaks: clip to cell width 2687 bClip = sal_True; 2688 } 2689 2690 if ( aAreaParam.maClipRect.Top() < nScrY ) 2691 { 2692 aAreaParam.maClipRect.Top() = nScrY; 2693 bClip = sal_True; 2694 } 2695 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH ) 2696 { 2697 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one? 2698 bClip = sal_True; 2699 } 2700 2701 Size aCellSize; // output area, excluding margins, in logical units 2702 if (bPixelToLogic) 2703 aCellSize = pRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) ); 2704 else 2705 aCellSize = Size( nOutWidth, nOutHeight ); 2706 2707 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() ) 2708 { 2709 const ScMergeAttr* pMerge = 2710 (ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE); 2711 sal_Bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1; 2712 2713 // Don't clip for text height when printing rows with optimal height, 2714 // except when font size is from conditional formatting. 2715 //! Allow clipping when vertically merged? 2716 if ( eType != OUTTYPE_PRINTER || 2717 ( pDoc->GetRowFlags( nCellY, nTab ) & CR_MANUALSIZE ) || 2718 ( pCondSet && SFX_ITEM_SET == 2719 pCondSet->GetItemState(ATTR_FONT_HEIGHT, sal_True) ) ) 2720 bClip = sal_True; 2721 else 2722 bSimClip = sal_True; 2723 2724 // Show clip marks if height is at least 5pt too small and 2725 // there are several lines of text. 2726 // Not for asian vertical text, because that would interfere 2727 // with the default right position of the text. 2728 // Only with automatic line breaks, to avoid having to find 2729 // the cells with the horizontal end of the text again. 2730 if ( nEngineHeight - aCellSize.Height() > 100 && 2731 ( bBreak || eOrient == SVX_ORIENTATION_STACKED ) && 2732 !bAsianVertical && bMarkClipped && 2733 ( pEngine->GetParagraphCount() > 1 || pEngine->GetLineCount(0) > 1 ) ) 2734 { 2735 CellInfo* pClipMarkCell = NULL; 2736 if ( bMerged ) 2737 { 2738 // anywhere in the merged area... 2739 SCCOL nClipX = ( nX < nX1 ) ? nX1 : nX; 2740 pClipMarkCell = &pRowInfo[(nArrY != 0) ? nArrY : 1].pCellInfo[nClipX+1]; 2741 } 2742 else 2743 pClipMarkCell = &pThisRowInfo->pCellInfo[nX+1]; 2744 2745 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left? 2746 bAnyClipped = sal_True; 2747 2748 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX ); 2749 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() ) 2750 aAreaParam.maClipRect.Right() -= nMarkPixel; 2751 } 2752 } 2753 2754 #if 0 2755 long nClipStartY = nStartY; 2756 if (nArrY==0 || bVisChanged) 2757 { 2758 if ( nClipStartY < nRowPosY ) 2759 { 2760 long nDif = nRowPosY - nClipStartY; 2761 bClip = sal_True; 2762 nClipStartY = nRowPosY; 2763 aClipSize.Height() -= nDif; 2764 } 2765 } 2766 #endif 2767 2768 Rectangle aLogicClip; 2769 if (bClip || bSimClip) 2770 { 2771 // Clip marks are already handled in GetOutputArea 2772 2773 if (bPixelToLogic) 2774 aLogicClip = pRefDevice->PixelToLogic( aAreaParam.maClipRect ); 2775 else 2776 aLogicClip = aAreaParam.maClipRect; 2777 2778 if (bClip) // bei bSimClip nur aClipRect initialisieren 2779 { 2780 if (bMetaFile) 2781 { 2782 pDev->Push(); 2783 pDev->IntersectClipRegion( aLogicClip ); 2784 } 2785 else 2786 pDev->SetClipRegion( Region( aLogicClip ) ); 2787 } 2788 } 2789 2790 Point aLogicStart; 2791 if (bPixelToLogic) 2792 aLogicStart = pRefDevice->PixelToLogic( Point(nStartX,nStartY) ); 2793 else 2794 aLogicStart = Point(nStartX, nStartY); 2795 if ( eOrient!=SVX_ORIENTATION_STANDARD || bAsianVertical || !bBreak ) 2796 { 2797 long nAvailWidth = aCellSize.Width(); 2798 // space for AutoFilter is already handled in GetOutputArea 2799 2800 // horizontal alignment 2801 2802 if (eOrient==SVX_ORIENTATION_STANDARD && !bAsianVertical) 2803 { 2804 if (eHorJust==SVX_HOR_JUSTIFY_RIGHT || 2805 eHorJust==SVX_HOR_JUSTIFY_CENTER || 2806 (eHorJust==SVX_HOR_JUSTIFY_STANDARD && bCellIsValue) ) 2807 { 2808 pEngine->SetUpdateMode( sal_False ); 2809 2810 SvxAdjust eEditAdjust = 2811 (eHorJust==SVX_HOR_JUSTIFY_CENTER) ? 2812 SVX_ADJUST_CENTER : SVX_ADJUST_RIGHT; 2813 pEngine->SetDefaultItem( 2814 SvxAdjustItem( eEditAdjust, EE_PARA_JUST ) ); 2815 2816 // #55142# reset adjustment for the next cell 2817 pOldPattern = NULL; 2818 2819 pEngine->SetUpdateMode( sal_True ); 2820 } 2821 } 2822 else 2823 { 2824 if (eHorJust==SVX_HOR_JUSTIFY_RIGHT) 2825 aLogicStart.X() += nAvailWidth - nEngineWidth; 2826 else if (eHorJust==SVX_HOR_JUSTIFY_CENTER) 2827 aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2; 2828 } 2829 } 2830 2831 if ( bAsianVertical ) 2832 { 2833 // paper size is subtracted below 2834 aLogicStart.X() += nEngineWidth; 2835 } 2836 2837 if ( ( bAsianVertical || eOrient == SVX_ORIENTATION_TOPBOTTOM || 2838 eOrient == SVX_ORIENTATION_BOTTOMTOP ) && bBreak ) 2839 { 2840 // vertical adjustment is within the EditEngine 2841 if (bPixelToLogic) 2842 aLogicStart.Y() += pRefDevice->PixelToLogic(Size(0,nTopM)).Height(); 2843 else 2844 aLogicStart.Y() += nTopM; 2845 } 2846 2847 if ( ( eOrient==SVX_ORIENTATION_STANDARD && !bAsianVertical ) || 2848 eOrient==SVX_ORIENTATION_STACKED || !bBreak ) 2849 { 2850 if (eVerJust==SVX_VER_JUSTIFY_BOTTOM || 2851 eVerJust==SVX_VER_JUSTIFY_STANDARD) 2852 { 2853 //! if pRefDevice != pFmtDevice, keep heights in logic units, 2854 //! only converting margin? 2855 2856 if (bPixelToLogic) 2857 aLogicStart.Y() += pRefDevice->PixelToLogic( Size(0, nTopM + 2858 pRefDevice->LogicToPixel(aCellSize).Height() - 2859 pRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() 2860 )).Height(); 2861 else 2862 aLogicStart.Y() += nTopM + aCellSize.Height() - nEngineHeight; 2863 } 2864 else if (eVerJust==SVX_VER_JUSTIFY_CENTER) 2865 { 2866 if (bPixelToLogic) 2867 aLogicStart.Y() += pRefDevice->PixelToLogic( Size(0, nTopM + ( 2868 pRefDevice->LogicToPixel(aCellSize).Height() - 2869 pRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() ) 2870 / 2)).Height(); 2871 else 2872 aLogicStart.Y() += nTopM + (aCellSize.Height() - nEngineHeight) / 2; 2873 } 2874 else // top 2875 { 2876 if (bPixelToLogic) 2877 aLogicStart.Y() += pRefDevice->PixelToLogic(Size(0,nTopM)).Height(); 2878 else 2879 aLogicStart.Y() += nTopM; 2880 } 2881 } 2882 2883 Point aURLStart = aLogicStart; // copy before modifying for orientation 2884 2885 short nOriVal = 0; 2886 if (eOrient==SVX_ORIENTATION_TOPBOTTOM) 2887 { 2888 // nOriVal = -900; 2889 nOriVal = 2700; 2890 aLogicStart.X() += nEngineWidth; 2891 } 2892 else if (eOrient==SVX_ORIENTATION_BOTTOMTOP) 2893 { 2894 nOriVal = 900; 2895 aLogicStart.Y() += bBreak ? pEngine->GetPaperSize().Width() : 2896 nEngineHeight; 2897 } 2898 else if (eOrient==SVX_ORIENTATION_STACKED) 2899 { 2900 Size aPaperLogic = pEngine->GetPaperSize(); 2901 aPaperLogic.Width() = nEngineWidth; 2902 pEngine->SetPaperSize(aPaperLogic); 2903 } 2904 2905 if ( pEngine->IsRightToLeft( 0 ) ) 2906 { 2907 // For right-to-left, EditEngine always calculates its lines 2908 // beginning from the right edge, but EditLine::nStartPosX is 2909 // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX. 2910 Size aLogicPaper = pEngine->GetPaperSize(); 2911 if ( aLogicPaper.Width() > USHRT_MAX ) 2912 { 2913 aLogicPaper.Width() = USHRT_MAX; 2914 pEngine->SetPaperSize(aLogicPaper); 2915 } 2916 } 2917 2918 // bMoveClipped handling has been replaced by complete alignment 2919 // handling (also extending to the left). 2920 2921 if ( bSimClip && !nOriVal && !bAsianVertical ) 2922 { 2923 // kein hartes Clipping, aber nur die betroffenen 2924 // Zeilen ausgeben 2925 2926 Point aDocStart = aLogicClip.TopLeft(); 2927 aDocStart -= aLogicStart; 2928 pEngine->Draw( pDev, aLogicClip, aDocStart, sal_False ); 2929 } 2930 else 2931 { 2932 if (bAsianVertical) 2933 { 2934 // with SetVertical, the start position is top left of 2935 // the whole output area, not the text itself 2936 aLogicStart.X() -= pEngine->GetPaperSize().Width(); 2937 } 2938 pEngine->Draw( pDev, aLogicStart, nOriVal ); 2939 } 2940 2941 if (bClip) 2942 { 2943 if (bMetaFile) 2944 pDev->Pop(); 2945 else 2946 pDev->SetClipRegion(); 2947 } 2948 2949 // PDF: whole-cell hyperlink from formula? 2950 sal_Bool bHasURL = pPDFData && pCell && pCell->GetCellType() == CELLTYPE_FORMULA && 2951 static_cast<ScFormulaCell*>(pCell)->IsHyperLinkCell(); 2952 if ( bHasURL ) 2953 { 2954 long nURLWidth = (long) pEngine->CalcTextWidth(); 2955 long nURLHeight = pEngine->GetTextHeight(); 2956 if ( bBreak ) 2957 { 2958 Size aPaper = pEngine->GetPaperSize(); 2959 if ( bAsianVertical ) 2960 nURLHeight = aPaper.Height(); 2961 else 2962 nURLWidth = aPaper.Width(); 2963 } 2964 if ( eOrient == SVX_ORIENTATION_TOPBOTTOM || eOrient == SVX_ORIENTATION_BOTTOMTOP ) 2965 std::swap( nURLWidth, nURLHeight ); 2966 else if ( bAsianVertical ) 2967 aURLStart.X() -= nURLWidth; 2968 2969 Rectangle aURLRect( aURLStart, Size( nURLWidth, nURLHeight ) ); 2970 lcl_DoHyperlinkResult( pDev, aURLRect, pCell ); 2971 } 2972 } 2973 } 2974 } 2975 } 2976 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign; 2977 } 2978 } 2979 nRowPosY += pRowInfo[nArrY].nHeight; 2980 } 2981 2982 delete pEngine; 2983 2984 if (bAnyRotated) 2985 DrawRotated(bPixelToLogic); //! von aussen rufen ? 2986 } 2987 2988 // ------------------------------------------------------------------------------- 2989 2990 void ScOutputData::DrawRotated(sal_Bool bPixelToLogic) 2991 { 2992 //! nRotMax speichern 2993 SCCOL nRotMax = nX2; 2994 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++) 2995 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax) 2996 nRotMax = pRowInfo[nRotY].nRotMaxCol; 2997 2998 2999 ScModule* pScMod = SC_MOD(); 3000 sal_Int32 nConfBackColor = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; 3001 // #105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True) 3002 sal_Bool bCellContrast = bUseStyleColor && 3003 Application::GetSettings().GetStyleSettings().GetHighContrastMode(); 3004 3005 ScFieldEditEngine* pEngine = NULL; 3006 sal_Bool bHyphenatorSet = sal_False; 3007 const ScPatternAttr* pPattern; 3008 const SfxItemSet* pCondSet; 3009 const ScPatternAttr* pOldPattern = NULL; 3010 const SfxItemSet* pOldCondSet = NULL; 3011 ScBaseCell* pCell = NULL; 3012 3013 long nInitPosX = nScrX; 3014 if ( bLayoutRTL ) 3015 { 3016 #if 0 3017 Size aOnePixel = pDev->PixelToLogic(Size(1,1)); 3018 long nOneX = aOnePixel.Width(); 3019 nInitPosX += nMirrorW - nOneX; 3020 #endif 3021 nInitPosX += nMirrorW - 1; 3022 } 3023 long nLayoutSign = bLayoutRTL ? -1 : 1; 3024 3025 long nRowPosY = nScrY; 3026 for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 fuer Reste von zusammengefassten 3027 { 3028 RowInfo* pThisRowInfo = &pRowInfo[nArrY]; 3029 long nCellHeight = (long) pThisRowInfo->nHeight; 3030 if (nArrY==1) nRowPosY = nScrY; // vorher wird einzeln berechnet 3031 3032 if ( ( pThisRowInfo->bChanged || nArrY==0 ) && pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE ) 3033 { 3034 long nPosX = 0; 3035 for (SCCOL nX=0; nX<=nRotMax; nX++) 3036 { 3037 if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually 3038 3039 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1]; 3040 if ( pInfo->nRotateDir != SC_ROTDIR_NONE ) 3041 { 3042 SCROW nY = pThisRowInfo->nRowNo; 3043 3044 sal_Bool bHidden = sal_False; 3045 if (bEditMode) 3046 if ( nX == nEditCol && nY == nEditRow ) 3047 bHidden = sal_True; 3048 3049 if (!bHidden) 3050 { 3051 if (!pEngine) 3052 pEngine = CreateOutputEditEngine(); 3053 else 3054 lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False) 3055 3056 long nPosY = nRowPosY; 3057 sal_Bool bVisChanged = sal_False; 3058 3059 //! Rest von zusammengefasster Zelle weiter oben funktioniert nicht! 3060 3061 sal_Bool bFromDoc = sal_False; 3062 pPattern = pInfo->pPatternAttr; 3063 pCondSet = pInfo->pConditionSet; 3064 if (!pPattern) 3065 { 3066 pPattern = pDoc->GetPattern( nX, nY, nTab ); 3067 bFromDoc = sal_True; 3068 } 3069 pCell = pInfo->pCell; 3070 if (bFromDoc) 3071 pCondSet = pDoc->GetCondResult( nX, nY, nTab ); 3072 3073 if (!pCell && nX>nX2) 3074 GetVisibleCell( nX, nY, nTab, pCell ); 3075 3076 if ( !pCell || IsEmptyCellText( pThisRowInfo, nX, nY ) ) 3077 bHidden = sal_True; // nRotateDir is also set without a cell 3078 3079 long nCellWidth = (long) pRowInfo[0].pCellInfo[nX+1].nWidth; 3080 3081 SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&) 3082 pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet)).GetValue(); 3083 sal_Bool bBreak = ( eHorJust == SVX_HOR_JUSTIFY_BLOCK ) || 3084 ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue(); 3085 sal_Bool bRepeat = ( eHorJust == SVX_HOR_JUSTIFY_REPEAT && !bBreak ); 3086 sal_Bool bShrink = !bBreak && !bRepeat && static_cast<const SfxBoolItem&> 3087 (pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue(); 3088 SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet ); 3089 3090 const ScMergeAttr* pMerge = 3091 (ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE); 3092 sal_Bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1; 3093 3094 long nStartX = nPosX; 3095 long nStartY = nPosY; 3096 if (nX<nX1) 3097 { 3098 if ((bBreak || eOrient!=SVX_ORIENTATION_STANDARD) && !bMerged) 3099 bHidden = sal_True; 3100 else 3101 { 3102 nStartX = nInitPosX; 3103 SCCOL nCol = nX1; 3104 while (nCol > nX) 3105 { 3106 --nCol; 3107 nStartX -= nLayoutSign * (long) pRowInfo[0].pCellInfo[nCol+1].nWidth; 3108 } 3109 } 3110 } 3111 long nCellStartX = nStartX; 3112 3113 // Ersatzdarstellung fuer zu kleinen Text weggelassen 3114 3115 if (!bHidden) 3116 { 3117 long nOutWidth = nCellWidth - 1; 3118 long nOutHeight; 3119 if (pInfo) 3120 nOutHeight = nCellHeight; 3121 else 3122 nOutHeight = (long) ( pDoc->GetRowHeight(nY,nTab) * nPPTY ); 3123 3124 if ( bMerged ) // Zusammengefasst 3125 { 3126 SCCOL nCountX = pMerge->GetColMerge(); 3127 for (SCCOL i=1; i<nCountX; i++) 3128 nOutWidth += (long) ( pDoc->GetColWidth(nX+i,nTab) * nPPTX ); 3129 SCROW nCountY = pMerge->GetRowMerge(); 3130 nOutHeight += (long) pDoc->GetScaledRowHeight( nY+1, nY+nCountY-1, nTab, nPPTY); 3131 } 3132 3133 SvxCellVerJustify eVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&) 3134 pPattern->GetItem(ATTR_VER_JUSTIFY, pCondSet)).GetValue(); 3135 3136 // Syntax-Modus wird hier ignoriert... 3137 3138 // StringDiffer doesn't look at hyphenate, language items 3139 if ( pPattern != pOldPattern || pCondSet != pOldCondSet ) 3140 { 3141 SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() ); 3142 pPattern->FillEditItemSet( pSet, pCondSet ); 3143 3144 // Ausrichtung fuer EditEngine 3145 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT; 3146 if (eOrient==SVX_ORIENTATION_STACKED) 3147 eSvxAdjust = SVX_ADJUST_CENTER; 3148 // Adjustment fuer bBreak ist hier weggelassen 3149 pSet->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) ); 3150 3151 pEngine->SetDefaults( pSet ); 3152 pOldPattern = pPattern; 3153 pOldCondSet = pCondSet; 3154 3155 sal_uLong nControl = pEngine->GetControlWord(); 3156 if (eOrient==SVX_ORIENTATION_STACKED) 3157 nControl |= EE_CNTRL_ONECHARPERLINE; 3158 else 3159 nControl &= ~EE_CNTRL_ONECHARPERLINE; 3160 pEngine->SetControlWord( nControl ); 3161 3162 if ( !bHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) 3163 { 3164 // set hyphenator the first time it is needed 3165 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() ); 3166 pEngine->SetHyphenator( xXHyphenator ); 3167 bHyphenatorSet = sal_True; 3168 } 3169 3170 Color aBackCol = ((const SvxBrushItem&) 3171 pPattern->GetItem( ATTR_BACKGROUND, pCondSet )).GetColor(); 3172 if ( bUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) ) 3173 aBackCol.SetColor( nConfBackColor ); 3174 pEngine->SetBackgroundColor( aBackCol ); 3175 } 3176 3177 // Raender 3178 3179 //! Position und Papersize auf EditUtil umstellen !!! 3180 3181 const SvxMarginItem* pMargin = (const SvxMarginItem*) 3182 &pPattern->GetItem(ATTR_MARGIN, pCondSet); 3183 sal_uInt16 nIndent = 0; 3184 if ( eHorJust == SVX_HOR_JUSTIFY_LEFT ) 3185 nIndent = ((const SfxUInt16Item&)pPattern-> 3186 GetItem(ATTR_INDENT, pCondSet)).GetValue(); 3187 3188 long nTotalHeight = nOutHeight; // ohne Rand abzuziehen 3189 if ( bPixelToLogic ) 3190 nTotalHeight = pRefDevice->PixelToLogic(Size(0,nTotalHeight)).Height(); 3191 3192 long nLeftM = (long) ( (pMargin->GetLeftMargin() + nIndent) * nPPTX ); 3193 long nTopM = (long) ( pMargin->GetTopMargin() * nPPTY ); 3194 long nRightM = (long) ( pMargin->GetRightMargin() * nPPTX ); 3195 long nBottomM = (long) ( pMargin->GetBottomMargin() * nPPTY ); 3196 nStartX += nLeftM; 3197 nStartY += nTopM; 3198 nOutWidth -= nLeftM + nRightM; 3199 nOutHeight -= nTopM + nBottomM; 3200 3201 // Rotation schon hier, um bei Umbruch auch PaperSize anzupassen 3202 long nAttrRotate = 0; 3203 double nSin = 0.0; 3204 double nCos = 1.0; 3205 SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD; 3206 if ( eOrient == SVX_ORIENTATION_STANDARD ) 3207 { 3208 nAttrRotate = ((const SfxInt32Item&)pPattern-> 3209 GetItem(ATTR_ROTATE_VALUE, pCondSet)).GetValue(); 3210 if ( nAttrRotate ) 3211 { 3212 eRotMode = (SvxRotateMode)((const SvxRotateModeItem&) 3213 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue(); 3214 3215 if ( nAttrRotate == 18000 ) 3216 eRotMode = SVX_ROTATE_MODE_STANDARD; // keinen Ueberlauf 3217 3218 if ( bLayoutRTL ) 3219 nAttrRotate = -nAttrRotate; 3220 3221 double nRealOrient = nAttrRotate * F_PI18000; // 1/100 Grad 3222 nCos = cos( nRealOrient ); 3223 nSin = sin( nRealOrient ); 3224 } 3225 } 3226 3227 Size aPaperSize = Size( 1000000, 1000000 ); 3228 if (eOrient==SVX_ORIENTATION_STACKED) 3229 aPaperSize.Width() = nOutWidth; // zum Zentrieren 3230 else if (bBreak) 3231 { 3232 if (nAttrRotate) 3233 { 3234 //! richtige PaperSize fuer Umbruch haengt von der Zeilenzahl 3235 //! ab, solange die Zeilen nicht einzeln versetzt ausgegeben 3236 //! werden koennen -> darum unbegrenzt, also kein Umbruch. 3237 //! Mit versetzten Zeilen waere das folgende richtig: 3238 aPaperSize.Width() = (long)(nOutHeight / fabs(nSin)); 3239 } 3240 else if (eOrient == SVX_ORIENTATION_STANDARD) 3241 aPaperSize.Width() = nOutWidth; 3242 else 3243 aPaperSize.Width() = nOutHeight - 1; 3244 } 3245 if (bPixelToLogic) 3246 pEngine->SetPaperSize(pRefDevice->PixelToLogic(aPaperSize)); 3247 else 3248 pEngine->SetPaperSize(aPaperSize); // Scale ist immer 1 3249 3250 // Daten aus Zelle lesen 3251 3252 if (pCell) 3253 { 3254 if (pCell->GetCellType() == CELLTYPE_EDIT) 3255 { 3256 const EditTextObject* pData; 3257 ((ScEditCell*)pCell)->GetData(pData); 3258 3259 if (pData) 3260 pEngine->SetText(*pData); 3261 else 3262 { 3263 DBG_ERROR("pData == 0"); 3264 } 3265 } 3266 else 3267 { 3268 sal_uLong nFormat = pPattern->GetNumberFormat( 3269 pDoc->GetFormatTable(), pCondSet ); 3270 String aString; 3271 Color* pColor; 3272 ScCellFormat::GetString( pCell, 3273 nFormat,aString, &pColor, 3274 *pDoc->GetFormatTable(), 3275 bShowNullValues, 3276 bShowFormulas, 3277 ftCheck ); 3278 3279 pEngine->SetText(aString); 3280 if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) ) 3281 lcl_SetEditColor( *pEngine, *pColor ); 3282 } 3283 3284 if ( bSyntaxMode ) 3285 SetEditSyntaxColor( *pEngine, pCell ); 3286 else if ( bUseStyleColor && bForceAutoColor ) 3287 lcl_SetEditColor( *pEngine, COL_AUTO ); //! or have a flag at EditEngine 3288 } 3289 else 3290 { 3291 DBG_ERROR("pCell == NULL"); 3292 } 3293 3294 pEngine->SetUpdateMode( sal_True ); // after SetText, before CalcTextWidth/GetTextHeight 3295 3296 long nEngineWidth = (long) pEngine->CalcTextWidth(); 3297 long nEngineHeight = pEngine->GetTextHeight(); 3298 3299 if (nAttrRotate && bBreak) 3300 { 3301 double nAbsCos = fabs( nCos ); 3302 double nAbsSin = fabs( nSin ); 3303 3304 // #47740# adjust witdh of papersize for height of text 3305 int nSteps = 5; 3306 while (nSteps > 0) 3307 { 3308 // everything is in pixels 3309 long nEnginePixel = pRefDevice->LogicToPixel( 3310 Size(0,nEngineHeight)).Height(); 3311 long nEffHeight = nOutHeight - (long)(nEnginePixel * nAbsCos) + 2; 3312 long nNewWidth = (long)(nEffHeight / nAbsSin) + 2; 3313 sal_Bool bFits = ( nNewWidth >= aPaperSize.Width() ); 3314 if ( bFits ) 3315 nSteps = 0; 3316 else 3317 { 3318 if ( nNewWidth < 4 ) 3319 { 3320 // can't fit -> fall back to using half height 3321 nEffHeight = nOutHeight / 2; 3322 nNewWidth = (long)(nEffHeight / nAbsSin) + 2; 3323 nSteps = 0; 3324 } 3325 else 3326 --nSteps; 3327 3328 // set paper width and get new text height 3329 aPaperSize.Width() = nNewWidth; 3330 if (bPixelToLogic) 3331 pEngine->SetPaperSize(pRefDevice->PixelToLogic(aPaperSize)); 3332 else 3333 pEngine->SetPaperSize(aPaperSize); // Scale ist immer 1 3334 //pEngine->QuickFormatDoc( sal_True ); 3335 nEngineWidth = (long) pEngine->CalcTextWidth(); 3336 nEngineHeight = pEngine->GetTextHeight(); 3337 } 3338 } 3339 } 3340 3341 long nRealWidth = nEngineWidth; 3342 long nRealHeight = nEngineHeight; 3343 3344 // wenn gedreht, Groesse anpassen 3345 if (nAttrRotate) 3346 { 3347 double nAbsCos = fabs( nCos ); 3348 double nAbsSin = fabs( nSin ); 3349 3350 if ( eRotMode == SVX_ROTATE_MODE_STANDARD ) 3351 nEngineWidth = (long) ( nRealWidth * nAbsCos + 3352 nRealHeight * nAbsSin ); 3353 else 3354 nEngineWidth = (long) ( nRealHeight / nAbsSin ); 3355 //! begrenzen !!! 3356 3357 nEngineHeight = (long) ( nRealHeight * nAbsCos + 3358 nRealWidth * nAbsSin ); 3359 } 3360 3361 if (!nAttrRotate) // hier nur gedrehter Text 3362 bHidden = sal_True; //! vorher abfragen !!! 3363 3364 //! weglassen, was nicht hereinragt 3365 3366 if (!bHidden) 3367 { 3368 sal_Bool bClip = sal_False; 3369 Size aClipSize = Size( nScrX+nScrW-nStartX, nScrY+nScrH-nStartY ); 3370 3371 // weiterschreiben 3372 3373 Size aCellSize; 3374 if (bPixelToLogic) 3375 aCellSize = pRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) ); 3376 else 3377 aCellSize = Size( nOutWidth, nOutHeight ); // Scale ist 1 3378 3379 long nGridWidth = nEngineWidth; 3380 sal_Bool bNegative = sal_False; 3381 if ( eRotMode != SVX_ROTATE_MODE_STANDARD ) 3382 { 3383 nGridWidth = aCellSize.Width() + 3384 Abs((long) ( aCellSize.Height() * nCos / nSin )); 3385 bNegative = ( pInfo->nRotateDir == SC_ROTDIR_LEFT ); 3386 if ( bLayoutRTL ) 3387 bNegative = !bNegative; 3388 } 3389 3390 // use GetOutputArea to hide the grid 3391 // (clip region is done manually below) 3392 OutputAreaParam aAreaParam; 3393 3394 SCCOL nCellX = nX; 3395 SCROW nCellY = nY; 3396 SvxCellHorJustify eOutHorJust = eHorJust; 3397 if ( eRotMode != SVX_ROTATE_MODE_STANDARD ) 3398 eOutHorJust = bNegative ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT; 3399 long nNeededWidth = nGridWidth; // in pixel for GetOutputArea 3400 if ( bPixelToLogic ) 3401 nNeededWidth = pRefDevice->LogicToPixel(Size(nNeededWidth,0)).Width(); 3402 3403 GetOutputArea( nX, nArrY, nCellStartX, nPosY, nCellX, nCellY, nNeededWidth, 3404 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust), 3405 sal_False, sal_False, sal_True, aAreaParam ); 3406 3407 if ( bShrink ) 3408 { 3409 long nPixelWidth = bPixelToLogic ? 3410 pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width() : nEngineWidth; 3411 long nNeededPixel = nPixelWidth + nLeftM + nRightM; 3412 3413 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = sal_True; 3414 3415 // always do height 3416 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM, 3417 sal_False, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic, 3418 nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip ); 3419 3420 if ( eRotMode == SVX_ROTATE_MODE_STANDARD ) 3421 { 3422 // do width only if rotating within the cell (standard mode) 3423 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM, 3424 sal_True, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic, 3425 nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip ); 3426 } 3427 3428 // nEngineWidth/nEngineHeight is updated in ShrinkEditEngine 3429 // (but width is only valid for standard mode) 3430 nRealWidth = (long) pEngine->CalcTextWidth(); 3431 nRealHeight = pEngine->GetTextHeight(); 3432 3433 if ( eRotMode != SVX_ROTATE_MODE_STANDARD ) 3434 nEngineWidth = (long) ( nRealHeight / fabs( nSin ) ); 3435 } 3436 3437 // sal_Bool bVClip = ( nEngineHeight > aCellSize.Height() ); 3438 3439 long nClipStartX = nStartX; 3440 if (nX<nX1) 3441 { 3442 //! Clipping unnoetig, wenn links am Fenster 3443 3444 bClip = sal_True; // nur Rest ausgeben! 3445 if (nStartX<nScrX) 3446 { 3447 long nDif = nScrX - nStartX; 3448 nClipStartX = nScrX; 3449 aClipSize.Width() -= nDif; 3450 } 3451 } 3452 3453 long nClipStartY = nStartY; 3454 if (nArrY==0 || bVisChanged) 3455 { 3456 if ( nClipStartY < nRowPosY ) 3457 { 3458 long nDif = nRowPosY - nClipStartY; 3459 bClip = sal_True; 3460 nClipStartY = nRowPosY; 3461 aClipSize.Height() -= nDif; 3462 } 3463 } 3464 3465 bClip = sal_True; // always clip at the window/page border 3466 3467 //Rectangle aClipRect; 3468 if (bClip) 3469 { 3470 if ( nAttrRotate /* && eRotMode != SVX_ROTATE_MODE_STANDARD */ ) 3471 { 3472 // gedrehten, ausgerichteten Text nur an den 3473 // Seitengrenzen clippen 3474 nClipStartX = nScrX; 3475 aClipSize.Width() = nScrW; 3476 } 3477 3478 if (bPixelToLogic) 3479 aAreaParam.maClipRect = pRefDevice->PixelToLogic( Rectangle( 3480 Point(nClipStartX,nClipStartY), aClipSize ) ); 3481 else 3482 aAreaParam.maClipRect = Rectangle(Point(nClipStartX, nClipStartY), 3483 aClipSize ); // Scale = 1 3484 3485 if (bMetaFile) 3486 { 3487 pDev->Push(); 3488 pDev->IntersectClipRegion( aAreaParam.maClipRect ); 3489 } 3490 else 3491 pDev->SetClipRegion( Region( aAreaParam.maClipRect ) ); 3492 } 3493 3494 Point aLogicStart; 3495 if (bPixelToLogic) 3496 aLogicStart = pRefDevice->PixelToLogic( Point(nStartX,nStartY) ); 3497 else 3498 aLogicStart = Point(nStartX, nStartY); 3499 if ( eOrient!=SVX_ORIENTATION_STANDARD || !bBreak ) 3500 { 3501 long nAvailWidth = aCellSize.Width(); 3502 if (eType==OUTTYPE_WINDOW && 3503 eOrient!=SVX_ORIENTATION_STACKED && 3504 pInfo && pInfo->bAutoFilter) 3505 { 3506 // filter drop-down width is now independent from row height 3507 if (bPixelToLogic) 3508 nAvailWidth -= pRefDevice->PixelToLogic(Size(0,DROPDOWN_BITMAP_SIZE)).Height(); 3509 else 3510 nAvailWidth -= DROPDOWN_BITMAP_SIZE; 3511 long nComp = nEngineWidth; 3512 if (nAvailWidth<nComp) nAvailWidth=nComp; 3513 } 3514 3515 // horizontale Ausrichtung 3516 3517 if (eOrient==SVX_ORIENTATION_STANDARD && !nAttrRotate) 3518 { 3519 if (eHorJust==SVX_HOR_JUSTIFY_RIGHT || 3520 eHorJust==SVX_HOR_JUSTIFY_CENTER) 3521 { 3522 pEngine->SetUpdateMode( sal_False ); 3523 3524 SvxAdjust eSvxAdjust = 3525 (eHorJust==SVX_HOR_JUSTIFY_RIGHT) ? 3526 SVX_ADJUST_RIGHT : SVX_ADJUST_CENTER; 3527 pEngine->SetDefaultItem( 3528 SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) ); 3529 3530 aPaperSize.Width() = nOutWidth; 3531 if (bPixelToLogic) 3532 pEngine->SetPaperSize(pRefDevice->PixelToLogic(aPaperSize)); 3533 else 3534 pEngine->SetPaperSize(aPaperSize); 3535 3536 pEngine->SetUpdateMode( sal_True ); 3537 } 3538 } 3539 else 3540 { 3541 // bei gedrehtem Text ist Standard zentriert 3542 if (eHorJust==SVX_HOR_JUSTIFY_RIGHT) 3543 aLogicStart.X() += nAvailWidth - nEngineWidth; 3544 else if (eHorJust==SVX_HOR_JUSTIFY_CENTER || 3545 eHorJust==SVX_HOR_JUSTIFY_STANDARD) 3546 aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2; 3547 } 3548 } 3549 3550 if ( bLayoutRTL ) 3551 { 3552 if (bPixelToLogic) 3553 aLogicStart.X() -= pRefDevice->PixelToLogic( 3554 Size( nCellWidth, 0 ) ).Width(); 3555 else 3556 aLogicStart.X() -= nCellWidth; 3557 } 3558 3559 if ( eOrient==SVX_ORIENTATION_STANDARD || 3560 eOrient==SVX_ORIENTATION_STACKED || !bBreak ) 3561 { 3562 if (eVerJust==SVX_VER_JUSTIFY_BOTTOM || 3563 eVerJust==SVX_VER_JUSTIFY_STANDARD) 3564 { 3565 if (bPixelToLogic) 3566 aLogicStart.Y() += pRefDevice->PixelToLogic( Size(0, 3567 pRefDevice->LogicToPixel(aCellSize).Height() - 3568 pRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() 3569 )).Height(); 3570 else 3571 aLogicStart.Y() += aCellSize.Height() - nEngineHeight; 3572 } 3573 3574 else if (eVerJust==SVX_VER_JUSTIFY_CENTER) 3575 { 3576 if (bPixelToLogic) 3577 aLogicStart.Y() += pRefDevice->PixelToLogic( Size(0,( 3578 pRefDevice->LogicToPixel(aCellSize).Height() - 3579 pRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()) 3580 / 2)).Height(); 3581 else 3582 aLogicStart.Y() += (aCellSize.Height() - nEngineHeight) / 2; 3583 } 3584 } 3585 3586 // TOPBOTTON and BOTTOMTOP are handled in DrawStrings/DrawEdit 3587 DBG_ASSERT( eOrient == SVX_ORIENTATION_STANDARD && nAttrRotate, 3588 "DrawRotated: no rotation" ); 3589 3590 long nOriVal = 0; 3591 if ( nAttrRotate ) 3592 { 3593 // Attribut ist 1/100, Font 1/10 Grad 3594 nOriVal = nAttrRotate / 10; 3595 3596 double nAddX = 0.0; 3597 double nAddY = 0.0; 3598 if ( nCos > 0.0 && eRotMode != SVX_ROTATE_MODE_STANDARD ) 3599 { 3600 //! begrenzen !!! 3601 double nH = nRealHeight * nCos; 3602 nAddX += nH * ( nCos / fabs(nSin) ); 3603 } 3604 if ( nCos < 0.0 && eRotMode == SVX_ROTATE_MODE_STANDARD ) 3605 nAddX -= nRealWidth * nCos; 3606 if ( nSin < 0.0 ) 3607 nAddX -= nRealHeight * nSin; 3608 if ( nSin > 0.0 ) 3609 nAddY += nRealWidth * nSin; 3610 if ( nCos < 0.0 ) 3611 nAddY -= nRealHeight * nCos; 3612 3613 if ( eRotMode != SVX_ROTATE_MODE_STANDARD ) 3614 { 3615 //! begrenzen !!! 3616 double nSkew = nTotalHeight * nCos / fabs(nSin); 3617 if ( eRotMode == SVX_ROTATE_MODE_CENTER ) 3618 nAddX -= nSkew * 0.5; 3619 if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nSin > 0.0 ) || 3620 ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nSin < 0.0 ) ) 3621 nAddX -= nSkew; 3622 3623 long nUp = 0; 3624 if ( eVerJust == SVX_VER_JUSTIFY_CENTER ) 3625 nUp = ( aCellSize.Height() - nEngineHeight ) / 2; 3626 else if ( eVerJust == SVX_VER_JUSTIFY_TOP ) 3627 { 3628 if ( nSin > 0.0 ) 3629 nUp = aCellSize.Height() - nEngineHeight; 3630 } 3631 else // BOTTOM / STANDARD 3632 { 3633 if ( nSin < 0.0 ) 3634 nUp = aCellSize.Height() - nEngineHeight; 3635 } 3636 if ( nUp ) 3637 nAddX += ( nUp * nCos / fabs(nSin) ); 3638 } 3639 3640 aLogicStart.X() += (long) nAddX; 3641 aLogicStart.Y() += (long) nAddY; 3642 } 3643 3644 // bSimClip is not used here (because nOriVal is set) 3645 3646 if ( pEngine->IsRightToLeft( 0 ) ) 3647 { 3648 // For right-to-left, EditEngine always calculates its lines 3649 // beginning from the right edge, but EditLine::nStartPosX is 3650 // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX. 3651 Size aLogicPaper = pEngine->GetPaperSize(); 3652 if ( aLogicPaper.Width() > USHRT_MAX ) 3653 { 3654 aLogicPaper.Width() = USHRT_MAX; 3655 pEngine->SetPaperSize(aLogicPaper); 3656 } 3657 } 3658 3659 pEngine->Draw( pDev, aLogicStart, (short)nOriVal ); 3660 3661 if (bClip) 3662 { 3663 if (bMetaFile) 3664 pDev->Pop(); 3665 else 3666 pDev->SetClipRegion(); 3667 } 3668 } 3669 } 3670 } 3671 } 3672 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign; 3673 } 3674 } 3675 nRowPosY += pRowInfo[nArrY].nHeight; 3676 } 3677 3678 delete pEngine; 3679 } 3680 3681 3682 3683