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