Version 4.0.2.1, tag libreoffice-4.0.2.1
[LibreOffice.git] / sc / source / ui / view / output2.cxx
blob5461fec2c0e0e4262f37b3e7913fbeb5927d61d7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "scitems.hxx"
21 #include <editeng/eeitem.hxx>
23 #include <editeng/adjitem.hxx>
24 #include <svx/algitem.hxx>
25 #include <editeng/brshitem.hxx>
26 #include <svtools/colorcfg.hxx>
27 #include <editeng/colritem.hxx>
28 #include <editeng/editobj.hxx>
29 #include <editeng/editstat.hxx>
30 #include <editeng/fhgtitem.hxx>
31 #include <editeng/forbiddencharacterstable.hxx>
32 #include <editeng/frmdiritem.hxx>
33 #include <editeng/langitem.hxx>
34 #include <editeng/justifyitem.hxx>
35 #include <svx/rotmodit.hxx>
36 #include <editeng/scripttypeitem.hxx>
37 #include <editeng/udlnitem.hxx>
38 #include <editeng/unolingu.hxx>
39 #include <svl/zforlist.hxx>
40 #include <svl/zformat.hxx>
41 #include <vcl/svapp.hxx>
42 #include <vcl/metric.hxx>
43 #include <vcl/outdev.hxx>
44 #include <vcl/pdfextoutdevdata.hxx>
46 #include "output.hxx"
47 #include "document.hxx"
48 #include "cell.hxx"
49 #include "attrib.hxx"
50 #include "patattr.hxx"
51 #include "cellform.hxx"
52 #include "editutil.hxx"
53 #include "progress.hxx"
54 #include "scmod.hxx"
55 #include "fillinfo.hxx"
57 #include <com/sun/star/i18n/DirectionProperty.hpp>
58 #include <comphelper/string.hxx>
60 #include <boost/ptr_container/ptr_vector.hpp>
62 #include <math.h>
64 using namespace com::sun::star;
66 //! Autofilter-Breite mit column.cxx zusammenfassen
67 #define DROPDOWN_BITMAP_SIZE 18
69 #define DRAWTEXT_MAX 32767
71 const sal_uInt16 SC_SHRINKAGAIN_MAX = 7;
73 // STATIC DATA -----------------------------------------------------------
76 // -----------------------------------------------------------------------
78 class ScDrawStringsVars
80 ScOutputData* pOutput; // Verbindung
82 const ScPatternAttr* pPattern; // Attribute
83 const SfxItemSet* pCondSet; // aus bedingter Formatierung
85 Font aFont; // aus Attributen erzeugt
86 FontMetric aMetric;
87 long nAscentPixel; // always pixels
88 SvxCellOrientation eAttrOrient;
89 SvxCellHorJustify eAttrHorJust;
90 SvxCellVerJustify eAttrVerJust;
91 SvxCellJustifyMethod eAttrHorJustMethod;
92 SvxCellJustifyMethod eAttrVerJustMethod;
93 const SvxMarginItem* pMargin;
94 sal_uInt16 nIndent;
95 sal_Bool bRotated;
97 String aString; // Inhalte
98 Size aTextSize;
99 long nOriginalWidth;
100 long nMaxDigitWidth;
101 long nSignWidth;
102 long nDotWidth;
103 long nExpWidth;
105 ScBaseCell* pLastCell;
106 sal_uLong nValueFormat;
107 sal_Bool bLineBreak;
108 sal_Bool bRepeat;
109 sal_Bool bShrink;
111 sal_Bool bPixelToLogic;
112 sal_Bool bCellContrast;
114 Color aBackConfigColor; // used for ScPatternAttr::GetFont calls
115 Color aTextConfigColor;
116 sal_Int32 nPos;
117 sal_Unicode nChar;
119 public:
120 ScDrawStringsVars(ScOutputData* pData, sal_Bool bPTL);
121 ~ScDrawStringsVars();
123 // SetPattern = ex-SetVars
124 // SetPatternSimple: ohne Font
126 void SetPattern( const ScPatternAttr* pNew, const SfxItemSet* pSet, ScBaseCell* pCell, sal_uInt8 nScript );
127 void SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet );
129 sal_Bool SetText( ScBaseCell* pCell ); // TRUE -> pOldPattern vergessen
130 void SetHashText();
131 void SetTextToWidthOrHash( ScBaseCell* pCell, long nWidth );
132 void SetAutoText( const String& rAutoText );
134 const ScPatternAttr* GetPattern() const { return pPattern; }
135 SvxCellOrientation GetOrient() const { return eAttrOrient; }
136 SvxCellHorJustify GetHorJust() const { return eAttrHorJust; }
137 SvxCellVerJustify GetVerJust() const { return eAttrVerJust; }
138 SvxCellJustifyMethod GetHorJustMethod() const { return eAttrHorJustMethod; }
139 SvxCellJustifyMethod GetVerJustMethod() const { return eAttrVerJustMethod; }
140 const SvxMarginItem* GetMargin() const { return pMargin; }
142 sal_uInt16 GetLeftTotal() const { return pMargin->GetLeftMargin() + nIndent; }
144 const String& GetString() const { return aString; }
145 const Size& GetTextSize() const { return aTextSize; }
146 long GetOriginalWidth() const { return nOriginalWidth; }
148 sal_uLong GetResultValueFormat( const ScBaseCell* pCell ) const;
150 sal_uLong GetValueFormat() const { return nValueFormat; }
151 sal_Bool GetLineBreak() const { return bLineBreak; }
152 sal_Bool IsRepeat() const { return bRepeat; }
153 sal_Bool IsShrink() const { return bShrink; }
154 void RepeatToFill( long colWidth );
156 long GetAscent() const { return nAscentPixel; }
157 sal_Bool IsRotated() const { return bRotated; }
159 void SetShrinkScale( long nScale, sal_uInt8 nScript );
161 sal_Bool HasCondHeight() const { return pCondSet && SFX_ITEM_SET ==
162 pCondSet->GetItemState( ATTR_FONT_HEIGHT, sal_True ); }
164 sal_Bool HasEditCharacters() const;
166 private:
167 long GetMaxDigitWidth(); // in logic units
168 long GetSignWidth();
169 long GetDotWidth();
170 long GetExpWidth();
171 void TextChanged();
174 //==================================================================
176 ScDrawStringsVars::ScDrawStringsVars(ScOutputData* pData, sal_Bool bPTL) :
177 pOutput ( pData ),
178 pPattern ( NULL ),
179 pCondSet ( NULL ),
180 nAscentPixel(0),
181 eAttrOrient ( SVX_ORIENTATION_STANDARD ),
182 eAttrHorJust( SVX_HOR_JUSTIFY_STANDARD ),
183 eAttrVerJust( SVX_VER_JUSTIFY_BOTTOM ),
184 eAttrHorJustMethod( SVX_JUSTIFY_METHOD_AUTO ),
185 eAttrVerJustMethod( SVX_JUSTIFY_METHOD_AUTO ),
186 pMargin ( NULL ),
187 nIndent ( 0 ),
188 bRotated ( false ),
189 nOriginalWidth( 0 ),
190 nMaxDigitWidth( 0 ),
191 nSignWidth( 0 ),
192 nDotWidth( 0 ),
193 nExpWidth( 0 ),
194 pLastCell ( NULL ),
195 nValueFormat( 0 ),
196 bLineBreak ( false ),
197 bRepeat ( false ),
198 bShrink ( false ),
199 bPixelToLogic( bPTL ),
200 nPos( STRING_NOTFOUND ),
201 nChar( 0x0 )
203 ScModule* pScMod = SC_MOD();
204 bCellContrast = pOutput->mbUseStyleColor &&
205 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
207 const svtools::ColorConfig& rColorConfig = pScMod->GetColorConfig();
208 aBackConfigColor.SetColor( rColorConfig.GetColorValue(svtools::DOCCOLOR).nColor );
209 aTextConfigColor.SetColor( rColorConfig.GetColorValue(svtools::FONTCOLOR).nColor );
212 ScDrawStringsVars::~ScDrawStringsVars()
216 void ScDrawStringsVars::SetShrinkScale( long nScale, sal_uInt8 nScript )
218 // text remains valid, size is updated
220 OutputDevice* pDev = pOutput->mpDev;
221 OutputDevice* pRefDevice = pOutput->mpRefDevice;
222 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
224 // call GetFont with a modified fraction, use only the height
226 Fraction aFraction( nScale, 100 );
227 if ( !bPixelToLogic )
228 aFraction *= pOutput->aZoomY;
229 Font aTmpFont;
230 pPattern->GetFont( aTmpFont, SC_AUTOCOL_RAW, pFmtDevice, &aFraction, pCondSet, nScript );
231 long nNewHeight = aTmpFont.GetHeight();
232 if ( nNewHeight > 0 )
233 aFont.SetHeight( nNewHeight );
235 // set font and dependent variables as in SetPattern
237 pDev->SetFont( aFont );
238 if ( pFmtDevice != pDev )
239 pFmtDevice->SetFont( aFont );
241 aMetric = pFmtDevice->GetFontMetric();
242 if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 )
244 OutputDevice* pDefaultDev = Application::GetDefaultDevice();
245 MapMode aOld = pDefaultDev->GetMapMode();
246 pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
247 aMetric = pDefaultDev->GetFontMetric( aFont );
248 pDefaultDev->SetMapMode( aOld );
251 nAscentPixel = aMetric.GetAscent();
252 if ( bPixelToLogic )
253 nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
255 SetAutoText( aString ); // same text again, to get text size
258 namespace {
260 template<typename _ItemType, typename _EnumType>
261 _EnumType lcl_GetValue(const ScPatternAttr& rPattern, sal_uInt16 nWhich, const SfxItemSet* pCondSet)
263 const _ItemType& rItem = static_cast<const _ItemType&>(rPattern.GetItem(nWhich, pCondSet));
264 return static_cast<_EnumType>(rItem.GetValue());
267 bool lcl_GetBoolValue(const ScPatternAttr& rPattern, sal_uInt16 nWhich, const SfxItemSet* pCondSet)
269 return lcl_GetValue<SfxBoolItem, bool>(rPattern, nWhich, pCondSet);
274 void ScDrawStringsVars::SetPattern( const ScPatternAttr* pNew, const SfxItemSet* pSet,
275 ScBaseCell* pCell, sal_uInt8 nScript )
277 nMaxDigitWidth = 0;
278 nSignWidth = 0;
279 nDotWidth = 0;
280 nExpWidth = 0;
282 pPattern = pNew;
283 pCondSet = pSet;
285 // pPattern auswerten
287 OutputDevice* pDev = pOutput->mpDev;
288 OutputDevice* pRefDevice = pOutput->mpRefDevice;
289 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
291 // Font
293 ScAutoFontColorMode eColorMode;
294 if ( pOutput->mbUseStyleColor )
296 if ( pOutput->mbForceAutoColor )
297 eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREALL : SC_AUTOCOL_IGNOREFONT;
298 else
299 eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREBACK : SC_AUTOCOL_DISPLAY;
301 else
302 eColorMode = SC_AUTOCOL_PRINT;
304 if ( bPixelToLogic )
305 pPattern->GetFont( aFont, eColorMode, pFmtDevice, NULL, pCondSet, nScript,
306 &aBackConfigColor, &aTextConfigColor );
307 else
308 pPattern->GetFont( aFont, eColorMode, pFmtDevice, &pOutput->aZoomY, pCondSet, nScript,
309 &aBackConfigColor, &aTextConfigColor );
310 aFont.SetAlign(ALIGN_BASELINE);
312 // Orientierung
314 eAttrOrient = pPattern->GetCellOrientation( pCondSet );
316 // alignment
318 eAttrHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue();
320 eAttrVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&)pPattern->GetItem( ATTR_VER_JUSTIFY, pCondSet )).GetValue();
321 if ( eAttrVerJust == SVX_VER_JUSTIFY_STANDARD )
322 eAttrVerJust = SVX_VER_JUSTIFY_BOTTOM;
324 // justification method
326 eAttrHorJustMethod = lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_HOR_JUSTIFY_METHOD, pCondSet);
327 eAttrVerJustMethod = lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_VER_JUSTIFY_METHOD, pCondSet);
329 // line break
331 bLineBreak = ((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK, pCondSet )).GetValue();
333 // handle "repeat" alignment
335 bRepeat = ( eAttrHorJust == SVX_HOR_JUSTIFY_REPEAT );
336 if ( bRepeat )
338 // "repeat" disables rotation (before constructing the font)
339 eAttrOrient = SVX_ORIENTATION_STANDARD;
341 // #i31843# "repeat" with "line breaks" is treated as default alignment (but rotation is still disabled)
342 if ( bLineBreak )
343 eAttrHorJust = SVX_HOR_JUSTIFY_STANDARD;
346 short nRot;
347 switch (eAttrOrient)
349 case SVX_ORIENTATION_STANDARD:
350 nRot = 0;
351 bRotated = (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE, pCondSet )).GetValue() != 0) &&
352 !bRepeat;
353 break;
354 case SVX_ORIENTATION_STACKED:
355 nRot = 0;
356 bRotated = false;
357 break;
358 case SVX_ORIENTATION_TOPBOTTOM:
359 nRot = 2700;
360 bRotated = false;
361 break;
362 case SVX_ORIENTATION_BOTTOMTOP:
363 nRot = 900;
364 bRotated = false;
365 break;
366 default:
367 OSL_FAIL("Falscher SvxCellOrientation Wert");
368 nRot = 0;
369 bRotated = false;
370 break;
372 aFont.SetOrientation( nRot );
374 // Syntax-Modus
376 if (pOutput->mbSyntaxMode)
377 pOutput->SetSyntaxColor( &aFont, pCell );
379 pDev->SetFont( aFont );
380 if ( pFmtDevice != pDev )
381 pFmtDevice->SetFont( aFont );
383 aMetric = pFmtDevice->GetFontMetric();
386 // Wenn auf dem Drucker das Leading 0 ist, gibt es Probleme
387 // -> Metric vom Bildschirm nehmen (wie EditEngine!)
390 if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 )
392 OutputDevice* pDefaultDev = Application::GetDefaultDevice();
393 MapMode aOld = pDefaultDev->GetMapMode();
394 pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
395 aMetric = pDefaultDev->GetFontMetric( aFont );
396 pDefaultDev->SetMapMode( aOld );
399 nAscentPixel = aMetric.GetAscent();
400 if ( bPixelToLogic )
401 nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
403 Color aULineColor( ((const SvxUnderlineItem&)pPattern->GetItem( ATTR_FONT_UNDERLINE, pCondSet )).GetColor() );
404 pDev->SetTextLineColor( aULineColor );
406 Color aOLineColor( ((const SvxOverlineItem&)pPattern->GetItem( ATTR_FONT_OVERLINE, pCondSet )).GetColor() );
407 pDev->SetOverlineColor( aOLineColor );
409 // Zahlenformat
411 nValueFormat = pPattern->GetNumberFormat( pOutput->mpDoc->GetFormatTable(), pCondSet );
413 // Raender
415 pMargin = (const SvxMarginItem*)&pPattern->GetItem( ATTR_MARGIN, pCondSet );
416 if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT )
417 nIndent = ((const SfxUInt16Item&)pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue();
418 else
419 nIndent = 0;
421 // "Shrink to fit"
423 bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
425 // zumindest die Text-Groesse muss neu geholt werden
426 //! unterscheiden, und den Text nicht neu vom Numberformatter holen?
428 pLastCell = NULL;
431 void ScDrawStringsVars::SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet )
433 nMaxDigitWidth = 0;
434 nSignWidth = 0;
435 nDotWidth = 0;
436 nExpWidth = 0;
437 // wird gerufen, wenn sich die Font-Variablen nicht aendern (!StringDiffer)
439 pPattern = pNew;
440 pCondSet = pSet; //! noetig ???
442 // Zahlenformat
444 sal_uLong nOld = nValueFormat;
445 const SfxPoolItem* pFormItem;
446 if ( !pCondSet || pCondSet->GetItemState(ATTR_VALUE_FORMAT,sal_True,&pFormItem) != SFX_ITEM_SET )
447 pFormItem = &pPattern->GetItem(ATTR_VALUE_FORMAT);
448 const SfxPoolItem* pLangItem;
449 if ( !pCondSet || pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT,sal_True,&pLangItem) != SFX_ITEM_SET )
450 pLangItem = &pPattern->GetItem(ATTR_LANGUAGE_FORMAT);
451 nValueFormat = pOutput->mpDoc->GetFormatTable()->GetFormatForLanguageIfBuiltIn(
452 ((SfxUInt32Item*)pFormItem)->GetValue(),
453 ((SvxLanguageItem*)pLangItem)->GetLanguage() );
455 if (nValueFormat != nOld)
456 pLastCell = NULL; // immer neu formatieren
458 // Raender
460 pMargin = (const SvxMarginItem*)&pPattern->GetItem( ATTR_MARGIN, pCondSet );
462 if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT )
463 nIndent = ((const SfxUInt16Item&)pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue();
464 else
465 nIndent = 0;
467 // "Shrink to fit"
469 bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
472 inline sal_Bool SameValue( ScBaseCell* pCell, ScBaseCell* pOldCell ) // pCell ist != 0
474 return pOldCell && pOldCell->GetCellType() == CELLTYPE_VALUE &&
475 pCell->GetCellType() == CELLTYPE_VALUE &&
476 ((ScValueCell*)pCell)->GetValue() == ((ScValueCell*)pOldCell)->GetValue();
479 sal_Bool ScDrawStringsVars::SetText( ScBaseCell* pCell )
481 sal_Bool bChanged = false;
483 if (pCell)
485 if ( !SameValue( pCell, pLastCell ) )
487 pLastCell = pCell; // Zelle merken
489 Color* pColor;
490 sal_uLong nFormat = GetValueFormat();
491 rtl::OUString aOUString = aString;
492 ScCellFormat::GetString( pCell,
493 nFormat, aOUString, &pColor,
494 *pOutput->mpDoc->GetFormatTable(),
495 pOutput->mbShowNullValues,
496 pOutput->mbShowFormulas,
497 ftCheck, true );
498 aString = aOUString;
499 if ( nFormat )
501 nPos = aString.Search( 0x1B );
502 if ( nPos != STRING_NOTFOUND )
504 nChar = aString.GetChar( nPos + 1 );
505 // delete placeholder and char to repeat
506 aString.Erase( nPos, 2 );
509 else
511 nPos = STRING_NOTFOUND;
512 nChar = 0x0;
514 if (aString.Len() > DRAWTEXT_MAX)
515 aString.Erase(DRAWTEXT_MAX);
517 if ( pColor && !pOutput->mbSyntaxMode && !( pOutput->mbUseStyleColor && pOutput->mbForceAutoColor ) )
519 OutputDevice* pDev = pOutput->mpDev;
520 aFont.SetColor(*pColor);
521 pDev->SetFont( aFont ); // nur fuer Ausgabe
522 bChanged = sal_True;
523 pLastCell = NULL; // naechstes Mal wieder hierherkommen
526 TextChanged();
528 // sonst String/Groesse behalten
530 else
532 aString.Erase();
533 pLastCell = NULL;
534 aTextSize = Size(0,0);
535 nOriginalWidth = 0;
538 return bChanged;
541 void ScDrawStringsVars::SetHashText()
543 SetAutoText(rtl::OUString("###"));
546 void ScDrawStringsVars::RepeatToFill( long colWidth )
548 if ( nPos == STRING_NOTFOUND || nPos > aString.Len() )
549 return;
551 long charWidth = pOutput->pFmtDevice->GetTextWidth(rtl::OUString(nChar));
552 if ( charWidth < 1) return;
553 if (bPixelToLogic)
554 colWidth = pOutput->mpRefDevice->PixelToLogic(Size(colWidth,0)).Width();
555 // Are there restrictions on the cell type we should filter out here ?
556 long aSpaceToFill = ( colWidth - aTextSize.Width() );
558 if ( aSpaceToFill <= charWidth )
559 return;
561 long nCharsToInsert = aSpaceToFill / charWidth;
562 OUStringBuffer aFill;
563 comphelper::string::padToLength(aFill, nCharsToInsert, nChar);
564 aString.Insert( aFill.makeStringAndClear(), nPos);
565 TextChanged();
568 void ScDrawStringsVars::SetTextToWidthOrHash( ScBaseCell* pCell, long nWidth )
570 // #i113045# do the single-character width calculations in logic units
571 if (bPixelToLogic)
572 nWidth = pOutput->mpRefDevice->PixelToLogic(Size(nWidth,0)).Width();
574 if (!pCell)
575 return;
577 CellType eType = pCell->GetCellType();
578 if (eType != CELLTYPE_VALUE && eType != CELLTYPE_FORMULA)
579 // must be a value or formula cell.
580 return;
582 if (eType == CELLTYPE_FORMULA)
584 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
585 if (pFCell->GetErrCode() != 0 || pOutput->mbShowFormulas)
587 SetHashText(); // If the error string doesn't fit, always use "###". Also for "display formulas" (#i116691#)
588 return;
590 // If it's formula, the result must be a value.
591 if (!pFCell->IsValue())
592 return;
594 if (pFCell->GetFormatType() != NUMBERFORMAT_NUMBER)
596 // Make sure the format type implicitly set by the interpreter is
597 // of pure numeric type. We don't want to adjust date and time
598 // values here.
599 SetHashText();
600 return;
604 sal_uLong nFormat = GetResultValueFormat(pCell);
605 if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
607 // Not 'General' number format. Set hash text and bail out.
608 SetHashText();
609 return;
612 double fVal = (eType == CELLTYPE_VALUE) ?
613 static_cast<ScValueCell*>(pCell)->GetValue() : static_cast<ScFormulaCell*>(pCell)->GetValue();
615 const SvNumberformat* pNumFormat = pOutput->mpDoc->GetFormatTable()->GetEntry(nFormat);
616 if (!pNumFormat)
617 return;
619 long nMaxDigit = GetMaxDigitWidth();
620 sal_uInt16 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
622 OUString sTempOut(aString);
623 if (!pNumFormat->GetOutputString(fVal, nNumDigits, sTempOut))
625 aString = sTempOut;
626 // Failed to get output string. Bail out.
627 return;
629 aString = sTempOut;
631 sal_uInt8 nSignCount = 0, nDecimalCount = 0, nExpCount = 0;
632 xub_StrLen nLen = aString.Len();
633 sal_Unicode cDecSep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator.getStr()[0];
634 for (xub_StrLen i = 0; i < nLen; ++i)
636 sal_Unicode c = aString.GetChar(i);
637 if (c == sal_Unicode('-'))
638 ++nSignCount;
639 else if (c == cDecSep)
640 ++nDecimalCount;
641 else if (c == sal_Unicode('E'))
642 ++nExpCount;
645 // #i112250# A small value might be formatted as "0" when only counting the digits,
646 // but fit into the column when considering the smaller width of the decimal separator.
647 if (aString.EqualsAscii("0") && fVal != 0.0)
648 nDecimalCount = 1;
650 if (nDecimalCount)
651 nWidth += (nMaxDigit - GetDotWidth()) * nDecimalCount;
652 if (nSignCount)
653 nWidth += (nMaxDigit - GetSignWidth()) * nSignCount;
654 if (nExpCount)
655 nWidth += (nMaxDigit - GetExpWidth()) * nExpCount;
657 if (nDecimalCount || nSignCount || nExpCount)
659 // Re-calculate.
660 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
661 OUString sTempOut(aString);
662 if (!pNumFormat->GetOutputString(fVal, nNumDigits, sTempOut))
664 aString = sTempOut;
665 // Failed to get output string. Bail out.
666 return;
668 aString = sTempOut;
671 long nActualTextWidth = pOutput->pFmtDevice->GetTextWidth(aString);
672 if (nActualTextWidth > nWidth)
674 // Even after the decimal adjustment the text doesn't fit. Give up.
675 SetHashText();
676 return;
679 TextChanged();
680 pLastCell = NULL; // #i113022# equal cell and format in another column may give different string
683 void ScDrawStringsVars::SetAutoText( const String& rAutoText )
685 aString = rAutoText;
687 OutputDevice* pRefDevice = pOutput->mpRefDevice;
688 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
689 aTextSize.Width() = pFmtDevice->GetTextWidth( aString );
690 aTextSize.Height() = pFmtDevice->GetTextHeight();
692 if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
694 double fMul = pOutput->GetStretch();
695 aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5);
698 aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent();
699 if ( GetOrient() != SVX_ORIENTATION_STANDARD )
701 long nTemp = aTextSize.Height();
702 aTextSize.Height() = aTextSize.Width();
703 aTextSize.Width() = nTemp;
706 nOriginalWidth = aTextSize.Width();
707 if ( bPixelToLogic )
708 aTextSize = pRefDevice->LogicToPixel( aTextSize );
710 pLastCell = NULL; // derselbe Text kann in der naechsten Zelle wieder passen
713 long ScDrawStringsVars::GetMaxDigitWidth()
715 if (nMaxDigitWidth > 0)
716 return nMaxDigitWidth;
718 sal_Char cZero = '0';
719 for (sal_Char i = 0; i < 10; ++i)
721 sal_Char cDigit = cZero + i;
722 long n = pOutput->pFmtDevice->GetTextWidth(rtl::OUString(cDigit));
723 nMaxDigitWidth = ::std::max(nMaxDigitWidth, n);
725 return nMaxDigitWidth;
728 long ScDrawStringsVars::GetSignWidth()
730 if (nSignWidth > 0)
731 return nSignWidth;
733 nSignWidth = pOutput->pFmtDevice->GetTextWidth(rtl::OUString('-'));
734 return nSignWidth;
737 long ScDrawStringsVars::GetDotWidth()
739 if (nDotWidth > 0)
740 return nDotWidth;
742 const ::rtl::OUString& sep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator;
743 nDotWidth = pOutput->pFmtDevice->GetTextWidth(sep);
744 return nDotWidth;
747 long ScDrawStringsVars::GetExpWidth()
749 if (nExpWidth > 0)
750 return nExpWidth;
752 nExpWidth = pOutput->pFmtDevice->GetTextWidth(rtl::OUString('E'));
753 return nExpWidth;
756 void ScDrawStringsVars::TextChanged()
758 OutputDevice* pRefDevice = pOutput->mpRefDevice;
759 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
760 aTextSize.Width() = pFmtDevice->GetTextWidth( aString );
761 aTextSize.Height() = pFmtDevice->GetTextHeight();
763 if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
765 double fMul = pOutput->GetStretch();
766 aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5);
769 aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent();
770 if ( GetOrient() != SVX_ORIENTATION_STANDARD )
772 long nTemp = aTextSize.Height();
773 aTextSize.Height() = aTextSize.Width();
774 aTextSize.Width() = nTemp;
777 nOriginalWidth = aTextSize.Width();
778 if ( bPixelToLogic )
779 aTextSize = pRefDevice->LogicToPixel( aTextSize );
782 sal_Bool ScDrawStringsVars::HasEditCharacters() const
784 static const sal_Unicode pChars[] =
786 CHAR_NBSP, CHAR_SHY, CHAR_ZWSP, CHAR_LRM, CHAR_RLM, CHAR_NBHY, CHAR_ZWNBSP, 0
788 return aString.SearchChar( pChars ) != STRING_NOTFOUND;
791 sal_uLong ScDrawStringsVars::GetResultValueFormat( const ScBaseCell* pCell ) const
793 // Get the effective number format, including formula result types.
794 // This assumes that a formula cell has already been calculated.
796 if ( (nValueFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
797 return static_cast<const ScFormulaCell*>(pCell)->GetStandardFormat(*pOutput->mpDoc->GetFormatTable(), nValueFormat);
798 else
799 return nValueFormat;
802 //==================================================================
804 double ScOutputData::GetStretch()
806 if ( mpRefDevice->IsMapMode() )
808 // If a non-trivial MapMode is set, its scale is now already
809 // taken into account in the OutputDevice's font handling
810 // (OutputDevice::ImplNewFont, see #95414#).
811 // The old handling below is only needed for pixel output.
812 return 1.0;
815 // calculation in double is faster than Fraction multiplication
816 // and doesn't overflow
818 if ( mpRefDevice == pFmtDevice )
820 MapMode aOld = mpRefDevice->GetMapMode();
821 return ((double)aOld.GetScaleY()) / ((double)aOld.GetScaleX()) * ((double)aZoomY) / ((double)aZoomX);
823 else
825 // when formatting for printer, device map mode has already been taken care of
826 return ((double)aZoomY) / ((double)aZoomX);
830 //==================================================================
833 // output strings
836 static void lcl_DoHyperlinkResult( OutputDevice* pDev, const Rectangle& rRect, ScBaseCell* pCell )
838 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
840 rtl::OUString aCellText;
841 rtl::OUString aURL;
842 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
844 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
845 if ( pFCell->IsHyperLinkCell() )
846 pFCell->GetURLResult( aURL, aCellText );
849 if ( !aURL.isEmpty() && pPDFData )
851 vcl::PDFExtOutDevBookmarkEntry aBookmark;
852 aBookmark.nLinkId = pPDFData->CreateLink( rRect );
853 aBookmark.aBookmark = aURL;
854 std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFData->GetBookmarks();
855 rBookmarks.push_back( aBookmark );
859 void ScOutputData::SetSyntaxColor( Font* pFont, ScBaseCell* pCell )
861 if (pCell)
863 switch (pCell->GetCellType())
865 case CELLTYPE_VALUE:
866 pFont->SetColor( *pValueColor );
867 break;
868 case CELLTYPE_STRING:
869 pFont->SetColor( *pTextColor );
870 break;
871 case CELLTYPE_FORMULA:
872 pFont->SetColor( *pFormulaColor );
873 break;
874 default:
876 // added to avoid warnings
882 static void lcl_SetEditColor( EditEngine& rEngine, const Color& rColor )
884 ESelection aSel( 0, 0, rEngine.GetParagraphCount(), 0 );
885 SfxItemSet aSet( rEngine.GetEmptyItemSet() );
886 aSet.Put( SvxColorItem( rColor, EE_CHAR_COLOR ) );
887 rEngine.QuickSetAttribs( aSet, aSel );
888 // function is called with update mode set to FALSE
891 void ScOutputData::SetEditSyntaxColor( EditEngine& rEngine, ScBaseCell* pCell )
893 if (pCell)
895 Color aColor;
896 switch (pCell->GetCellType())
898 case CELLTYPE_VALUE:
899 aColor = *pValueColor;
900 break;
901 case CELLTYPE_STRING:
902 aColor = *pTextColor;
903 break;
904 case CELLTYPE_FORMULA:
905 aColor = *pFormulaColor;
906 break;
907 default:
909 // added to avoid warnings
912 lcl_SetEditColor( rEngine, aColor );
916 sal_Bool ScOutputData::GetMergeOrigin( SCCOL nX, SCROW nY, SCSIZE nArrY,
917 SCCOL& rOverX, SCROW& rOverY,
918 sal_Bool bVisRowChanged )
920 sal_Bool bDoMerge = false;
921 sal_Bool bIsLeft = ( nX == nVisX1 );
922 sal_Bool bIsTop = ( nY == nVisY1 ) || bVisRowChanged;
924 CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nX+1];
925 if ( pInfo->bHOverlapped && pInfo->bVOverlapped )
926 bDoMerge = bIsLeft && bIsTop;
927 else if ( pInfo->bHOverlapped )
928 bDoMerge = bIsLeft;
929 else if ( pInfo->bVOverlapped )
930 bDoMerge = bIsTop;
932 rOverX = nX;
933 rOverY = nY;
934 sal_Bool bHOver = pInfo->bHOverlapped;
935 sal_Bool bVOver = pInfo->bVOverlapped;
936 sal_Bool bHidden;
938 while (bHOver) // nY konstant
940 --rOverX;
941 bHidden = mpDoc->ColHidden(rOverX, nTab);
942 if ( !bDoMerge && !bHidden )
943 return false;
945 if (rOverX >= nX1 && !bHidden)
947 bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped;
948 bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped;
950 else
952 sal_uInt16 nOverlap = ((ScMergeFlagAttr*)mpDoc->GetAttr(
953 rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue();
954 bHOver = ((nOverlap & SC_MF_HOR) != 0);
955 bVOver = ((nOverlap & SC_MF_VER) != 0);
959 while (bVOver)
961 --rOverY;
962 bHidden = mpDoc->RowHidden(rOverY, nTab);
963 if ( !bDoMerge && !bHidden )
964 return false;
966 if (nArrY>0)
967 --nArrY; // lokale Kopie !
969 if (rOverX >= nX1 && rOverY >= nY1 &&
970 !mpDoc->ColHidden(rOverX, nTab) &&
971 !mpDoc->RowHidden(rOverY, nTab) &&
972 pRowInfo[nArrY].nRowNo == rOverY)
974 bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped;
975 bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped;
977 else
979 sal_uInt16 nOverlap = ((ScMergeFlagAttr*)mpDoc->GetAttr(
980 rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue();
981 bHOver = ((nOverlap & SC_MF_HOR) != 0);
982 bVOver = ((nOverlap & SC_MF_VER) != 0);
986 return sal_True;
989 inline sal_Bool StringDiffer( const ScPatternAttr*& rpOldPattern, const ScPatternAttr*& rpNewPattern )
991 OSL_ENSURE( rpNewPattern, "pNewPattern" );
993 if ( rpNewPattern == rpOldPattern )
994 return false;
995 else if ( !rpOldPattern )
996 return sal_True;
997 else if ( &rpNewPattern->GetItem( ATTR_FONT ) != &rpOldPattern->GetItem( ATTR_FONT ) )
998 return sal_True;
999 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT ) )
1000 return sal_True;
1001 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT ) )
1002 return sal_True;
1003 else if ( &rpNewPattern->GetItem( ATTR_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_HEIGHT ) )
1004 return sal_True;
1005 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) )
1006 return sal_True;
1007 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) )
1008 return sal_True;
1009 else if ( &rpNewPattern->GetItem( ATTR_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_WEIGHT ) )
1010 return sal_True;
1011 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) )
1012 return sal_True;
1013 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) )
1014 return sal_True;
1015 else if ( &rpNewPattern->GetItem( ATTR_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_FONT_POSTURE ) )
1016 return sal_True;
1017 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_POSTURE ) )
1018 return sal_True;
1019 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_POSTURE ) )
1020 return sal_True;
1021 else if ( &rpNewPattern->GetItem( ATTR_FONT_UNDERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_UNDERLINE ) )
1022 return sal_True;
1023 else if ( &rpNewPattern->GetItem( ATTR_FONT_OVERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_OVERLINE ) )
1024 return sal_True;
1025 else if ( &rpNewPattern->GetItem( ATTR_FONT_WORDLINE ) != &rpOldPattern->GetItem( ATTR_FONT_WORDLINE ) )
1026 return sal_True;
1027 else if ( &rpNewPattern->GetItem( ATTR_FONT_CROSSEDOUT ) != &rpOldPattern->GetItem( ATTR_FONT_CROSSEDOUT ) )
1028 return sal_True;
1029 else if ( &rpNewPattern->GetItem( ATTR_FONT_CONTOUR ) != &rpOldPattern->GetItem( ATTR_FONT_CONTOUR ) )
1030 return sal_True;
1031 else if ( &rpNewPattern->GetItem( ATTR_FONT_SHADOWED ) != &rpOldPattern->GetItem( ATTR_FONT_SHADOWED ) )
1032 return sal_True;
1033 else if ( &rpNewPattern->GetItem( ATTR_FONT_COLOR ) != &rpOldPattern->GetItem( ATTR_FONT_COLOR ) )
1034 return sal_True;
1035 else if ( &rpNewPattern->GetItem( ATTR_HOR_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY ) )
1036 return true;
1037 else if ( &rpNewPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) )
1038 return true;
1039 else if ( &rpNewPattern->GetItem( ATTR_VER_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY ) )
1040 return true;
1041 else if ( &rpNewPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) )
1042 return true;
1043 else if ( &rpNewPattern->GetItem( ATTR_STACKED ) != &rpOldPattern->GetItem( ATTR_STACKED ) )
1044 return sal_True;
1045 else if ( &rpNewPattern->GetItem( ATTR_LINEBREAK ) != &rpOldPattern->GetItem( ATTR_LINEBREAK ) )
1046 return sal_True;
1047 else if ( &rpNewPattern->GetItem( ATTR_MARGIN ) != &rpOldPattern->GetItem( ATTR_MARGIN ) )
1048 return sal_True;
1049 else if ( &rpNewPattern->GetItem( ATTR_ROTATE_VALUE ) != &rpOldPattern->GetItem( ATTR_ROTATE_VALUE ) )
1050 return sal_True;
1051 else if ( &rpNewPattern->GetItem( ATTR_FORBIDDEN_RULES ) != &rpOldPattern->GetItem( ATTR_FORBIDDEN_RULES ) )
1052 return sal_True;
1053 else if ( &rpNewPattern->GetItem( ATTR_FONT_EMPHASISMARK ) != &rpOldPattern->GetItem( ATTR_FONT_EMPHASISMARK ) )
1054 return sal_True;
1055 else if ( &rpNewPattern->GetItem( ATTR_FONT_RELIEF ) != &rpOldPattern->GetItem( ATTR_FONT_RELIEF ) )
1056 return sal_True;
1057 else if ( &rpNewPattern->GetItem( ATTR_BACKGROUND ) != &rpOldPattern->GetItem( ATTR_BACKGROUND ) )
1058 return sal_True; // needed with automatic text color
1059 else
1061 rpOldPattern = rpNewPattern;
1062 return false;
1066 static inline void lcl_CreateInterpretProgress( sal_Bool& bProgress, ScDocument* pDoc,
1067 ScFormulaCell* pFCell )
1069 if ( !bProgress && pFCell->GetDirty() )
1071 ScProgress::CreateInterpretProgress( pDoc, sal_True );
1072 bProgress = sal_True;
1076 inline sal_uInt8 GetScriptType( ScDocument* pDoc, ScBaseCell* pCell,
1077 const ScPatternAttr* pPattern,
1078 const SfxItemSet* pCondSet )
1080 return pDoc->GetCellScriptType( pCell, pPattern->GetNumberFormat( pDoc->GetFormatTable(), pCondSet ) );
1083 inline sal_Bool IsAmbiguousScript( sal_uInt8 nScript )
1085 return ( nScript != SCRIPTTYPE_LATIN &&
1086 nScript != SCRIPTTYPE_ASIAN &&
1087 nScript != SCRIPTTYPE_COMPLEX );
1090 sal_Bool ScOutputData::IsEmptyCellText( RowInfo* pThisRowInfo, SCCOL nX, SCROW nY )
1092 // pThisRowInfo may be NULL
1094 sal_Bool bEmpty;
1095 if ( pThisRowInfo && nX <= nX2 )
1096 bEmpty = pThisRowInfo->pCellInfo[nX+1].bEmptyCellText;
1097 else
1098 bEmpty = ( mpDoc->GetCell( ScAddress( nX, nY, nTab ) ) == NULL );
1100 if ( !bEmpty && ( nX < nX1 || nX > nX2 || !pThisRowInfo ) )
1102 // for the range nX1..nX2 in RowInfo, cell protection attribute is already evaluated
1103 // into bEmptyCellText in ScDocument::FillInfo / lcl_HidePrint (printfun)
1105 sal_Bool bIsPrint = ( eType == OUTTYPE_PRINTER );
1107 if ( bIsPrint || bTabProtected )
1109 const ScProtectionAttr* pAttr = (const ScProtectionAttr*)
1110 mpDoc->GetEffItem( nX, nY, nTab, ATTR_PROTECTION );
1111 if ( bIsPrint && pAttr->GetHidePrint() )
1112 bEmpty = sal_True;
1113 else if ( bTabProtected )
1115 if ( pAttr->GetHideCell() )
1116 bEmpty = sal_True;
1117 else if ( mbShowFormulas && pAttr->GetHideFormula() )
1119 ScBaseCell* pCell = mpDoc->GetCell( ScAddress( nX, nY, nTab ) );
1120 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
1121 bEmpty = sal_True;
1126 return bEmpty;
1129 void ScOutputData::GetVisibleCell( SCCOL nCol, SCROW nRow, SCTAB nTabP, ScBaseCell*& rpCell )
1131 mpDoc->GetCell( nCol, nRow, nTabP, rpCell );
1132 if ( rpCell && IsEmptyCellText( NULL, nCol, nRow ) )
1133 rpCell = NULL;
1136 sal_Bool ScOutputData::IsAvailable( SCCOL nX, SCROW nY )
1138 // apply the same logic here as in DrawStrings/DrawEdit:
1139 // Stop at non-empty or merged or overlapped cell,
1140 // where a note is empty as well as a cell that's hidden by protection settings
1142 const ScBaseCell* pCell = mpDoc->GetCell( ScAddress( nX, nY, nTab ) );
1143 if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE && !IsEmptyCellText( NULL, nX, nY ) )
1145 return false;
1148 const ScPatternAttr* pPattern = mpDoc->GetPattern( nX, nY, nTab );
1149 if ( ((const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE)).IsMerged() ||
1150 ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).IsOverlapped() )
1152 return false;
1155 return sal_True;
1158 // nX, nArrY: loop variables from DrawStrings / DrawEdit
1159 // nPosX, nPosY: corresponding positions for nX, nArrY
1160 // nCellX, nCellY: position of the cell that contains the text
1161 // nNeeded: Text width, including margin
1162 // rPattern: cell format at nCellX, nCellY
1163 // nHorJustify: horizontal alignment (visual) to determine which cells to use for long strings
1164 // bCellIsValue: if set, don't extend into empty cells
1165 // bBreak: if set, don't extend, and don't set clip marks (but rLeftClip/rRightClip is set)
1166 // bOverwrite: if set, also extend into non-empty cells (for rotated text)
1167 // rParam output: various area parameters.
1169 void ScOutputData::GetOutputArea( SCCOL nX, SCSIZE nArrY, long nPosX, long nPosY,
1170 SCCOL nCellX, SCROW nCellY, long nNeeded,
1171 const ScPatternAttr& rPattern,
1172 sal_uInt16 nHorJustify, bool bCellIsValue,
1173 bool bBreak, bool bOverwrite,
1174 OutputAreaParam& rParam )
1176 // rThisRowInfo may be for a different row than nCellY, is still used for clip marks
1177 RowInfo& rThisRowInfo = pRowInfo[nArrY];
1179 long nLayoutSign = bLayoutRTL ? -1 : 1;
1181 long nCellPosX = nPosX; // find nCellX position, starting at nX/nPosX
1182 SCCOL nCompCol = nX;
1183 while ( nCellX > nCompCol )
1185 //! extra member function for width?
1186 long nColWidth = ( nCompCol <= nX2 ) ?
1187 pRowInfo[0].pCellInfo[nCompCol+1].nWidth :
1188 (long) ( mpDoc->GetColWidth( nCompCol, nTab ) * mnPPTX );
1189 nCellPosX += nColWidth * nLayoutSign;
1190 ++nCompCol;
1192 while ( nCellX < nCompCol )
1194 --nCompCol;
1195 long nColWidth = ( nCompCol <= nX2 ) ?
1196 pRowInfo[0].pCellInfo[nCompCol+1].nWidth :
1197 (long) ( mpDoc->GetColWidth( nCompCol, nTab ) * mnPPTX );
1198 nCellPosX -= nColWidth * nLayoutSign;
1201 long nCellPosY = nPosY; // find nCellY position, starting at nArrY/nPosY
1202 SCSIZE nCompArr = nArrY;
1203 SCROW nCompRow = pRowInfo[nCompArr].nRowNo;
1204 while ( nCellY > nCompRow )
1206 if ( nCompArr + 1 < nArrCount )
1208 nCellPosY += pRowInfo[nCompArr].nHeight;
1209 ++nCompArr;
1210 nCompRow = pRowInfo[nCompArr].nRowNo;
1212 else
1214 sal_uInt16 nDocHeight = mpDoc->GetRowHeight( nCompRow, nTab );
1215 if ( nDocHeight )
1216 nCellPosY += (long) ( nDocHeight * mnPPTY );
1217 ++nCompRow;
1220 nCellPosY -= (long) mpDoc->GetScaledRowHeight( nCellY, nCompRow-1, nTab, mnPPTY );
1222 const ScMergeAttr* pMerge = (const ScMergeAttr*)&rPattern.GetItem( ATTR_MERGE );
1223 sal_Bool bMerged = pMerge->IsMerged();
1224 long nMergeCols = pMerge->GetColMerge();
1225 if ( nMergeCols == 0 )
1226 nMergeCols = 1;
1227 long nMergeRows = pMerge->GetRowMerge();
1228 if ( nMergeRows == 0 )
1229 nMergeRows = 1;
1231 long i;
1232 long nMergeSizeX = 0;
1233 for ( i=0; i<nMergeCols; i++ )
1235 long nColWidth = ( nCellX+i <= nX2 ) ?
1236 pRowInfo[0].pCellInfo[nCellX+i+1].nWidth :
1237 (long) ( mpDoc->GetColWidth( sal::static_int_cast<SCCOL>(nCellX+i), nTab ) * mnPPTX );
1238 nMergeSizeX += nColWidth;
1240 long nMergeSizeY = 0;
1241 short nDirect = 0;
1242 if ( rThisRowInfo.nRowNo == nCellY )
1244 // take first row's height from row info
1245 nMergeSizeY += rThisRowInfo.nHeight;
1246 nDirect = 1; // skip in loop
1248 // following rows always from document
1249 nMergeSizeY += (long) mpDoc->GetScaledRowHeight( nCellY+nDirect, nCellY+nMergeRows-1, nTab, mnPPTY);
1251 --nMergeSizeX; // leave out the grid horizontally, also for alignment (align between grid lines)
1253 rParam.mnColWidth = nMergeSizeX; // store the actual column width.
1256 // construct the rectangles using logical left/right values (justify is called at the end)
1259 // rAlignRect is the single cell or merged area, used for alignment.
1261 rParam.maAlignRect.Left() = nCellPosX;
1262 rParam.maAlignRect.Right() = nCellPosX + ( nMergeSizeX - 1 ) * nLayoutSign;
1263 rParam.maAlignRect.Top() = nCellPosY;
1264 rParam.maAlignRect.Bottom() = nCellPosY + nMergeSizeY - 1;
1266 // rClipRect is all cells that are used for output.
1267 // For merged cells this is the same as rAlignRect, otherwise neighboring cells can also be used.
1269 rParam.maClipRect = rParam.maAlignRect;
1270 if ( nNeeded > nMergeSizeX )
1272 SvxCellHorJustify eHorJust = (SvxCellHorJustify)nHorJustify;
1274 long nMissing = nNeeded - nMergeSizeX;
1275 long nLeftMissing = 0;
1276 long nRightMissing = 0;
1277 switch ( eHorJust )
1279 case SVX_HOR_JUSTIFY_LEFT:
1280 nRightMissing = nMissing;
1281 break;
1282 case SVX_HOR_JUSTIFY_RIGHT:
1283 nLeftMissing = nMissing;
1284 break;
1285 case SVX_HOR_JUSTIFY_CENTER:
1286 nLeftMissing = nMissing / 2;
1287 nRightMissing = nMissing - nLeftMissing;
1288 break;
1289 default:
1291 // added to avoid warnings
1295 // nLeftMissing, nRightMissing are logical, eHorJust values are visual
1296 if ( bLayoutRTL )
1297 ::std::swap( nLeftMissing, nRightMissing );
1299 SCCOL nRightX = nCellX;
1300 SCCOL nLeftX = nCellX;
1301 if ( !bMerged && !bCellIsValue && !bBreak )
1303 // look for empty cells into which the text can be extended
1305 while ( nRightMissing > 0 && nRightX < MAXCOL && ( bOverwrite || IsAvailable( nRightX+1, nCellY ) ) )
1307 ++nRightX;
1308 long nAdd = (long) ( mpDoc->GetColWidth( nRightX, nTab ) * mnPPTX );
1309 nRightMissing -= nAdd;
1310 rParam.maClipRect.Right() += nAdd * nLayoutSign;
1312 if ( rThisRowInfo.nRowNo == nCellY && nRightX >= nX1 && nRightX <= nX2 )
1313 rThisRowInfo.pCellInfo[nRightX].bHideGrid = sal_True;
1316 while ( nLeftMissing > 0 && nLeftX > 0 && ( bOverwrite || IsAvailable( nLeftX-1, nCellY ) ) )
1318 if ( rThisRowInfo.nRowNo == nCellY && nLeftX >= nX1 && nLeftX <= nX2 )
1319 rThisRowInfo.pCellInfo[nLeftX].bHideGrid = sal_True;
1321 --nLeftX;
1322 long nAdd = (long) ( mpDoc->GetColWidth( nLeftX, nTab ) * mnPPTX );
1323 nLeftMissing -= nAdd;
1324 rParam.maClipRect.Left() -= nAdd * nLayoutSign;
1328 // Set flag and reserve space for clipping mark triangle,
1329 // even if rThisRowInfo isn't for nCellY (merged cells).
1330 if ( nRightMissing > 0 && bMarkClipped && nRightX >= nX1 && nRightX <= nX2 && !bBreak && !bCellIsValue )
1332 rThisRowInfo.pCellInfo[nRightX+1].nClipMark |= SC_CLIPMARK_RIGHT;
1333 bAnyClipped = sal_True;
1334 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
1335 rParam.maClipRect.Right() -= nMarkPixel * nLayoutSign;
1337 if ( nLeftMissing > 0 && bMarkClipped && nLeftX >= nX1 && nLeftX <= nX2 && !bBreak && !bCellIsValue )
1339 rThisRowInfo.pCellInfo[nLeftX+1].nClipMark |= SC_CLIPMARK_LEFT;
1340 bAnyClipped = sal_True;
1341 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
1342 rParam.maClipRect.Left() += nMarkPixel * nLayoutSign;
1345 rParam.mbLeftClip = ( nLeftMissing > 0 );
1346 rParam.mbRightClip = ( nRightMissing > 0 );
1348 else
1350 rParam.mbLeftClip = rParam.mbRightClip = false;
1352 // leave space for AutoFilter on screen
1353 // (for automatic line break: only if not formatting for printer, as in ScColumn::GetNeededSize)
1355 if ( eType==OUTTYPE_WINDOW &&
1356 ( static_cast<const ScMergeFlagAttr&>(rPattern.GetItem(ATTR_MERGE_FLAG)).GetValue() & SC_MF_AUTO ) &&
1357 ( !bBreak || mpRefDevice == pFmtDevice ) )
1359 // filter drop-down width is now independent from row height
1360 const long nFilter = DROPDOWN_BITMAP_SIZE;
1361 sal_Bool bFit = ( nNeeded + nFilter <= nMergeSizeX );
1362 if ( bFit || bCellIsValue )
1364 // content fits even in the remaining area without the filter button
1365 // -> align within that remaining area
1367 rParam.maAlignRect.Right() -= nFilter * nLayoutSign;
1368 rParam.maClipRect.Right() -= nFilter * nLayoutSign;
1370 // if a number doesn't fit, don't hide part of the number behind the button
1371 // -> set clip flags, so "###" replacement is used (but also within the smaller area)
1373 if ( !bFit )
1374 rParam.mbLeftClip = rParam.mbRightClip = sal_True;
1379 // justify both rectangles for alignment calculation, use with DrawText etc.
1381 rParam.maAlignRect.Justify();
1382 rParam.maClipRect.Justify();
1385 namespace {
1387 bool beginsWithRTLCharacter(const rtl::OUString& rStr)
1389 if (rStr.isEmpty())
1390 return false;
1392 switch (ScGlobal::pCharClass->getCharacterDirection(rStr, 0))
1394 case i18n::DirectionProperty_RIGHT_TO_LEFT:
1395 case i18n::DirectionProperty_RIGHT_TO_LEFT_ARABIC:
1396 case i18n::DirectionProperty_RIGHT_TO_LEFT_EMBEDDING:
1397 case i18n::DirectionProperty_RIGHT_TO_LEFT_OVERRIDE:
1398 return true;
1399 default:
1403 return false;
1408 void ScOutputData::DrawStrings( sal_Bool bPixelToLogic )
1410 OSL_ENSURE( mpDev == mpRefDevice ||
1411 mpDev->GetMapMode().GetMapUnit() == mpRefDevice->GetMapMode().GetMapUnit(),
1412 "DrawStrings: unterschiedliche MapUnits ?!?!" );
1414 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, mpDev->GetExtOutDevData() );
1416 sal_Bool bWasIdleDisabled = mpDoc->IsIdleDisabled();
1417 mpDoc->DisableIdle( true );
1419 ScDrawStringsVars aVars( this, bPixelToLogic );
1421 sal_Bool bProgress = false;
1423 long nInitPosX = nScrX;
1424 if ( bLayoutRTL )
1425 nInitPosX += nMirrorW - 1; // pixels
1426 long nLayoutSign = bLayoutRTL ? -1 : 1;
1428 SCCOL nLastContentCol = MAXCOL;
1429 if ( nX2 < MAXCOL )
1430 nLastContentCol = sal::static_int_cast<SCCOL>(
1431 nLastContentCol - mpDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) );
1432 SCCOL nLoopStartX = nX1;
1433 if ( nX1 > 0 )
1434 --nLoopStartX; // start before nX1 for rest of long text to the left
1436 // variables for GetOutputArea
1437 OutputAreaParam aAreaParam;
1438 sal_Bool bCellIsValue = false;
1439 long nNeededWidth = 0;
1440 SvxCellHorJustify eOutHorJust = SVX_HOR_JUSTIFY_STANDARD;
1441 const ScPatternAttr* pPattern = NULL;
1442 const SfxItemSet* pCondSet = NULL;
1443 const ScPatternAttr* pOldPattern = NULL;
1444 const SfxItemSet* pOldCondSet = NULL;
1445 sal_uInt8 nOldScript = 0;
1447 // alternative pattern instances in case we need to modify the pattern
1448 // before processing the cell value.
1449 ::boost::ptr_vector<ScPatternAttr> aAltPatterns;
1451 long nPosY = nScrY;
1452 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1454 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1455 if ( pThisRowInfo->bChanged )
1457 SCROW nY = pThisRowInfo->nRowNo;
1458 long nPosX = nInitPosX;
1459 if ( nLoopStartX < nX1 )
1460 nPosX -= pRowInfo[0].pCellInfo[nLoopStartX+1].nWidth * nLayoutSign;
1461 for (SCCOL nX=nLoopStartX; nX<=nX2; nX++)
1463 sal_Bool bMergeEmpty = false;
1464 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
1465 sal_Bool bEmpty = nX < nX1 || pInfo->bEmptyCellText;
1467 SCCOL nCellX = nX; // position where the cell really starts
1468 SCROW nCellY = nY;
1469 sal_Bool bDoCell = false;
1470 sal_Bool bNeedEdit = false;
1473 // Part of a merged cell?
1476 sal_Bool bOverlapped = ( pInfo->bHOverlapped || pInfo->bVOverlapped );
1477 if ( bOverlapped )
1479 bEmpty = sal_True;
1481 SCCOL nOverX; // start of the merged cells
1482 SCROW nOverY;
1483 sal_Bool bVisChanged = !pRowInfo[nArrY-1].bChanged;
1484 if (GetMergeOrigin( nX,nY, nArrY, nOverX,nOverY, bVisChanged ))
1486 nCellX = nOverX;
1487 nCellY = nOverY;
1488 bDoCell = sal_True;
1490 else
1491 bMergeEmpty = sal_True;
1495 // Rest of a long text further to the left?
1498 if ( bEmpty && !bMergeEmpty && nX < nX1 && !bOverlapped )
1500 SCCOL nTempX=nX1;
1501 while (nTempX > 0 && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
1502 --nTempX;
1504 if ( nTempX < nX1 &&
1505 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
1506 !mpDoc->HasAttrib( nTempX,nY,nTab, nX1,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
1508 nCellX = nTempX;
1509 bDoCell = sal_True;
1514 // Rest of a long text further to the right?
1517 if ( bEmpty && !bMergeEmpty && nX == nX2 && !bOverlapped )
1519 // don't have to look further than nLastContentCol
1521 SCCOL nTempX=nX;
1522 while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
1523 ++nTempX;
1525 if ( nTempX > nX &&
1526 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
1527 !mpDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
1529 nCellX = nTempX;
1530 bDoCell = sal_True;
1535 // normal visible cell
1538 if (!bEmpty)
1539 bDoCell = sal_True;
1542 // don't output the cell that's being edited
1545 if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
1546 bDoCell = false;
1548 // skip text in cell if data bar is set and only value selected
1549 if ( bDoCell )
1551 if(pInfo->pDataBar && !pInfo->pDataBar->mbShowValue)
1552 bDoCell = false;
1556 // output the cell text
1559 ScBaseCell* pCell = NULL;
1560 if (bDoCell)
1562 if ( nCellY == nY && nCellX == nX && nCellX >= nX1 && nCellX <= nX2 )
1563 pCell = pThisRowInfo->pCellInfo[nCellX+1].pCell;
1564 else
1565 GetVisibleCell( nCellX, nCellY, nTab, pCell ); // get from document
1566 if ( !pCell )
1567 bDoCell = false;
1568 else if ( pCell->GetCellType() == CELLTYPE_EDIT )
1569 bNeedEdit = sal_True;
1571 if (bDoCell && !bNeedEdit)
1573 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 )
1575 CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1];
1576 pPattern = rCellInfo.pPatternAttr;
1577 pCondSet = rCellInfo.pConditionSet;
1579 if ( !pPattern )
1581 // #i68085# pattern from cell info for hidden columns is null,
1582 // test for null is quicker than using column flags
1583 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
1584 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
1587 else // get from document
1589 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
1590 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
1593 if (pCell->HasValueData() &&
1594 static_cast<const SfxBoolItem&>(
1595 pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue())
1597 // Disable line break when the cell content is numeric.
1598 aAltPatterns.push_back(new ScPatternAttr(*pPattern));
1599 ScPatternAttr* pAltPattern = &aAltPatterns.back();
1600 SfxBoolItem aLineBreak(ATTR_LINEBREAK, false);
1601 pAltPattern->GetItemSet().Put(aLineBreak);
1602 pPattern = pAltPattern;
1605 sal_uInt8 nScript = GetScriptType( mpDoc, pCell, pPattern, pCondSet );
1606 if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
1607 if ( pPattern != pOldPattern || pCondSet != pOldCondSet ||
1608 nScript != nOldScript || mbSyntaxMode )
1610 if ( StringDiffer(pOldPattern,pPattern) ||
1611 pCondSet != pOldCondSet || nScript != nOldScript || mbSyntaxMode )
1612 aVars.SetPattern( pPattern, pCondSet, pCell, nScript );
1613 else
1614 aVars.SetPatternSimple( pPattern, pCondSet );
1615 pOldPattern = pPattern;
1616 pOldCondSet = pCondSet;
1617 nOldScript = nScript;
1620 // use edit engine for rotated, stacked or mixed-script text
1621 if ( aVars.GetOrient() == SVX_ORIENTATION_STACKED ||
1622 aVars.IsRotated() || IsAmbiguousScript(nScript) )
1623 bNeedEdit = sal_True;
1625 if (bDoCell && !bNeedEdit)
1627 sal_Bool bFormulaCell = (pCell->GetCellType() == CELLTYPE_FORMULA );
1628 if ( bFormulaCell )
1629 lcl_CreateInterpretProgress( bProgress, mpDoc, (ScFormulaCell*)pCell );
1630 if ( aVars.SetText(pCell) )
1631 pOldPattern = NULL;
1632 bNeedEdit = aVars.HasEditCharacters() ||
1633 (bFormulaCell && ((ScFormulaCell*)pCell)->IsMultilineResult());
1635 long nTotalMargin = 0;
1636 if (bDoCell && !bNeedEdit)
1638 CellType eCellType = pCell->GetCellType();
1639 bCellIsValue = ( eCellType == CELLTYPE_VALUE );
1640 if ( eCellType == CELLTYPE_FORMULA )
1642 ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
1643 bCellIsValue = pFCell->IsRunning() || pFCell->IsValue();
1646 if (aVars.GetHorJust() == SVX_HOR_JUSTIFY_STANDARD)
1648 // fdo#32530: Default alignment depends on value vs
1649 // string, and the direction of the 1st letter.
1650 if (beginsWithRTLCharacter(aVars.GetString()))
1651 eOutHorJust = bCellIsValue ? SVX_HOR_JUSTIFY_LEFT : SVX_HOR_JUSTIFY_RIGHT;
1652 else
1653 eOutHorJust = bCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT;
1655 else
1656 eOutHorJust = aVars.GetHorJust();
1658 if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT )
1659 eOutHorJust = SVX_HOR_JUSTIFY_LEFT; // repeat is not yet implemented
1661 sal_Bool bBreak = ( aVars.GetLineBreak() || aVars.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK );
1662 // #i111387# #o11817313# disable automatic line breaks only for "General" number format
1663 if ( bBreak && bCellIsValue && ( aVars.GetResultValueFormat(pCell) % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 )
1664 bBreak = sal_False;
1666 sal_Bool bRepeat = aVars.IsRepeat() && !bBreak;
1667 sal_Bool bShrink = aVars.IsShrink() && !bBreak && !bRepeat;
1669 nTotalMargin =
1670 static_cast<long>(aVars.GetLeftTotal() * mnPPTX) +
1671 static_cast<long>(aVars.GetMargin()->GetRightMargin() * mnPPTX);
1673 nNeededWidth = aVars.GetTextSize().Width() + nTotalMargin;
1675 // GetOutputArea gives justfied rectangles
1676 GetOutputArea( nX, nArrY, nPosX, nPosY, nCellX, nCellY, nNeededWidth,
1677 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
1678 bCellIsValue || bRepeat || bShrink, bBreak, false,
1679 aAreaParam );
1681 aVars.RepeatToFill( aAreaParam.mnColWidth - nTotalMargin );
1682 if ( bShrink )
1684 if ( aVars.GetOrient() != SVX_ORIENTATION_STANDARD )
1686 // Only horizontal scaling is handled here.
1687 // DrawEdit is used to vertically scale 90 deg rotated text.
1688 bNeedEdit = sal_True;
1690 else if ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) // horizontal
1692 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
1693 long nScaleSize = aVars.GetTextSize().Width(); // without margin
1695 if ( nScaleSize > 0 ) // 0 if the text is empty (formulas, number formats)
1697 long nScale = ( nAvailable * 100 ) / nScaleSize;
1699 aVars.SetShrinkScale( nScale, nOldScript );
1700 long nNewSize = aVars.GetTextSize().Width();
1702 sal_uInt16 nShrinkAgain = 0;
1703 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
1705 // If the text is still too large, reduce the scale again by 10%, until it fits,
1706 // at most 7 times (it's less than 50% of the calculated scale then).
1708 nScale = ( nScale * 9 ) / 10;
1709 aVars.SetShrinkScale( nScale, nOldScript );
1710 nNewSize = aVars.GetTextSize().Width();
1711 ++nShrinkAgain;
1713 // If even at half the size the font still isn't rendered smaller,
1714 // fall back to normal clipping (showing ### for numbers).
1715 if ( nNewSize <= nAvailable )
1716 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = false;
1718 pOldPattern = NULL;
1723 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip )
1725 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
1726 long nRepeatSize = aVars.GetTextSize().Width(); // without margin
1727 // When formatting for the printer, the text sizes don't always add up.
1728 // Round down (too few repetitions) rather than exceeding the cell size then:
1729 if ( pFmtDevice != mpRefDevice )
1730 ++nRepeatSize;
1731 if ( nRepeatSize > 0 )
1733 long nRepeatCount = nAvailable / nRepeatSize;
1734 if ( nRepeatCount > 1 )
1736 String aCellStr = aVars.GetString();
1737 String aRepeated = aCellStr;
1738 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
1739 aRepeated.Append( aCellStr );
1740 aVars.SetAutoText( aRepeated );
1745 // use edit engine if automatic line breaks are needed
1746 if ( bBreak )
1748 if ( aVars.GetOrient() == SVX_ORIENTATION_STANDARD )
1749 bNeedEdit = ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip );
1750 else
1752 long nHeight = aVars.GetTextSize().Height() +
1753 (long)(aVars.GetMargin()->GetTopMargin()*mnPPTY) +
1754 (long)(aVars.GetMargin()->GetBottomMargin()*mnPPTY);
1755 bNeedEdit = ( nHeight > aAreaParam.maClipRect.GetHeight() );
1758 if (!bNeedEdit)
1760 bNeedEdit =
1761 aVars.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK &&
1762 aVars.GetHorJustMethod() == SVX_JUSTIFY_METHOD_DISTRIBUTE;
1765 if (bNeedEdit)
1767 // mark the cell in CellInfo to be drawn in DrawEdit:
1768 // Cells to the left are marked directly, cells to the
1769 // right are handled by the flag for nX2
1770 SCCOL nMarkX = ( nCellX <= nX2 ) ? nCellX : nX2;
1771 RowInfo* pMarkRowInfo = ( nCellY == nY ) ? pThisRowInfo : &pRowInfo[0];
1772 pMarkRowInfo->pCellInfo[nMarkX+1].bEditEngine = sal_True;
1773 bDoCell = false; // don't draw here
1775 if ( bDoCell )
1777 if ( bCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
1779 if (mbShowFormulas)
1780 aVars.SetHashText();
1781 else
1782 // Adjust the decimals to fit the available column width.
1783 aVars.SetTextToWidthOrHash(pCell, aAreaParam.mnColWidth - nTotalMargin);
1785 nNeededWidth = aVars.GetTextSize().Width() +
1786 (long) ( aVars.GetLeftTotal() * mnPPTX ) +
1787 (long) ( aVars.GetMargin()->GetRightMargin() * mnPPTX );
1788 if ( nNeededWidth <= aAreaParam.maClipRect.GetWidth() )
1789 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = false;
1791 // If the "###" replacement doesn't fit into the cells, no clip marks
1792 // are shown, as the "###" already denotes too little space.
1793 // The rectangles from the first GetOutputArea call remain valid.
1796 long nJustPosX = aAreaParam.maAlignRect.Left(); // "justified" - effect of alignment will be added
1797 long nJustPosY = aAreaParam.maAlignRect.Top();
1798 long nAvailWidth = aAreaParam.maAlignRect.GetWidth();
1799 long nOutHeight = aAreaParam.maAlignRect.GetHeight();
1801 sal_Bool bOutside = ( aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW );
1802 if ( aAreaParam.maClipRect.Left() < nScrX )
1804 aAreaParam.maClipRect.Left() = nScrX;
1805 aAreaParam.mbLeftClip = sal_True;
1807 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
1809 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
1810 aAreaParam.mbRightClip = sal_True;
1813 sal_Bool bHClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
1814 sal_Bool bVClip = false;
1816 if ( aAreaParam.maClipRect.Top() < nScrY )
1818 aAreaParam.maClipRect.Top() = nScrY;
1819 bVClip = sal_True;
1821 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
1823 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
1824 bVClip = sal_True;
1828 // horizontalen Platz testen
1831 sal_Bool bRightAdjusted = false; // to correct text width calculation later
1832 sal_Bool bNeedEditEngine = false;
1833 if ( !bNeedEditEngine && !bOutside )
1835 switch (eOutHorJust)
1837 case SVX_HOR_JUSTIFY_LEFT:
1838 nJustPosX += (long) ( aVars.GetLeftTotal() * mnPPTX );
1839 break;
1840 case SVX_HOR_JUSTIFY_RIGHT:
1841 nJustPosX += nAvailWidth - aVars.GetTextSize().Width() -
1842 (long) ( aVars.GetMargin()->GetRightMargin() * mnPPTX );
1843 bRightAdjusted = sal_True;
1844 break;
1845 case SVX_HOR_JUSTIFY_CENTER:
1846 nJustPosX += ( nAvailWidth - aVars.GetTextSize().Width() +
1847 (long) ( aVars.GetLeftTotal() * mnPPTX ) -
1848 (long) ( aVars.GetMargin()->GetRightMargin() * mnPPTX ) ) / 2;
1849 break;
1850 default:
1852 // added to avoid warnings
1856 long nTestClipHeight = aVars.GetTextSize().Height();
1857 switch (aVars.GetVerJust())
1859 case SVX_VER_JUSTIFY_TOP:
1860 case SVX_VER_JUSTIFY_BLOCK:
1862 long nTop = (long)( aVars.GetMargin()->GetTopMargin() * mnPPTY );
1863 nJustPosY += nTop;
1864 nTestClipHeight += nTop;
1866 break;
1867 case SVX_VER_JUSTIFY_BOTTOM:
1869 long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * mnPPTY );
1870 nJustPosY += nOutHeight - aVars.GetTextSize().Height() - nBot;
1871 nTestClipHeight += nBot;
1873 break;
1874 case SVX_VER_JUSTIFY_CENTER:
1876 long nTop = (long)( aVars.GetMargin()->GetTopMargin() * mnPPTY );
1877 long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * mnPPTY );
1878 nJustPosY += ( nOutHeight + nTop -
1879 aVars.GetTextSize().Height() - nBot ) / 2;
1880 nTestClipHeight += Abs( nTop - nBot );
1882 break;
1883 default:
1885 // added to avoid warnings
1889 if ( nTestClipHeight > nOutHeight )
1891 // kein vertikales Clipping beim Drucken von Zellen mit
1892 // optimaler Hoehe, ausser bei Groesse in bedingter Formatierung
1893 if ( eType != OUTTYPE_PRINTER ||
1894 ( mpDoc->GetRowFlags( nCellY, nTab ) & CR_MANUALSIZE ) ||
1895 ( aVars.HasCondHeight() ) )
1896 bVClip = sal_True;
1899 if ( bHClip || bVClip )
1901 // nur die betroffene Dimension clippen,
1902 // damit bei nicht-proportionalem Resize nicht alle
1903 // rechtsbuendigen Zahlen abgeschnitten werden:
1905 if (!bHClip)
1907 aAreaParam.maClipRect.Left() = nScrX;
1908 aAreaParam.maClipRect.Right() = nScrX+nScrW;
1910 if (!bVClip)
1912 aAreaParam.maClipRect.Top() = nScrY;
1913 aAreaParam.maClipRect.Bottom() = nScrY+nScrH;
1916 // aClipRect is not used after SetClipRegion/IntersectClipRegion,
1917 // so it can be modified here
1918 if (bPixelToLogic)
1919 aAreaParam.maClipRect = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
1921 if (bMetaFile)
1923 mpDev->Push();
1924 mpDev->IntersectClipRegion( aAreaParam.maClipRect );
1926 else
1927 mpDev->SetClipRegion( Region( aAreaParam.maClipRect ) );
1930 Point aURLStart( nJustPosX, nJustPosY ); // copy before modifying for orientation
1932 switch (aVars.GetOrient())
1934 case SVX_ORIENTATION_STANDARD:
1935 nJustPosY += aVars.GetAscent();
1936 break;
1937 case SVX_ORIENTATION_TOPBOTTOM:
1938 nJustPosX += aVars.GetTextSize().Width() - aVars.GetAscent();
1939 break;
1940 case SVX_ORIENTATION_BOTTOMTOP:
1941 nJustPosY += aVars.GetTextSize().Height();
1942 nJustPosX += aVars.GetAscent();
1943 break;
1944 default:
1946 // added to avoid warnings
1950 // When clipping, the visible part is now completely defined by the alignment,
1951 // there's no more special handling to show the right part of RTL text.
1953 Point aDrawTextPos( nJustPosX, nJustPosY );
1954 if ( bPixelToLogic )
1956 // undo text width adjustment in pixels
1957 if (bRightAdjusted)
1958 aDrawTextPos.X() += aVars.GetTextSize().Width();
1960 aDrawTextPos = mpRefDevice->PixelToLogic( aDrawTextPos );
1962 // redo text width adjustment in logic units
1963 if (bRightAdjusted)
1964 aDrawTextPos.X() -= aVars.GetOriginalWidth();
1967 // in Metafiles immer DrawTextArray, damit die Positionen mit
1968 // aufgezeichnet werden (fuer nicht-proportionales Resize):
1970 String aString = aVars.GetString();
1971 if (bMetaFile || pFmtDevice != mpDev || aZoomX != aZoomY)
1973 sal_Int32* pDX = new sal_Int32[aString.Len()];
1974 pFmtDevice->GetTextArray( aString, pDX );
1976 if ( !mpRefDevice->GetConnectMetaFile() ||
1977 mpRefDevice->GetOutDevType() == OUTDEV_PRINTER )
1979 double fMul = GetStretch();
1980 xub_StrLen nLen = aString.Len();
1981 for (xub_StrLen i=0; i<nLen; i++)
1982 pDX[i] = (long)(pDX[i] / fMul + 0.5);
1985 mpDev->DrawTextArray( aDrawTextPos, aString, pDX );
1986 delete[] pDX;
1988 else
1989 mpDev->DrawText( aDrawTextPos, aString );
1991 if ( bHClip || bVClip )
1993 if (bMetaFile)
1994 mpDev->Pop();
1995 else
1996 mpDev->SetClipRegion();
1999 // PDF: whole-cell hyperlink from formula?
2000 sal_Bool bHasURL = pPDFData && pCell && pCell->GetCellType() == CELLTYPE_FORMULA &&
2001 static_cast<ScFormulaCell*>(pCell)->IsHyperLinkCell();
2002 if ( bHasURL )
2004 Rectangle aURLRect( aURLStart, aVars.GetTextSize() );
2005 lcl_DoHyperlinkResult( mpDev, aURLRect, pCell );
2009 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2012 nPosY += pRowInfo[nArrY].nHeight;
2014 if ( bProgress )
2015 ScProgress::DeleteInterpretProgress();
2016 mpDoc->DisableIdle( bWasIdleDisabled );
2019 // -------------------------------------------------------------------------------
2021 ScFieldEditEngine* ScOutputData::CreateOutputEditEngine()
2023 ScFieldEditEngine* pEngine = new ScFieldEditEngine(mpDoc, mpDoc->GetEnginePool());
2024 pEngine->SetUpdateMode( false );
2025 // a RefDevice always has to be set, otherwise EditEngine would create a VirtualDevice
2026 pEngine->SetRefDevice( pFmtDevice );
2027 sal_uLong nCtrl = pEngine->GetControlWord();
2028 if ( bShowSpellErrors )
2029 nCtrl |= EE_CNTRL_ONLINESPELLING;
2030 if ( eType == OUTTYPE_PRINTER )
2031 nCtrl &= ~EE_CNTRL_MARKFIELDS;
2032 if ( eType == OUTTYPE_WINDOW && mpRefDevice == pFmtDevice )
2033 nCtrl &= ~EE_CNTRL_FORMAT100; // use the actual MapMode
2034 pEngine->SetControlWord( nCtrl );
2035 mpDoc->ApplyAsianEditSettings( *pEngine );
2036 pEngine->EnableAutoColor( mbUseStyleColor );
2037 pEngine->SetDefaultHorizontalTextDirection( (EEHorizontalTextDirection)mpDoc->GetEditTextDirection( nTab ) );
2038 return pEngine;
2041 static void lcl_ClearEdit( EditEngine& rEngine ) // Text und Attribute
2043 rEngine.SetUpdateMode( false );
2045 rEngine.SetText(EMPTY_STRING);
2046 // keine Para-Attribute uebrigbehalten...
2047 const SfxItemSet& rPara = rEngine.GetParaAttribs(0);
2048 if (rPara.Count())
2049 rEngine.SetParaAttribs( 0,
2050 SfxItemSet( *rPara.GetPool(), rPara.GetRanges() ) );
2053 static sal_Bool lcl_SafeIsValue( ScBaseCell* pCell )
2055 if (!pCell)
2056 return false;
2058 sal_Bool bRet = false;
2059 switch ( pCell->GetCellType() )
2061 case CELLTYPE_VALUE:
2062 bRet = sal_True;
2063 break;
2064 case CELLTYPE_FORMULA:
2066 ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
2067 if ( pFCell->IsRunning() || pFCell->IsValue() )
2068 bRet = sal_True;
2070 break;
2071 default:
2073 // added to avoid warnings
2076 return bRet;
2079 static void lcl_ScaleFonts( EditEngine& rEngine, long nPercent )
2081 sal_Bool bUpdateMode = rEngine.GetUpdateMode();
2082 if ( bUpdateMode )
2083 rEngine.SetUpdateMode( false );
2085 sal_uInt16 nParCount = rEngine.GetParagraphCount();
2086 for (sal_uInt16 nPar=0; nPar<nParCount; nPar++)
2088 std::vector<sal_uInt16> aPortions;
2089 rEngine.GetPortions( nPar, aPortions );
2091 sal_uInt16 nStart = 0;
2092 for ( std::vector<sal_uInt16>::const_iterator it(aPortions.begin()); it != aPortions.end(); ++it )
2094 sal_uInt16 nEnd = *it;
2095 ESelection aSel( nPar, nStart, nPar, nEnd );
2096 SfxItemSet aAttribs = rEngine.GetAttribs( aSel );
2098 long nWestern = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT)).GetHeight();
2099 long nCJK = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CJK)).GetHeight();
2100 long nCTL = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CTL)).GetHeight();
2102 nWestern = ( nWestern * nPercent ) / 100;
2103 nCJK = ( nCJK * nPercent ) / 100;
2104 nCTL = ( nCTL * nPercent ) / 100;
2106 aAttribs.Put( SvxFontHeightItem( nWestern, 100, EE_CHAR_FONTHEIGHT ) );
2107 aAttribs.Put( SvxFontHeightItem( nCJK, 100, EE_CHAR_FONTHEIGHT_CJK ) );
2108 aAttribs.Put( SvxFontHeightItem( nCTL, 100, EE_CHAR_FONTHEIGHT_CTL ) );
2110 rEngine.QuickSetAttribs( aAttribs, aSel ); //! remove paragraph attributes from aAttribs?
2112 nStart = nEnd;
2116 if ( bUpdateMode )
2117 rEngine.SetUpdateMode( sal_True );
2120 static long lcl_GetEditSize( EditEngine& rEngine, sal_Bool bWidth, sal_Bool bSwap, long nAttrRotate )
2122 if ( bSwap )
2123 bWidth = !bWidth;
2125 if ( nAttrRotate )
2127 long nRealWidth = (long) rEngine.CalcTextWidth();
2128 long nRealHeight = rEngine.GetTextHeight();
2130 // assuming standard mode, otherwise width isn't used
2132 double nRealOrient = nAttrRotate * F_PI18000; // 1/100th degrees
2133 double nAbsCos = fabs( cos( nRealOrient ) );
2134 double nAbsSin = fabs( sin( nRealOrient ) );
2135 if ( bWidth )
2136 return (long) ( nRealWidth * nAbsCos + nRealHeight * nAbsSin );
2137 else
2138 return (long) ( nRealHeight * nAbsCos + nRealWidth * nAbsSin );
2140 else if ( bWidth )
2141 return (long) rEngine.CalcTextWidth();
2142 else
2143 return rEngine.GetTextHeight();
2147 void ScOutputData::ShrinkEditEngine( EditEngine& rEngine, const Rectangle& rAlignRect,
2148 long nLeftM, long nTopM, long nRightM, long nBottomM,
2149 sal_Bool bWidth, sal_uInt16 nOrient, long nAttrRotate, sal_Bool bPixelToLogic,
2150 long& rEngineWidth, long& rEngineHeight, long& rNeededPixel, bool& rLeftClip, bool& rRightClip )
2152 if ( !bWidth )
2154 // vertical
2156 long nScaleSize = bPixelToLogic ?
2157 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2159 // Don't scale if it fits already.
2160 // Allowing to extend into the margin, to avoid scaling at optimal height.
2161 if ( nScaleSize <= rAlignRect.GetHeight() )
2162 return;
2164 sal_Bool bSwap = ( nOrient == SVX_ORIENTATION_TOPBOTTOM || nOrient == SVX_ORIENTATION_BOTTOMTOP );
2165 long nAvailable = rAlignRect.GetHeight() - nTopM - nBottomM;
2166 long nScale = ( nAvailable * 100 ) / nScaleSize;
2168 lcl_ScaleFonts( rEngine, nScale );
2169 rEngineHeight = lcl_GetEditSize( rEngine, false, bSwap, nAttrRotate );
2170 long nNewSize = bPixelToLogic ?
2171 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2173 sal_uInt16 nShrinkAgain = 0;
2174 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
2176 // further reduce, like in DrawStrings
2177 lcl_ScaleFonts( rEngine, 90 ); // reduce by 10%
2178 rEngineHeight = lcl_GetEditSize( rEngine, false, bSwap, nAttrRotate );
2179 nNewSize = bPixelToLogic ?
2180 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2181 ++nShrinkAgain;
2184 // sizes for further processing (alignment etc):
2185 rEngineWidth = lcl_GetEditSize( rEngine, sal_True, bSwap, nAttrRotate );
2186 long nPixelWidth = bPixelToLogic ?
2187 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2188 rNeededPixel = nPixelWidth + nLeftM + nRightM;
2190 else if ( rLeftClip || rRightClip )
2192 // horizontal
2194 long nAvailable = rAlignRect.GetWidth() - nLeftM - nRightM;
2195 long nScaleSize = rNeededPixel - nLeftM - nRightM; // without margin
2197 if ( nScaleSize <= nAvailable )
2198 return;
2200 long nScale = ( nAvailable * 100 ) / nScaleSize;
2202 lcl_ScaleFonts( rEngine, nScale );
2203 rEngineWidth = lcl_GetEditSize( rEngine, sal_True, false, nAttrRotate );
2204 long nNewSize = bPixelToLogic ?
2205 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2207 sal_uInt16 nShrinkAgain = 0;
2208 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
2210 // further reduce, like in DrawStrings
2211 lcl_ScaleFonts( rEngine, 90 ); // reduce by 10%
2212 rEngineWidth = lcl_GetEditSize( rEngine, sal_True, false, nAttrRotate );
2213 nNewSize = bPixelToLogic ?
2214 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2215 ++nShrinkAgain;
2217 if ( nNewSize <= nAvailable )
2218 rLeftClip = rRightClip = false;
2220 // sizes for further processing (alignment etc):
2221 rNeededPixel = nNewSize + nLeftM + nRightM;
2222 rEngineHeight = lcl_GetEditSize( rEngine, false, false, nAttrRotate );
2226 ScOutputData::DrawEditParam::DrawEditParam(const ScPatternAttr* pPattern, const SfxItemSet* pCondSet, bool bCellIsValue) :
2227 meHorJust( lcl_GetValue<SvxHorJustifyItem, SvxCellHorJustify>(*pPattern, ATTR_HOR_JUSTIFY, pCondSet) ),
2228 meVerJust( lcl_GetValue<SvxVerJustifyItem, SvxCellVerJustify>(*pPattern, ATTR_VER_JUSTIFY, pCondSet) ),
2229 meHorJustMethod( lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_HOR_JUSTIFY_METHOD, pCondSet) ),
2230 meVerJustMethod( lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_VER_JUSTIFY_METHOD, pCondSet) ),
2231 meOrient( pPattern->GetCellOrientation(pCondSet) ),
2232 mnArrY(0),
2233 mnX(0), mnY(0), mnCellX(0), mnCellY(0),
2234 mnPosX(0), mnPosY(0), mnInitPosX(0),
2235 mbBreak( (meHorJust == SVX_HOR_JUSTIFY_BLOCK) || lcl_GetBoolValue(*pPattern, ATTR_LINEBREAK, pCondSet) ),
2236 mbCellIsValue(bCellIsValue),
2237 mbAsianVertical(false),
2238 mbPixelToLogic(false),
2239 mbHyphenatorSet(false),
2240 mbRTL(false),
2241 mpEngine(NULL),
2242 mpCell(NULL),
2243 mpPattern(pPattern),
2244 mpCondSet(pCondSet),
2245 mpOldPattern(NULL),
2246 mpOldCondSet(NULL),
2247 mpThisRowInfo(NULL)
2250 bool ScOutputData::DrawEditParam::readCellContent(
2251 ScDocument* pDoc, bool bShowNullValues, bool bShowFormulas, bool bSyntaxMode, bool bUseStyleColor, bool bForceAutoColor, bool& rWrapFields)
2253 if (!mpCell)
2255 OSL_FAIL("pCell == NULL");
2256 return false;
2259 if (mpCell->GetCellType() == CELLTYPE_EDIT)
2261 const EditTextObject* pData;
2262 ((ScEditCell*)mpCell)->GetData(pData);
2264 if (pData)
2266 mpEngine->SetText(*pData);
2268 if ( mbBreak && !mbAsianVertical && pData->HasField() )
2270 // Fields aren't wrapped, so clipping is enabled to prevent
2271 // a field from being drawn beyond the cell size
2273 rWrapFields = true;
2276 else
2278 OSL_FAIL("pData == 0");
2279 return false;
2282 else
2284 sal_uLong nFormat = mpPattern->GetNumberFormat(
2285 pDoc->GetFormatTable(), mpCondSet );
2286 rtl::OUString aString;
2287 Color* pColor;
2288 ScCellFormat::GetString( mpCell,
2289 nFormat,aString, &pColor,
2290 *pDoc->GetFormatTable(),
2291 bShowNullValues,
2292 bShowFormulas,
2293 ftCheck );
2295 mpEngine->SetText(aString);
2296 if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) )
2297 lcl_SetEditColor( *mpEngine, *pColor );
2299 return true;
2302 void ScOutputData::DrawEditParam::setPatternToEngine(bool bUseStyleColor)
2304 // syntax highlighting mode is ignored here
2305 // StringDiffer doesn't look at hyphenate, language items
2307 if (mpPattern == mpOldPattern && mpCondSet == mpOldCondSet)
2308 return;
2310 sal_Int32 nConfBackColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
2311 bool bCellContrast = bUseStyleColor &&
2312 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
2314 SfxItemSet* pSet = new SfxItemSet( mpEngine->GetEmptyItemSet() );
2315 mpPattern->FillEditItemSet( pSet, mpCondSet );
2317 mpEngine->SetDefaults( pSet );
2318 mpOldPattern = mpPattern;
2319 mpOldCondSet = mpCondSet;
2321 sal_uLong nControl = mpEngine->GetControlWord();
2322 if (meOrient == SVX_ORIENTATION_STACKED)
2323 nControl |= EE_CNTRL_ONECHARPERLINE;
2324 else
2325 nControl &= ~EE_CNTRL_ONECHARPERLINE;
2326 mpEngine->SetControlWord( nControl );
2328 if ( !mbHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() )
2330 // set hyphenator the first time it is needed
2331 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
2332 mpEngine->SetHyphenator( xXHyphenator );
2333 mbHyphenatorSet = true;
2336 Color aBackCol = ((const SvxBrushItem&)mpPattern->GetItem( ATTR_BACKGROUND, mpCondSet )).GetColor();
2337 if ( bUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) )
2338 aBackCol.SetColor( nConfBackColor );
2339 mpEngine->SetBackgroundColor( aBackCol );
2342 void ScOutputData::DrawEditParam::calcMargins(long& rTopM, long& rLeftM, long& rBottomM, long& rRightM, double nPPTX, double nPPTY) const
2344 const SvxMarginItem& rMargin =
2345 static_cast<const SvxMarginItem&>(mpPattern->GetItem(ATTR_MARGIN, mpCondSet));
2347 sal_uInt16 nIndent = 0;
2348 if (meHorJust == SVX_HOR_JUSTIFY_LEFT)
2349 nIndent = lcl_GetValue<SfxUInt16Item, sal_uInt16>(*mpPattern, ATTR_INDENT, mpCondSet);
2351 rLeftM = static_cast<long>(((rMargin.GetLeftMargin() + nIndent) * nPPTX));
2352 rTopM = static_cast<long>((rMargin.GetTopMargin() * nPPTY));
2353 rRightM = static_cast<long>((rMargin.GetRightMargin() * nPPTX));
2354 rBottomM = static_cast<long>((rMargin.GetBottomMargin() * nPPTY));
2357 void ScOutputData::DrawEditParam::calcPaperSize(
2358 Size& rPaperSize, const Rectangle& rAlignRect, double nPPTX, double nPPTY) const
2360 long nTopM, nLeftM, nBottomM, nRightM;
2361 calcMargins(nTopM, nLeftM, nBottomM, nRightM, nPPTX, nPPTY);
2363 if (isVerticallyOriented())
2365 rPaperSize.Width() = rAlignRect.GetHeight() - nTopM - nBottomM;
2366 rPaperSize.Height() = rAlignRect.GetWidth() - nLeftM - nRightM;
2368 else
2370 rPaperSize.Width() = rAlignRect.GetWidth() - nLeftM - nRightM;
2371 rPaperSize.Height() = rAlignRect.GetHeight() - nTopM - nBottomM;
2374 if (mbAsianVertical)
2376 rPaperSize.Height() = rAlignRect.GetHeight() - nTopM - nBottomM;
2377 // Subtract some extra value from the height or else the text would go
2378 // outside the cell area. The value of 5 is arbitrary, and is based
2379 // entirely on heuristics.
2380 rPaperSize.Height() -= 5;
2384 void ScOutputData::DrawEditParam::getEngineSize(ScFieldEditEngine* pEngine, long& rWidth, long& rHeight) const
2386 long nEngineWidth = 0;
2387 if (!mbBreak || meOrient == SVX_ORIENTATION_STACKED || mbAsianVertical)
2388 nEngineWidth = static_cast<long>(pEngine->CalcTextWidth());
2390 long nEngineHeight = pEngine->GetTextHeight();
2392 if (isVerticallyOriented())
2394 long nTemp = nEngineWidth;
2395 nEngineWidth = nEngineHeight;
2396 nEngineHeight = nTemp;
2399 if (meOrient == SVX_ORIENTATION_STACKED)
2400 nEngineWidth = nEngineWidth * 11 / 10;
2402 rWidth = nEngineWidth;
2403 rHeight = nEngineHeight;
2406 bool ScOutputData::DrawEditParam::hasLineBreak() const
2408 return (mbBreak || (meOrient == SVX_ORIENTATION_STACKED) || mbAsianVertical);
2411 bool ScOutputData::DrawEditParam::isHyperlinkCell() const
2413 if (!mpCell)
2414 return false;
2416 if (mpCell->GetCellType() != CELLTYPE_FORMULA)
2417 return false;
2419 return static_cast<ScFormulaCell*>(mpCell)->IsHyperLinkCell();
2422 bool ScOutputData::DrawEditParam::isVerticallyOriented() const
2424 return (meOrient == SVX_ORIENTATION_TOPBOTTOM || meOrient == SVX_ORIENTATION_BOTTOMTOP);
2427 void ScOutputData::DrawEditParam::calcStartPosForVertical(
2428 Point& rLogicStart, long nCellWidth, long nEngineWidth, long nTopM, OutputDevice* pRefDevice)
2430 OSL_ENSURE(isVerticallyOriented(), "Use this only for vertically oriented cell!");
2432 if (mbPixelToLogic)
2433 rLogicStart = pRefDevice->PixelToLogic(rLogicStart);
2435 if (mbBreak)
2437 // vertical adjustment is within the EditEngine
2438 if (mbPixelToLogic)
2439 rLogicStart.Y() += pRefDevice->PixelToLogic(Size(0,nTopM)).Height();
2440 else
2441 rLogicStart.Y() += nTopM;
2443 switch (meHorJust)
2445 case SVX_HOR_JUSTIFY_CENTER:
2446 rLogicStart.X() += (nCellWidth - nEngineWidth) / 2;
2447 break;
2448 case SVX_HOR_JUSTIFY_RIGHT:
2449 rLogicStart.X() += nCellWidth - nEngineWidth;
2450 break;
2451 default:
2452 ; // do nothing
2457 void ScOutputData::DrawEditParam::setAlignmentToEngine()
2459 if (isVerticallyOriented() || mbAsianVertical)
2461 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
2462 switch (meVerJust)
2464 case SVX_VER_JUSTIFY_TOP:
2465 eSvxAdjust = (meOrient == SVX_ORIENTATION_TOPBOTTOM || mbAsianVertical) ?
2466 SVX_ADJUST_LEFT : SVX_ADJUST_RIGHT;
2467 break;
2468 case SVX_VER_JUSTIFY_CENTER:
2469 eSvxAdjust = SVX_ADJUST_CENTER;
2470 break;
2471 case SVX_VER_JUSTIFY_BOTTOM:
2472 case SVX_VER_JUSTIFY_STANDARD:
2473 eSvxAdjust = (meOrient == SVX_ORIENTATION_TOPBOTTOM || mbAsianVertical) ?
2474 SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT;
2475 break;
2476 case SVX_VER_JUSTIFY_BLOCK:
2477 eSvxAdjust = SVX_ADJUST_BLOCK;
2478 break;
2481 mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) );
2482 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) );
2484 if (meHorJust == SVX_HOR_JUSTIFY_BLOCK)
2485 mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) );
2487 else
2489 // horizontal alignment now may depend on cell content
2490 // (for values with number formats with mixed script types)
2491 // -> always set adjustment
2493 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
2494 if (meOrient == SVX_ORIENTATION_STACKED)
2495 eSvxAdjust = SVX_ADJUST_CENTER;
2496 else if (mbBreak)
2498 if (meOrient == SVX_ORIENTATION_STANDARD)
2499 switch (meHorJust)
2501 case SVX_HOR_JUSTIFY_STANDARD:
2502 eSvxAdjust = mbCellIsValue ? SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT;
2503 break;
2504 case SVX_HOR_JUSTIFY_LEFT:
2505 case SVX_HOR_JUSTIFY_REPEAT: // nicht implementiert
2506 eSvxAdjust = SVX_ADJUST_LEFT;
2507 break;
2508 case SVX_HOR_JUSTIFY_RIGHT:
2509 eSvxAdjust = SVX_ADJUST_RIGHT;
2510 break;
2511 case SVX_HOR_JUSTIFY_CENTER:
2512 eSvxAdjust = SVX_ADJUST_CENTER;
2513 break;
2514 case SVX_HOR_JUSTIFY_BLOCK:
2515 eSvxAdjust = SVX_ADJUST_BLOCK;
2516 break;
2518 else
2519 switch (meVerJust)
2521 case SVX_VER_JUSTIFY_TOP:
2522 eSvxAdjust = SVX_ADJUST_RIGHT;
2523 break;
2524 case SVX_VER_JUSTIFY_CENTER:
2525 eSvxAdjust = SVX_ADJUST_CENTER;
2526 break;
2527 case SVX_VER_JUSTIFY_BOTTOM:
2528 case SVX_VER_JUSTIFY_STANDARD:
2529 eSvxAdjust = SVX_ADJUST_LEFT;
2530 break;
2531 case SVX_VER_JUSTIFY_BLOCK:
2532 eSvxAdjust = SVX_ADJUST_BLOCK;
2533 break;
2537 mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) );
2539 if (mbAsianVertical)
2541 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) );
2542 if (meHorJust == SVX_HOR_JUSTIFY_BLOCK)
2543 mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) );
2545 else
2547 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meHorJustMethod, EE_PARA_JUST_METHOD) );
2548 if (meVerJust == SVX_VER_JUSTIFY_BLOCK)
2549 mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) );
2553 mpEngine->SetVertical(mbAsianVertical);
2554 if (mpCell && mpCell->GetCellType() == CELLTYPE_EDIT)
2556 // We need to synchronize the vertical mode in the EditTextObject
2557 // instance too. No idea why we keep this state in two separate
2558 // instances.
2559 ScEditCell* pEditCell = static_cast<ScEditCell*>(mpCell);
2560 const EditTextObject* pData = pEditCell->GetData();
2561 if (pData)
2562 const_cast<EditTextObject*>(pData)->SetVertical(mbAsianVertical);
2566 bool ScOutputData::DrawEditParam::adjustHorAlignment(ScFieldEditEngine* pEngine)
2568 if (meHorJust == SVX_HOR_JUSTIFY_RIGHT || meHorJust == SVX_HOR_JUSTIFY_CENTER ||
2569 (meHorJust == SVX_HOR_JUSTIFY_STANDARD && mbCellIsValue))
2571 SvxAdjust eEditAdjust = (meHorJust == SVX_HOR_JUSTIFY_CENTER) ?
2572 SVX_ADJUST_CENTER : SVX_ADJUST_RIGHT;
2574 pEngine->SetUpdateMode(false);
2575 pEngine->SetDefaultItem( SvxAdjustItem(eEditAdjust, EE_PARA_JUST) );
2576 pEngine->SetUpdateMode(true);
2577 return true;
2579 return false;
2582 void ScOutputData::DrawEditParam::adjustForRTL()
2584 if (!mpEngine->IsRightToLeft(0))
2585 // No RTL mode.
2586 return;
2588 // For right-to-left, EditEngine always calculates its lines
2589 // beginning from the right edge, but EditLine::nStartPosX is
2590 // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX.
2591 Size aLogicPaper = mpEngine->GetPaperSize();
2592 if ( aLogicPaper.Width() > USHRT_MAX )
2594 aLogicPaper.Width() = USHRT_MAX;
2595 mpEngine->SetPaperSize(aLogicPaper);
2599 void ScOutputData::DrawEditParam::adjustForHyperlinkInPDF(Point aURLStart, OutputDevice* pDev)
2601 // PDF: whole-cell hyperlink from formula?
2602 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
2603 bool bHasURL = pPDFData && isHyperlinkCell();
2604 if (!bHasURL)
2605 return;
2607 long nURLWidth = (long) mpEngine->CalcTextWidth();
2608 long nURLHeight = mpEngine->GetTextHeight();
2609 if (mbBreak)
2611 Size aPaper = mpEngine->GetPaperSize();
2612 if ( mbAsianVertical )
2613 nURLHeight = aPaper.Height();
2614 else
2615 nURLWidth = aPaper.Width();
2617 if (isVerticallyOriented())
2618 std::swap( nURLWidth, nURLHeight );
2619 else if (mbAsianVertical)
2620 aURLStart.X() -= nURLWidth;
2622 Rectangle aURLRect( aURLStart, Size( nURLWidth, nURLHeight ) );
2623 lcl_DoHyperlinkResult( pDev, aURLRect, mpCell );
2626 void ScOutputData::DrawEditStandard(DrawEditParam& rParam)
2628 OSL_ASSERT(rParam.meOrient == SVX_ORIENTATION_STANDARD);
2629 OSL_ASSERT(!rParam.mbAsianVertical);
2631 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
2633 bool bHidden = false;
2634 bool bRepeat = (rParam.meHorJust == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
2635 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
2636 long nAttrRotate = lcl_GetValue<SfxInt32Item, long>(*rParam.mpPattern, ATTR_ROTATE_VALUE, rParam.mpCondSet);
2638 if ( rParam.meHorJust == SVX_HOR_JUSTIFY_REPEAT )
2640 // ignore orientation/rotation if "repeat" is active
2641 rParam.meOrient = SVX_ORIENTATION_STANDARD;
2642 nAttrRotate = 0;
2644 // #i31843# "repeat" with "line breaks" is treated as default alignment
2645 // (but rotation is still disabled)
2646 if ( rParam.mbBreak )
2647 rParam.meHorJust = SVX_HOR_JUSTIFY_STANDARD;
2650 if (nAttrRotate)
2652 //! Flag setzen, um die Zelle in DrawRotated wiederzufinden ?
2653 //! (oder Flag schon bei DrawBackground, dann hier keine Abfrage)
2654 bHidden = true; // gedreht wird getrennt ausgegeben
2657 SvxCellHorJustify eOutHorJust = rParam.meHorJust;
2658 if (eOutHorJust == SVX_HOR_JUSTIFY_STANDARD)
2660 // fdo#32530: Default alignment depends on value vs string, and the
2661 // direction of the 1st letter.
2662 if (rParam.mbRTL)
2663 eOutHorJust = rParam.mbCellIsValue ? SVX_HOR_JUSTIFY_LEFT : SVX_HOR_JUSTIFY_RIGHT;
2664 else
2665 eOutHorJust = rParam.mbCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT;
2668 if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT )
2669 eOutHorJust = SVX_HOR_JUSTIFY_LEFT; // repeat is not yet implemented
2671 if (bHidden)
2672 return;
2674 //! mirror margin values for RTL?
2675 //! move margin down to after final GetOutputArea call
2676 long nTopM, nLeftM, nBottomM, nRightM;
2677 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
2679 SCCOL nXForPos = rParam.mnX;
2680 if ( nXForPos < nX1 )
2682 nXForPos = nX1;
2683 rParam.mnPosX = rParam.mnInitPosX;
2685 SCSIZE nArrYForPos = rParam.mnArrY;
2686 if ( nArrYForPos < 1 )
2688 nArrYForPos = 1;
2689 rParam.mnPosY = nScrY;
2692 OutputAreaParam aAreaParam;
2695 // Initial page size - large for normal text, cell size for automatic line breaks
2698 Size aPaperSize = Size( 1000000, 1000000 );
2699 if (rParam.mbBreak)
2701 // call GetOutputArea with nNeeded=0, to get only the cell width
2703 //! handle nArrY == 0
2704 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
2705 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
2706 rParam.mbCellIsValue, true, false, aAreaParam );
2708 //! special ScEditUtil handling if formatting for printer
2709 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
2711 if (rParam.mbPixelToLogic)
2713 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
2714 if ( rParam.mbBreak && !rParam.mbAsianVertical && mpRefDevice != pFmtDevice )
2716 // #i85342# screen display and formatting for printer,
2717 // use same GetEditArea call as in ScViewData::SetEditEngine
2719 Fraction aFract(1,1);
2720 Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
2721 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
2722 aLogicSize.Width() = aUtilRect.GetWidth();
2724 rParam.mpEngine->SetPaperSize(aLogicSize);
2726 else
2727 rParam.mpEngine->SetPaperSize(aPaperSize);
2730 // Fill the EditEngine (cell attributes and text)
2733 // default alignment for asian vertical mode is top-right
2734 if ( rParam.mbAsianVertical && rParam.meVerJust == SVX_VER_JUSTIFY_STANDARD )
2735 rParam.meVerJust = SVX_VER_JUSTIFY_TOP;
2737 rParam.setPatternToEngine(mbUseStyleColor);
2738 rParam.setAlignmentToEngine();
2740 // Read content from cell
2742 bool bWrapFields = false;
2743 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
2744 // Failed to read cell content. Bail out.
2745 return;
2747 if ( mbSyntaxMode )
2748 SetEditSyntaxColor( *rParam.mpEngine, rParam.mpCell );
2749 else if ( mbUseStyleColor && mbForceAutoColor )
2750 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
2752 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
2755 // Get final output area using the calculated width
2758 long nEngineWidth, nEngineHeight;
2759 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
2761 long nNeededPixel = nEngineWidth;
2762 if (rParam.mbPixelToLogic)
2763 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
2764 nNeededPixel += nLeftM + nRightM;
2766 if (!rParam.mbBreak || bShrink)
2768 // for break, the first GetOutputArea call is sufficient
2769 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
2770 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
2771 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
2773 if ( bShrink )
2775 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
2776 nLeftM, nTopM, nRightM, nBottomM, true,
2777 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
2778 nEngineWidth, nEngineHeight, nNeededPixel,
2779 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
2781 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
2783 // First check if twice the space for the formatted text is available
2784 // (otherwise just keep it unchanged).
2786 long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
2787 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
2788 if ( nAvailable >= 2 * nFormatted )
2790 // "repeat" is handled with unformatted text (for performance reasons)
2791 String aCellStr = rParam.mpEngine->GetText();
2792 rParam.mpEngine->SetText( aCellStr );
2794 long nRepeatSize = (long) rParam.mpEngine->CalcTextWidth();
2795 if (rParam.mbPixelToLogic)
2796 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
2797 if ( pFmtDevice != mpRefDevice )
2798 ++nRepeatSize;
2799 if ( nRepeatSize > 0 )
2801 long nRepeatCount = nAvailable / nRepeatSize;
2802 if ( nRepeatCount > 1 )
2804 String aRepeated = aCellStr;
2805 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
2806 aRepeated.Append( aCellStr );
2807 rParam.mpEngine->SetText( aRepeated );
2809 nEngineHeight = rParam.mpEngine->GetTextHeight();
2810 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
2811 if (rParam.mbPixelToLogic)
2812 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
2813 else
2814 nNeededPixel = nEngineWidth;
2815 nNeededPixel += nLeftM + nRightM;
2821 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
2823 rParam.mpEngine->SetText(rtl::OUString("###"));
2824 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
2825 if (rParam.mbPixelToLogic)
2826 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
2827 else
2828 nNeededPixel = nEngineWidth;
2829 nNeededPixel += nLeftM + nRightM;
2831 // No clip marks if "###" doesn't fit (same as in DrawStrings)
2834 if (eOutHorJust != SVX_HOR_JUSTIFY_LEFT)
2836 aPaperSize.Width() = nNeededPixel + 1;
2837 if (rParam.mbPixelToLogic)
2838 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
2839 else
2840 rParam.mpEngine->SetPaperSize(aPaperSize);
2844 long nStartX = aAreaParam.maAlignRect.Left();
2845 long nStartY = aAreaParam.maAlignRect.Top();
2846 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
2847 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
2848 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
2850 if (rParam.mbBreak)
2852 // text with automatic breaks is aligned only within the
2853 // edit engine's paper size, the output of the whole area
2854 // is always left-aligned
2856 nStartX += nLeftM;
2858 else
2860 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
2861 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
2862 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
2863 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
2864 else
2865 nStartX += nLeftM;
2868 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
2869 if (bOutside)
2870 return;
2872 if ( aAreaParam.maClipRect.Left() < nScrX )
2874 aAreaParam.maClipRect.Left() = nScrX;
2875 aAreaParam.mbLeftClip = true;
2877 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
2879 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
2880 aAreaParam.mbRightClip = true;
2883 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
2884 bool bSimClip = false;
2886 if ( bWrapFields )
2888 // Fields in a cell with automatic breaks: clip to cell width
2889 bClip = true;
2892 if ( aAreaParam.maClipRect.Top() < nScrY )
2894 aAreaParam.maClipRect.Top() = nScrY;
2895 bClip = true;
2897 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
2899 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
2900 bClip = true;
2903 Size aCellSize; // output area, excluding margins, in logical units
2904 if (rParam.mbPixelToLogic)
2905 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
2906 else
2907 aCellSize = Size( nOutWidth, nOutHeight );
2909 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
2911 const ScMergeAttr* pMerge =
2912 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
2913 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
2915 // Don't clip for text height when printing rows with optimal height,
2916 // except when font size is from conditional formatting.
2917 //! Allow clipping when vertically merged?
2918 if ( eType != OUTTYPE_PRINTER ||
2919 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
2920 ( rParam.mpCondSet && SFX_ITEM_SET ==
2921 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
2922 bClip = true;
2923 else
2924 bSimClip = true;
2926 // Show clip marks if height is at least 5pt too small and
2927 // there are several lines of text.
2928 // Not for asian vertical text, because that would interfere
2929 // with the default right position of the text.
2930 // Only with automatic line breaks, to avoid having to find
2931 // the cells with the horizontal end of the text again.
2932 if ( nEngineHeight - aCellSize.Height() > 100 &&
2933 rParam.mbBreak && bMarkClipped &&
2934 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
2936 CellInfo* pClipMarkCell = NULL;
2937 if ( bMerged )
2939 // anywhere in the merged area...
2940 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
2941 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
2943 else
2944 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
2946 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
2947 bAnyClipped = true;
2949 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
2950 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
2951 aAreaParam.maClipRect.Right() -= nMarkPixel;
2955 Rectangle aLogicClip;
2956 if (bClip || bSimClip)
2958 // Clip marks are already handled in GetOutputArea
2960 if (rParam.mbPixelToLogic)
2961 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
2962 else
2963 aLogicClip = aAreaParam.maClipRect;
2965 if (bClip) // bei bSimClip nur aClipRect initialisieren
2967 if (bMetaFile)
2969 mpDev->Push();
2970 mpDev->IntersectClipRegion( aLogicClip );
2972 else
2973 mpDev->SetClipRegion( Region( aLogicClip ) );
2977 Point aLogicStart;
2978 if (rParam.mbPixelToLogic)
2979 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
2980 else
2981 aLogicStart = Point(nStartX, nStartY);
2983 if (!rParam.mbBreak)
2985 // horizontal alignment
2986 if (rParam.adjustHorAlignment(rParam.mpEngine))
2987 // reset adjustment for the next cell
2988 rParam.mpOldPattern = NULL;
2991 if (rParam.meVerJust==SVX_VER_JUSTIFY_BOTTOM ||
2992 rParam.meVerJust==SVX_VER_JUSTIFY_STANDARD)
2994 //! if pRefDevice != pFmtDevice, keep heights in logic units,
2995 //! only converting margin?
2997 if (rParam.mbPixelToLogic)
2998 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM +
2999 mpRefDevice->LogicToPixel(aCellSize).Height() -
3000 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
3001 )).Height();
3002 else
3003 aLogicStart.Y() += nTopM + aCellSize.Height() - nEngineHeight;
3005 else if (rParam.meVerJust==SVX_VER_JUSTIFY_CENTER)
3007 if (rParam.mbPixelToLogic)
3008 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM + (
3009 mpRefDevice->LogicToPixel(aCellSize).Height() -
3010 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
3011 / 2)).Height();
3012 else
3013 aLogicStart.Y() += nTopM + (aCellSize.Height() - nEngineHeight) / 2;
3015 else // top
3017 if (rParam.mbPixelToLogic)
3018 aLogicStart.Y() += mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3019 else
3020 aLogicStart.Y() += nTopM;
3023 Point aURLStart = aLogicStart; // copy before modifying for orientation
3025 rParam.adjustForRTL();
3027 // bMoveClipped handling has been replaced by complete alignment
3028 // handling (also extending to the left).
3030 if (bSimClip)
3032 // kein hartes Clipping, aber nur die betroffenen
3033 // Zeilen ausgeben
3035 Point aDocStart = aLogicClip.TopLeft();
3036 aDocStart -= aLogicStart;
3037 rParam.mpEngine->Draw( mpDev, aLogicClip, aDocStart, false );
3039 else
3041 rParam.mpEngine->Draw(mpDev, aLogicStart, 0);
3044 if (bClip)
3046 if (bMetaFile)
3047 mpDev->Pop();
3048 else
3049 mpDev->SetClipRegion();
3052 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3055 void ScOutputData::DrawEditBottomTop(DrawEditParam& rParam)
3057 OSL_ASSERT(rParam.meHorJust != SVX_HOR_JUSTIFY_REPEAT);
3058 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
3060 bool bRepeat = (rParam.meHorJust == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
3061 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3063 SvxCellHorJustify eOutHorJust =
3064 ( rParam.meHorJust != SVX_HOR_JUSTIFY_STANDARD ) ? rParam.meHorJust :
3065 ( rParam.mbCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT );
3067 if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT )
3068 eOutHorJust = SVX_HOR_JUSTIFY_LEFT; // repeat is not yet implemented
3070 //! mirror margin values for RTL?
3071 //! move margin down to after final GetOutputArea call
3072 long nTopM, nLeftM, nBottomM, nRightM;
3073 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3075 SCCOL nXForPos = rParam.mnX;
3076 if ( nXForPos < nX1 )
3078 nXForPos = nX1;
3079 rParam.mnPosX = rParam.mnInitPosX;
3081 SCSIZE nArrYForPos = rParam.mnArrY;
3082 if ( nArrYForPos < 1 )
3084 nArrYForPos = 1;
3085 rParam.mnPosY = nScrY;
3088 OutputAreaParam aAreaParam;
3091 // Initial page size - large for normal text, cell size for automatic line breaks
3094 Size aPaperSize = Size( 1000000, 1000000 );
3095 if (rParam.mbBreak)
3097 // call GetOutputArea with nNeeded=0, to get only the cell width
3099 //! handle nArrY == 0
3100 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3101 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3102 rParam.mbCellIsValue, true, false, aAreaParam );
3104 //! special ScEditUtil handling if formatting for printer
3105 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3107 if (rParam.mbPixelToLogic)
3109 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3110 rParam.mpEngine->SetPaperSize(aLogicSize);
3112 else
3113 rParam.mpEngine->SetPaperSize(aPaperSize);
3116 // Fill the EditEngine (cell attributes and text)
3119 rParam.setPatternToEngine(mbUseStyleColor);
3120 rParam.setAlignmentToEngine();
3122 // Read content from cell
3124 bool bWrapFields = false;
3125 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
3126 // Failed to read cell content. Bail out.
3127 return;
3129 if ( mbSyntaxMode )
3130 SetEditSyntaxColor( *rParam.mpEngine, rParam.mpCell );
3131 else if ( mbUseStyleColor && mbForceAutoColor )
3132 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
3134 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3137 // Get final output area using the calculated width
3140 long nEngineWidth, nEngineHeight;
3141 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3143 long nNeededPixel = nEngineWidth;
3144 if (rParam.mbPixelToLogic)
3145 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3146 nNeededPixel += nLeftM + nRightM;
3148 if (!rParam.mbBreak || bShrink)
3150 // for break, the first GetOutputArea call is sufficient
3151 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3152 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3153 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
3155 if ( bShrink )
3157 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3158 nLeftM, nTopM, nRightM, nBottomM, false,
3159 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
3160 nEngineWidth, nEngineHeight, nNeededPixel,
3161 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3163 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3165 // First check if twice the space for the formatted text is available
3166 // (otherwise just keep it unchanged).
3168 long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3169 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3170 if ( nAvailable >= 2 * nFormatted )
3172 // "repeat" is handled with unformatted text (for performance reasons)
3173 String aCellStr = rParam.mpEngine->GetText();
3174 rParam.mpEngine->SetText( aCellStr );
3176 long nRepeatSize = (long) rParam.mpEngine->CalcTextWidth();
3177 if (rParam.mbPixelToLogic)
3178 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
3179 if ( pFmtDevice != mpRefDevice )
3180 ++nRepeatSize;
3181 if ( nRepeatSize > 0 )
3183 long nRepeatCount = nAvailable / nRepeatSize;
3184 if ( nRepeatCount > 1 )
3186 String aRepeated = aCellStr;
3187 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3188 aRepeated.Append( aCellStr );
3189 rParam.mpEngine->SetText( aRepeated );
3191 nEngineHeight = rParam.mpEngine->GetTextHeight();
3192 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3193 if (rParam.mbPixelToLogic)
3194 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3195 else
3196 nNeededPixel = nEngineWidth;
3197 nNeededPixel += nLeftM + nRightM;
3203 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3205 rParam.mpEngine->SetText(rtl::OUString("###"));
3206 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3207 if (rParam.mbPixelToLogic)
3208 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3209 else
3210 nNeededPixel = nEngineWidth;
3211 nNeededPixel += nLeftM + nRightM;
3213 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3217 long nStartX = aAreaParam.maAlignRect.Left();
3218 long nStartY = aAreaParam.maAlignRect.Top();
3219 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3220 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3221 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3223 if (rParam.mbBreak)
3225 // text with automatic breaks is aligned only within the
3226 // edit engine's paper size, the output of the whole area
3227 // is always left-aligned
3229 nStartX += nLeftM;
3231 else
3233 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
3234 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3235 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
3236 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3237 else
3238 nStartX += nLeftM;
3241 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3242 if (bOutside)
3243 return;
3245 if ( aAreaParam.maClipRect.Left() < nScrX )
3247 aAreaParam.maClipRect.Left() = nScrX;
3248 aAreaParam.mbLeftClip = true;
3250 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
3252 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
3253 aAreaParam.mbRightClip = true;
3256 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
3257 bool bSimClip = false;
3259 if ( bWrapFields )
3261 // Fields in a cell with automatic breaks: clip to cell width
3262 bClip = true;
3265 if ( aAreaParam.maClipRect.Top() < nScrY )
3267 aAreaParam.maClipRect.Top() = nScrY;
3268 bClip = true;
3270 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
3272 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
3273 bClip = true;
3276 Size aCellSize; // output area, excluding margins, in logical units
3277 if (rParam.mbPixelToLogic)
3278 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
3279 else
3280 aCellSize = Size( nOutWidth, nOutHeight );
3282 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
3284 const ScMergeAttr* pMerge =
3285 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
3286 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
3288 // Don't clip for text height when printing rows with optimal height,
3289 // except when font size is from conditional formatting.
3290 //! Allow clipping when vertically merged?
3291 if ( eType != OUTTYPE_PRINTER ||
3292 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
3293 ( rParam.mpCondSet && SFX_ITEM_SET ==
3294 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
3295 bClip = true;
3296 else
3297 bSimClip = true;
3299 // Show clip marks if height is at least 5pt too small and
3300 // there are several lines of text.
3301 // Not for asian vertical text, because that would interfere
3302 // with the default right position of the text.
3303 // Only with automatic line breaks, to avoid having to find
3304 // the cells with the horizontal end of the text again.
3305 if ( nEngineHeight - aCellSize.Height() > 100 &&
3306 rParam.mbBreak && bMarkClipped &&
3307 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
3309 CellInfo* pClipMarkCell = NULL;
3310 if ( bMerged )
3312 // anywhere in the merged area...
3313 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
3314 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
3316 else
3317 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
3319 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
3320 bAnyClipped = true;
3322 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
3323 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
3324 aAreaParam.maClipRect.Right() -= nMarkPixel;
3328 Rectangle aLogicClip;
3329 if (bClip || bSimClip)
3331 // Clip marks are already handled in GetOutputArea
3333 if (rParam.mbPixelToLogic)
3334 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
3335 else
3336 aLogicClip = aAreaParam.maClipRect;
3338 if (bClip) // bei bSimClip nur aClipRect initialisieren
3340 if (bMetaFile)
3342 mpDev->Push();
3343 mpDev->IntersectClipRegion( aLogicClip );
3345 else
3346 mpDev->SetClipRegion( Region( aLogicClip ) );
3350 Point aLogicStart(nStartX, nStartY);
3351 rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
3353 Point aURLStart = aLogicStart; // copy before modifying for orientation
3355 if (rParam.meHorJust == SVX_HOR_JUSTIFY_BLOCK || rParam.mbBreak)
3357 Size aPSize = rParam.mpEngine->GetPaperSize();
3358 aPSize.Width() = aCellSize.Height();
3359 rParam.mpEngine->SetPaperSize(aPSize);
3360 aLogicStart.Y() +=
3361 rParam.mbBreak ? aPSize.Width() : nEngineHeight;
3363 else
3365 // Note that the "paper" is rotated 90 degrees to the left, so
3366 // paper's width is in vertical direction. Also, the whole text
3367 // is on a single line, as text wrap is not in effect.
3369 // Set the paper width to be the width of the text.
3370 Size aPSize = rParam.mpEngine->GetPaperSize();
3371 aPSize.Width() = rParam.mpEngine->CalcTextWidth();
3372 rParam.mpEngine->SetPaperSize(aPSize);
3374 long nGap = 0;
3375 long nTopOffset = 0;
3376 if (rParam.mbPixelToLogic)
3378 nGap = mpRefDevice->LogicToPixel(aCellSize).Height() - mpRefDevice->LogicToPixel(aPSize).Width();
3379 nGap = mpRefDevice->PixelToLogic(Size(0, nGap)).Height();
3380 nTopOffset = mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3382 else
3384 nGap = aCellSize.Height() - aPSize.Width();
3385 nTopOffset = nTopM;
3388 // First, align text to bottom.
3389 aLogicStart.Y() += aCellSize.Height();
3390 aLogicStart.Y() += nTopOffset;
3392 switch (rParam.meVerJust)
3394 case SVX_VER_JUSTIFY_STANDARD:
3395 case SVX_VER_JUSTIFY_BOTTOM:
3396 // align to bottom (do nothing).
3397 break;
3398 case SVX_VER_JUSTIFY_CENTER:
3399 // center it.
3400 aLogicStart.Y() -= nGap / 2;
3401 break;
3402 case SVX_VER_JUSTIFY_BLOCK:
3403 case SVX_VER_JUSTIFY_TOP:
3404 // align to top
3405 aLogicStart.Y() -= nGap;
3406 default:
3411 rParam.adjustForRTL();
3412 rParam.mpEngine->Draw(mpDev, aLogicStart, 900);
3414 if (bClip)
3416 if (bMetaFile)
3417 mpDev->Pop();
3418 else
3419 mpDev->SetClipRegion();
3422 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3425 void ScOutputData::DrawEditTopBottom(DrawEditParam& rParam)
3427 OSL_ASSERT(rParam.meHorJust != SVX_HOR_JUSTIFY_REPEAT);
3428 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
3430 bool bRepeat = (rParam.meHorJust == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
3431 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3433 SvxCellHorJustify eOutHorJust =
3434 ( rParam.meHorJust != SVX_HOR_JUSTIFY_STANDARD ) ? rParam.meHorJust :
3435 ( rParam.mbCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT );
3437 if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT )
3438 eOutHorJust = SVX_HOR_JUSTIFY_LEFT; // repeat is not yet implemented
3440 //! mirror margin values for RTL?
3441 //! move margin down to after final GetOutputArea call
3442 long nTopM, nLeftM, nBottomM, nRightM;
3443 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3445 SCCOL nXForPos = rParam.mnX;
3446 if ( nXForPos < nX1 )
3448 nXForPos = nX1;
3449 rParam.mnPosX = rParam.mnInitPosX;
3451 SCSIZE nArrYForPos = rParam.mnArrY;
3452 if ( nArrYForPos < 1 )
3454 nArrYForPos = 1;
3455 rParam.mnPosY = nScrY;
3458 OutputAreaParam aAreaParam;
3461 // Initial page size - large for normal text, cell size for automatic line breaks
3464 Size aPaperSize = Size( 1000000, 1000000 );
3465 if (rParam.hasLineBreak())
3467 // call GetOutputArea with nNeeded=0, to get only the cell width
3469 //! handle nArrY == 0
3470 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3471 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3472 rParam.mbCellIsValue, true, false, aAreaParam );
3474 //! special ScEditUtil handling if formatting for printer
3475 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3477 if (rParam.mbPixelToLogic)
3479 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3480 rParam.mpEngine->SetPaperSize(aLogicSize);
3482 else
3483 rParam.mpEngine->SetPaperSize(aPaperSize);
3486 // Fill the EditEngine (cell attributes and text)
3489 rParam.setPatternToEngine(mbUseStyleColor);
3490 rParam.setAlignmentToEngine();
3492 // Read content from cell
3494 bool bWrapFields = false;
3495 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
3496 // Failed to read cell content. Bail out.
3497 return;
3499 if ( mbSyntaxMode )
3500 SetEditSyntaxColor( *rParam.mpEngine, rParam.mpCell );
3501 else if ( mbUseStyleColor && mbForceAutoColor )
3502 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
3504 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3507 // Get final output area using the calculated width
3510 long nEngineWidth, nEngineHeight;
3511 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3513 long nNeededPixel = nEngineWidth;
3514 if (rParam.mbPixelToLogic)
3515 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3516 nNeededPixel += nLeftM + nRightM;
3518 if (!rParam.mbBreak || bShrink)
3520 // for break, the first GetOutputArea call is sufficient
3521 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3522 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3523 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
3525 if ( bShrink )
3527 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3528 nLeftM, nTopM, nRightM, nBottomM, false,
3529 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
3530 nEngineWidth, nEngineHeight, nNeededPixel,
3531 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3533 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3535 // First check if twice the space for the formatted text is available
3536 // (otherwise just keep it unchanged).
3538 long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3539 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3540 if ( nAvailable >= 2 * nFormatted )
3542 // "repeat" is handled with unformatted text (for performance reasons)
3543 String aCellStr = rParam.mpEngine->GetText();
3544 rParam.mpEngine->SetText( aCellStr );
3546 long nRepeatSize = (long) rParam.mpEngine->CalcTextWidth();
3547 if (rParam.mbPixelToLogic)
3548 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
3549 if ( pFmtDevice != mpRefDevice )
3550 ++nRepeatSize;
3551 if ( nRepeatSize > 0 )
3553 long nRepeatCount = nAvailable / nRepeatSize;
3554 if ( nRepeatCount > 1 )
3556 String aRepeated = aCellStr;
3557 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3558 aRepeated.Append( aCellStr );
3559 rParam.mpEngine->SetText( aRepeated );
3561 nEngineHeight = rParam.mpEngine->GetTextHeight();
3562 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3563 if (rParam.mbPixelToLogic)
3564 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3565 else
3566 nNeededPixel = nEngineWidth;
3567 nNeededPixel += nLeftM + nRightM;
3573 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3575 rParam.mpEngine->SetText(rtl::OUString("###"));
3576 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3577 if (rParam.mbPixelToLogic)
3578 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3579 else
3580 nNeededPixel = nEngineWidth;
3581 nNeededPixel += nLeftM + nRightM;
3583 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3587 long nStartX = aAreaParam.maAlignRect.Left();
3588 long nStartY = aAreaParam.maAlignRect.Top();
3589 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3590 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3591 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3593 if (rParam.mbBreak)
3595 // text with automatic breaks is aligned only within the
3596 // edit engine's paper size, the output of the whole area
3597 // is always left-aligned
3599 nStartX += nLeftM;
3600 if (rParam.meHorJust == SVX_HOR_JUSTIFY_BLOCK)
3601 nStartX += aPaperSize.Height();
3603 else
3605 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
3606 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3607 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
3608 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3609 else
3610 nStartX += nLeftM;
3613 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3614 if (bOutside)
3615 return;
3617 if ( aAreaParam.maClipRect.Left() < nScrX )
3619 aAreaParam.maClipRect.Left() = nScrX;
3620 aAreaParam.mbLeftClip = true;
3622 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
3624 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
3625 aAreaParam.mbRightClip = true;
3628 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
3629 bool bSimClip = false;
3631 if ( bWrapFields )
3633 // Fields in a cell with automatic breaks: clip to cell width
3634 bClip = true;
3637 if ( aAreaParam.maClipRect.Top() < nScrY )
3639 aAreaParam.maClipRect.Top() = nScrY;
3640 bClip = true;
3642 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
3644 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
3645 bClip = true;
3648 Size aCellSize; // output area, excluding margins, in logical units
3649 if (rParam.mbPixelToLogic)
3650 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
3651 else
3652 aCellSize = Size( nOutWidth, nOutHeight );
3654 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
3656 const ScMergeAttr* pMerge =
3657 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
3658 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
3660 // Don't clip for text height when printing rows with optimal height,
3661 // except when font size is from conditional formatting.
3662 //! Allow clipping when vertically merged?
3663 if ( eType != OUTTYPE_PRINTER ||
3664 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
3665 ( rParam.mpCondSet && SFX_ITEM_SET ==
3666 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
3667 bClip = true;
3668 else
3669 bSimClip = true;
3671 // Show clip marks if height is at least 5pt too small and
3672 // there are several lines of text.
3673 // Not for asian vertical text, because that would interfere
3674 // with the default right position of the text.
3675 // Only with automatic line breaks, to avoid having to find
3676 // the cells with the horizontal end of the text again.
3677 if ( nEngineHeight - aCellSize.Height() > 100 &&
3678 rParam.mbBreak && bMarkClipped &&
3679 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
3681 CellInfo* pClipMarkCell = NULL;
3682 if ( bMerged )
3684 // anywhere in the merged area...
3685 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
3686 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
3688 else
3689 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
3691 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
3692 bAnyClipped = true;
3694 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
3695 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
3696 aAreaParam.maClipRect.Right() -= nMarkPixel;
3700 Rectangle aLogicClip;
3701 if (bClip || bSimClip)
3703 // Clip marks are already handled in GetOutputArea
3705 if (rParam.mbPixelToLogic)
3706 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
3707 else
3708 aLogicClip = aAreaParam.maClipRect;
3710 if (bClip) // bei bSimClip nur aClipRect initialisieren
3712 if (bMetaFile)
3714 mpDev->Push();
3715 mpDev->IntersectClipRegion( aLogicClip );
3717 else
3718 mpDev->SetClipRegion( Region( aLogicClip ) );
3722 Point aLogicStart(nStartX, nStartY);
3723 rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
3725 Point aURLStart = aLogicStart; // copy before modifying for orientation
3727 if (rParam.meHorJust != SVX_HOR_JUSTIFY_BLOCK)
3729 aLogicStart.X() += nEngineWidth;
3730 if (!rParam.mbBreak)
3732 // Set the paper width to text size.
3733 Size aPSize = rParam.mpEngine->GetPaperSize();
3734 aPSize.Width() = rParam.mpEngine->CalcTextWidth();
3735 rParam.mpEngine->SetPaperSize(aPSize);
3737 long nGap = 0;
3738 long nTopOffset = 0; // offset by top margin
3739 if (rParam.mbPixelToLogic)
3741 nGap = mpRefDevice->LogicToPixel(aPSize).Width() - mpRefDevice->LogicToPixel(aCellSize).Height();
3742 nGap = mpRefDevice->PixelToLogic(Size(0, nGap)).Height();
3743 nTopOffset = mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3745 else
3747 nGap = aPSize.Width() - aCellSize.Height();
3748 nTopOffset = nTopM;
3750 aLogicStart.Y() += nTopOffset;
3752 switch (rParam.meVerJust)
3754 case SVX_VER_JUSTIFY_STANDARD:
3755 case SVX_VER_JUSTIFY_BOTTOM:
3756 // align to bottom
3757 aLogicStart.Y() -= nGap;
3758 break;
3759 case SVX_VER_JUSTIFY_CENTER:
3760 // center it.
3761 aLogicStart.Y() -= nGap / 2;
3762 break;
3763 case SVX_VER_JUSTIFY_BLOCK:
3764 case SVX_VER_JUSTIFY_TOP:
3765 // align to top (do nothing)
3766 default:
3772 rParam.adjustForRTL();
3774 // bMoveClipped handling has been replaced by complete alignment
3775 // handling (also extending to the left).
3777 rParam.mpEngine->Draw(mpDev, aLogicStart, 2700);
3779 if (bClip)
3781 if (bMetaFile)
3782 mpDev->Pop();
3783 else
3784 mpDev->SetClipRegion();
3787 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3790 void ScOutputData::DrawEditStacked(DrawEditParam& rParam)
3792 OSL_ASSERT(rParam.meHorJust != SVX_HOR_JUSTIFY_REPEAT);
3793 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
3795 bool bRepeat = (rParam.meHorJust == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
3796 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3798 rParam.mbAsianVertical =
3799 lcl_GetBoolValue(*rParam.mpPattern, ATTR_VERTICAL_ASIAN, rParam.mpCondSet);
3801 if ( rParam.mbAsianVertical )
3803 // in asian mode, use EditEngine::SetVertical instead of EE_CNTRL_ONECHARPERLINE
3804 rParam.meOrient = SVX_ORIENTATION_STANDARD;
3805 DrawEditAsianVertical(rParam);
3806 return;
3809 SvxCellHorJustify eOutHorJust =
3810 ( rParam.meHorJust != SVX_HOR_JUSTIFY_STANDARD ) ? rParam.meHorJust :
3811 ( rParam.mbCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT );
3813 if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT )
3814 eOutHorJust = SVX_HOR_JUSTIFY_LEFT; // repeat is not yet implemented
3816 //! mirror margin values for RTL?
3817 //! move margin down to after final GetOutputArea call
3818 long nTopM, nLeftM, nBottomM, nRightM;
3819 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3821 SCCOL nXForPos = rParam.mnX;
3822 if ( nXForPos < nX1 )
3824 nXForPos = nX1;
3825 rParam.mnPosX = rParam.mnInitPosX;
3827 SCSIZE nArrYForPos = rParam.mnArrY;
3828 if ( nArrYForPos < 1 )
3830 nArrYForPos = 1;
3831 rParam.mnPosY = nScrY;
3834 OutputAreaParam aAreaParam;
3837 // Initial page size - large for normal text, cell size for automatic line breaks
3840 Size aPaperSize = Size( 1000000, 1000000 );
3841 // call GetOutputArea with nNeeded=0, to get only the cell width
3843 //! handle nArrY == 0
3844 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3845 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3846 rParam.mbCellIsValue, true, false, aAreaParam );
3848 //! special ScEditUtil handling if formatting for printer
3849 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3851 if (rParam.mbPixelToLogic)
3853 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3854 if ( rParam.mbBreak && mpRefDevice != pFmtDevice )
3856 // #i85342# screen display and formatting for printer,
3857 // use same GetEditArea call as in ScViewData::SetEditEngine
3859 Fraction aFract(1,1);
3860 Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
3861 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
3862 aLogicSize.Width() = aUtilRect.GetWidth();
3864 rParam.mpEngine->SetPaperSize(aLogicSize);
3866 else
3867 rParam.mpEngine->SetPaperSize(aPaperSize);
3870 // Fill the EditEngine (cell attributes and text)
3873 rParam.setPatternToEngine(mbUseStyleColor);
3874 rParam.setAlignmentToEngine();
3876 // Read content from cell
3878 bool bWrapFields = false;
3879 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
3880 // Failed to read cell content. Bail out.
3881 return;
3883 if ( mbSyntaxMode )
3884 SetEditSyntaxColor( *rParam.mpEngine, rParam.mpCell );
3885 else if ( mbUseStyleColor && mbForceAutoColor )
3886 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
3888 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3891 // Get final output area using the calculated width
3894 long nEngineWidth, nEngineHeight;
3895 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3897 long nNeededPixel = nEngineWidth;
3898 if (rParam.mbPixelToLogic)
3899 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3900 nNeededPixel += nLeftM + nRightM;
3902 if (bShrink)
3904 // for break, the first GetOutputArea call is sufficient
3905 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3906 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3907 true, false, false, aAreaParam );
3909 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3910 nLeftM, nTopM, nRightM, nBottomM, true,
3911 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
3912 nEngineWidth, nEngineHeight, nNeededPixel,
3913 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3915 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3917 // First check if twice the space for the formatted text is available
3918 // (otherwise just keep it unchanged).
3920 long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3921 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3922 if ( nAvailable >= 2 * nFormatted )
3924 // "repeat" is handled with unformatted text (for performance reasons)
3925 String aCellStr = rParam.mpEngine->GetText();
3926 rParam.mpEngine->SetText( aCellStr );
3928 long nRepeatSize = (long) rParam.mpEngine->CalcTextWidth();
3929 if (rParam.mbPixelToLogic)
3930 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
3931 if ( pFmtDevice != mpRefDevice )
3932 ++nRepeatSize;
3933 if ( nRepeatSize > 0 )
3935 long nRepeatCount = nAvailable / nRepeatSize;
3936 if ( nRepeatCount > 1 )
3938 String aRepeated = aCellStr;
3939 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3940 aRepeated.Append( aCellStr );
3941 rParam.mpEngine->SetText( aRepeated );
3943 nEngineHeight = rParam.mpEngine->GetTextHeight();
3944 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3945 if (rParam.mbPixelToLogic)
3946 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3947 else
3948 nNeededPixel = nEngineWidth;
3949 nNeededPixel += nLeftM + nRightM;
3955 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3957 rParam.mpEngine->SetText(rtl::OUString("###"));
3958 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3959 if (rParam.mbPixelToLogic)
3960 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3961 else
3962 nNeededPixel = nEngineWidth;
3963 nNeededPixel += nLeftM + nRightM;
3965 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3968 if ( eOutHorJust != SVX_HOR_JUSTIFY_LEFT )
3970 aPaperSize.Width() = nNeededPixel + 1;
3971 if (rParam.mbPixelToLogic)
3972 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
3973 else
3974 rParam.mpEngine->SetPaperSize(aPaperSize);
3978 long nStartX = aAreaParam.maAlignRect.Left();
3979 long nStartY = aAreaParam.maAlignRect.Top();
3980 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3981 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3982 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3984 if (rParam.mbBreak)
3986 // text with automatic breaks is aligned only within the
3987 // edit engine's paper size, the output of the whole area
3988 // is always left-aligned
3990 nStartX += nLeftM;
3992 else
3994 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
3995 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3996 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
3997 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3998 else
3999 nStartX += nLeftM;
4002 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
4003 if (bOutside)
4004 return;
4006 if ( aAreaParam.maClipRect.Left() < nScrX )
4008 aAreaParam.maClipRect.Left() = nScrX;
4009 aAreaParam.mbLeftClip = true;
4011 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
4013 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
4014 aAreaParam.mbRightClip = true;
4017 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
4018 bool bSimClip = false;
4020 if ( bWrapFields )
4022 // Fields in a cell with automatic breaks: clip to cell width
4023 bClip = true;
4026 if ( aAreaParam.maClipRect.Top() < nScrY )
4028 aAreaParam.maClipRect.Top() = nScrY;
4029 bClip = true;
4031 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
4033 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
4034 bClip = true;
4037 Size aCellSize; // output area, excluding margins, in logical units
4038 if (rParam.mbPixelToLogic)
4039 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
4040 else
4041 aCellSize = Size( nOutWidth, nOutHeight );
4043 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
4045 const ScMergeAttr* pMerge =
4046 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
4047 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4049 // Don't clip for text height when printing rows with optimal height,
4050 // except when font size is from conditional formatting.
4051 //! Allow clipping when vertically merged?
4052 if ( eType != OUTTYPE_PRINTER ||
4053 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
4054 ( rParam.mpCondSet && SFX_ITEM_SET ==
4055 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
4056 bClip = true;
4057 else
4058 bSimClip = true;
4060 // Show clip marks if height is at least 5pt too small and
4061 // there are several lines of text.
4062 // Not for asian vertical text, because that would interfere
4063 // with the default right position of the text.
4064 // Only with automatic line breaks, to avoid having to find
4065 // the cells with the horizontal end of the text again.
4066 if ( nEngineHeight - aCellSize.Height() > 100 &&
4067 rParam.mbBreak && bMarkClipped &&
4068 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
4070 CellInfo* pClipMarkCell = NULL;
4071 if ( bMerged )
4073 // anywhere in the merged area...
4074 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
4075 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
4077 else
4078 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
4080 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
4081 bAnyClipped = true;
4083 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
4084 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
4085 aAreaParam.maClipRect.Right() -= nMarkPixel;
4089 Rectangle aLogicClip;
4090 if (bClip || bSimClip)
4092 // Clip marks are already handled in GetOutputArea
4094 if (rParam.mbPixelToLogic)
4095 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
4096 else
4097 aLogicClip = aAreaParam.maClipRect;
4099 if (bClip) // bei bSimClip nur aClipRect initialisieren
4101 if (bMetaFile)
4103 mpDev->Push();
4104 mpDev->IntersectClipRegion( aLogicClip );
4106 else
4107 mpDev->SetClipRegion( Region( aLogicClip ) );
4111 Point aLogicStart;
4112 if (rParam.mbPixelToLogic)
4113 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
4114 else
4115 aLogicStart = Point(nStartX, nStartY);
4117 if (rParam.meVerJust==SVX_VER_JUSTIFY_BOTTOM ||
4118 rParam.meVerJust==SVX_VER_JUSTIFY_STANDARD)
4120 //! if pRefDevice != pFmtDevice, keep heights in logic units,
4121 //! only converting margin?
4123 if (rParam.mbPixelToLogic)
4124 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM +
4125 mpRefDevice->LogicToPixel(aCellSize).Height() -
4126 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
4127 )).Height();
4128 else
4129 aLogicStart.Y() += nTopM + aCellSize.Height() - nEngineHeight;
4131 else if (rParam.meVerJust==SVX_VER_JUSTIFY_CENTER)
4133 if (rParam.mbPixelToLogic)
4134 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM + (
4135 mpRefDevice->LogicToPixel(aCellSize).Height() -
4136 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
4137 / 2)).Height();
4138 else
4139 aLogicStart.Y() += nTopM + (aCellSize.Height() - nEngineHeight) / 2;
4141 else // top
4143 if (rParam.mbPixelToLogic)
4144 aLogicStart.Y() += mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
4145 else
4146 aLogicStart.Y() += nTopM;
4149 Point aURLStart = aLogicStart; // copy before modifying for orientation
4151 Size aPaperLogic = rParam.mpEngine->GetPaperSize();
4152 aPaperLogic.Width() = nEngineWidth;
4153 rParam.mpEngine->SetPaperSize(aPaperLogic);
4155 rParam.adjustForRTL();
4157 // bMoveClipped handling has been replaced by complete alignment
4158 // handling (also extending to the left).
4160 if (bSimClip)
4162 // kein hartes Clipping, aber nur die betroffenen
4163 // Zeilen ausgeben
4165 Point aDocStart = aLogicClip.TopLeft();
4166 aDocStart -= aLogicStart;
4167 rParam.mpEngine->Draw( mpDev, aLogicClip, aDocStart, false );
4169 else
4171 rParam.mpEngine->Draw( mpDev, aLogicStart, 0 );
4174 if (bClip)
4176 if (bMetaFile)
4177 mpDev->Pop();
4178 else
4179 mpDev->SetClipRegion();
4182 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
4185 void ScOutputData::DrawEditAsianVertical(DrawEditParam& rParam)
4187 // When in asian vertical orientation, the orientation value is STANDARD,
4188 // and the asian vertical boolean is true.
4189 OSL_ASSERT(rParam.meOrient == SVX_ORIENTATION_STANDARD);
4190 OSL_ASSERT(rParam.mbAsianVertical);
4191 OSL_ASSERT(rParam.meHorJust != SVX_HOR_JUSTIFY_REPEAT);
4193 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
4195 bool bHidden = false;
4196 bool bRepeat = false;
4197 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
4198 long nAttrRotate = lcl_GetValue<SfxInt32Item, long>(*rParam.mpPattern, ATTR_ROTATE_VALUE, rParam.mpCondSet);
4200 if (nAttrRotate)
4202 //! Flag setzen, um die Zelle in DrawRotated wiederzufinden ?
4203 //! (oder Flag schon bei DrawBackground, dann hier keine Abfrage)
4204 bHidden = true; // gedreht wird getrennt ausgegeben
4207 // default alignment for asian vertical mode is top-right
4208 if ( rParam.meHorJust == SVX_HOR_JUSTIFY_STANDARD )
4209 rParam.meHorJust = SVX_HOR_JUSTIFY_RIGHT;
4211 SvxCellHorJustify eOutHorJust =
4212 ( rParam.meHorJust != SVX_HOR_JUSTIFY_STANDARD ) ? rParam.meHorJust :
4213 ( rParam.mbCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT );
4215 if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT )
4216 eOutHorJust = SVX_HOR_JUSTIFY_LEFT; // repeat is not yet implemented
4218 if (bHidden)
4219 return;
4221 //! mirror margin values for RTL?
4222 //! move margin down to after final GetOutputArea call
4223 long nTopM, nLeftM, nBottomM, nRightM;
4224 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
4226 SCCOL nXForPos = rParam.mnX;
4227 if ( nXForPos < nX1 )
4229 nXForPos = nX1;
4230 rParam.mnPosX = rParam.mnInitPosX;
4232 SCSIZE nArrYForPos = rParam.mnArrY;
4233 if ( nArrYForPos < 1 )
4235 nArrYForPos = 1;
4236 rParam.mnPosY = nScrY;
4239 OutputAreaParam aAreaParam;
4242 // Initial page size - large for normal text, cell size for automatic line breaks
4245 Size aPaperSize = Size( 1000000, 1000000 );
4246 // call GetOutputArea with nNeeded=0, to get only the cell width
4248 //! handle nArrY == 0
4249 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
4250 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
4251 rParam.mbCellIsValue, true, false, aAreaParam );
4253 //! special ScEditUtil handling if formatting for printer
4254 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
4256 if (rParam.mbPixelToLogic)
4258 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
4259 if ( rParam.mbBreak && !rParam.mbAsianVertical && mpRefDevice != pFmtDevice )
4261 // #i85342# screen display and formatting for printer,
4262 // use same GetEditArea call as in ScViewData::SetEditEngine
4264 Fraction aFract(1,1);
4265 Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
4266 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
4267 aLogicSize.Width() = aUtilRect.GetWidth();
4269 rParam.mpEngine->SetPaperSize(aLogicSize);
4271 else
4272 rParam.mpEngine->SetPaperSize(aPaperSize);
4275 // Fill the EditEngine (cell attributes and text)
4278 // default alignment for asian vertical mode is top-right
4279 if ( rParam.meVerJust == SVX_VER_JUSTIFY_STANDARD )
4280 rParam.meVerJust = SVX_VER_JUSTIFY_TOP;
4282 rParam.setPatternToEngine(mbUseStyleColor);
4283 rParam.setAlignmentToEngine();
4285 // Read content from cell
4287 bool bWrapFields = false;
4288 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
4289 // Failed to read cell content. Bail out.
4290 return;
4292 if ( mbSyntaxMode )
4293 SetEditSyntaxColor( *rParam.mpEngine, rParam.mpCell );
4294 else if ( mbUseStyleColor && mbForceAutoColor )
4295 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
4297 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
4300 // Get final output area using the calculated width
4303 long nEngineWidth, nEngineHeight;
4304 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
4306 long nNeededPixel = nEngineWidth;
4307 if (rParam.mbPixelToLogic)
4308 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
4309 nNeededPixel += nLeftM + nRightM;
4311 // for break, the first GetOutputArea call is sufficient
4312 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
4313 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
4314 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
4316 if ( bShrink )
4318 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
4319 nLeftM, nTopM, nRightM, nBottomM, false,
4320 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
4321 nEngineWidth, nEngineHeight, nNeededPixel,
4322 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
4324 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
4326 // First check if twice the space for the formatted text is available
4327 // (otherwise just keep it unchanged).
4329 long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
4330 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
4331 if ( nAvailable >= 2 * nFormatted )
4333 // "repeat" is handled with unformatted text (for performance reasons)
4334 String aCellStr = rParam.mpEngine->GetText();
4335 rParam.mpEngine->SetText( aCellStr );
4337 long nRepeatSize = (long) rParam.mpEngine->CalcTextWidth();
4338 if (rParam.mbPixelToLogic)
4339 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
4340 if ( pFmtDevice != mpRefDevice )
4341 ++nRepeatSize;
4342 if ( nRepeatSize > 0 )
4344 long nRepeatCount = nAvailable / nRepeatSize;
4345 if ( nRepeatCount > 1 )
4347 String aRepeated = aCellStr;
4348 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
4349 aRepeated.Append( aCellStr );
4350 rParam.mpEngine->SetText( aRepeated );
4352 nEngineHeight = rParam.mpEngine->GetTextHeight();
4353 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
4354 if (rParam.mbPixelToLogic)
4355 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
4356 else
4357 nNeededPixel = nEngineWidth;
4358 nNeededPixel += nLeftM + nRightM;
4364 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
4366 rParam.mpEngine->SetText(rtl::OUString("###"));
4367 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
4368 if (rParam.mbPixelToLogic)
4369 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
4370 else
4371 nNeededPixel = nEngineWidth;
4372 nNeededPixel += nLeftM + nRightM;
4374 // No clip marks if "###" doesn't fit (same as in DrawStrings)
4377 if (eOutHorJust != SVX_HOR_JUSTIFY_LEFT)
4379 aPaperSize.Width() = nNeededPixel + 1;
4380 if (rParam.mbPixelToLogic)
4381 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4382 else
4383 rParam.mpEngine->SetPaperSize(aPaperSize);
4386 long nStartX = aAreaParam.maAlignRect.Left();
4387 long nStartY = aAreaParam.maAlignRect.Top();
4388 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
4389 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
4390 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
4392 // text with automatic breaks is aligned only within the
4393 // edit engine's paper size, the output of the whole area
4394 // is always left-aligned
4396 nStartX += nLeftM;
4398 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
4399 if (bOutside)
4400 return;
4402 if ( aAreaParam.maClipRect.Left() < nScrX )
4404 aAreaParam.maClipRect.Left() = nScrX;
4405 aAreaParam.mbLeftClip = true;
4407 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
4409 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
4410 aAreaParam.mbRightClip = true;
4413 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
4414 bool bSimClip = false;
4416 if ( bWrapFields )
4418 // Fields in a cell with automatic breaks: clip to cell width
4419 bClip = true;
4422 if ( aAreaParam.maClipRect.Top() < nScrY )
4424 aAreaParam.maClipRect.Top() = nScrY;
4425 bClip = true;
4427 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
4429 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
4430 bClip = true;
4433 Size aCellSize; // output area, excluding margins, in logical units
4434 if (rParam.mbPixelToLogic)
4435 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
4436 else
4437 aCellSize = Size( nOutWidth, nOutHeight );
4439 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
4441 const ScMergeAttr* pMerge =
4442 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
4443 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4445 // Don't clip for text height when printing rows with optimal height,
4446 // except when font size is from conditional formatting.
4447 //! Allow clipping when vertically merged?
4448 if ( eType != OUTTYPE_PRINTER ||
4449 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
4450 ( rParam.mpCondSet && SFX_ITEM_SET ==
4451 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
4452 bClip = true;
4453 else
4454 bSimClip = true;
4456 // Show clip marks if height is at least 5pt too small and
4457 // there are several lines of text.
4458 // Not for asian vertical text, because that would interfere
4459 // with the default right position of the text.
4460 // Only with automatic line breaks, to avoid having to find
4461 // the cells with the horizontal end of the text again.
4462 if ( nEngineHeight - aCellSize.Height() > 100 &&
4463 ( rParam.mbBreak || rParam.meOrient == SVX_ORIENTATION_STACKED ) &&
4464 !rParam.mbAsianVertical && bMarkClipped &&
4465 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
4467 CellInfo* pClipMarkCell = NULL;
4468 if ( bMerged )
4470 // anywhere in the merged area...
4471 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
4472 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
4474 else
4475 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
4477 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
4478 bAnyClipped = true;
4480 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
4481 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
4482 aAreaParam.maClipRect.Right() -= nMarkPixel;
4486 Rectangle aLogicClip;
4487 if (bClip || bSimClip)
4489 // Clip marks are already handled in GetOutputArea
4491 if (rParam.mbPixelToLogic)
4492 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
4493 else
4494 aLogicClip = aAreaParam.maClipRect;
4496 if (bClip) // bei bSimClip nur aClipRect initialisieren
4498 if (bMetaFile)
4500 mpDev->Push();
4501 mpDev->IntersectClipRegion( aLogicClip );
4503 else
4504 mpDev->SetClipRegion( Region( aLogicClip ) );
4508 Point aLogicStart;
4509 if (rParam.mbPixelToLogic)
4510 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
4511 else
4512 aLogicStart = Point(nStartX, nStartY);
4514 long nAvailWidth = aCellSize.Width();
4515 // space for AutoFilter is already handled in GetOutputArea
4517 // horizontal alignment
4519 if (rParam.meHorJust==SVX_HOR_JUSTIFY_RIGHT)
4520 aLogicStart.X() += nAvailWidth - nEngineWidth;
4521 else if (rParam.meHorJust==SVX_HOR_JUSTIFY_CENTER)
4522 aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2;
4524 // paper size is subtracted below
4525 aLogicStart.X() += nEngineWidth;
4527 // vertical adjustment is within the EditEngine
4528 if (rParam.mbPixelToLogic)
4529 aLogicStart.Y() += mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
4530 else
4531 aLogicStart.Y() += nTopM;
4533 Point aURLStart = aLogicStart; // copy before modifying for orientation
4535 rParam.adjustForRTL();
4537 // bMoveClipped handling has been replaced by complete alignment
4538 // handling (also extending to the left).
4540 // with SetVertical, the start position is top left of
4541 // the whole output area, not the text itself
4542 aLogicStart.X() -= rParam.mpEngine->GetPaperSize().Width();
4544 rParam.mpEngine->Draw(mpDev, aLogicStart, 0);
4546 if (bClip)
4548 if (bMetaFile)
4549 mpDev->Pop();
4550 else
4551 mpDev->SetClipRegion();
4554 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
4557 void ScOutputData::DrawEdit(sal_Bool bPixelToLogic)
4559 ScFieldEditEngine* pEngine = NULL;
4560 bool bHyphenatorSet = false;
4561 const ScPatternAttr* pOldPattern = NULL;
4562 const SfxItemSet* pOldCondSet = NULL;
4563 ScBaseCell* pCell = NULL;
4565 long nInitPosX = nScrX;
4566 if ( bLayoutRTL )
4568 nInitPosX += nMirrorW - 1;
4570 long nLayoutSign = bLayoutRTL ? -1 : 1;
4572 //! store nLastContentCol as member!
4573 SCCOL nLastContentCol = MAXCOL;
4574 if ( nX2 < MAXCOL )
4575 nLastContentCol = sal::static_int_cast<SCCOL>(
4576 nLastContentCol - mpDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) );
4578 long nRowPosY = nScrY;
4579 for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 fuer Reste von zusammengefassten
4581 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
4583 if (nArrY==1) nRowPosY = nScrY; // vorher wird einzeln berechnet
4585 if ( pThisRowInfo->bChanged || nArrY==0 )
4587 long nPosX = 0;
4588 for (SCCOL nX=0; nX<=nX2; nX++) // wegen Ueberhaengen
4590 if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually
4592 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
4593 if (pInfo->bEditEngine)
4595 SCROW nY = pThisRowInfo->nRowNo;
4597 SCCOL nCellX = nX; // position where the cell really starts
4598 SCROW nCellY = nY;
4599 sal_Bool bDoCell = false;
4601 long nPosY = nRowPosY;
4602 if ( nArrY == 0 )
4604 nPosY = nScrY;
4605 nY = pRowInfo[1].nRowNo;
4606 SCCOL nOverX; // start of the merged cells
4607 SCROW nOverY;
4608 if (GetMergeOrigin( nX,nY, 1, nOverX,nOverY, sal_True ))
4610 nCellX = nOverX;
4611 nCellY = nOverY;
4612 bDoCell = sal_True;
4615 else if ( nX == nX2 && !pThisRowInfo->pCellInfo[nX+1].pCell )
4617 // Rest of a long text further to the right?
4619 SCCOL nTempX=nX;
4620 while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
4621 ++nTempX;
4623 if ( nTempX > nX &&
4624 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
4625 !mpDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
4627 nCellX = nTempX;
4628 bDoCell = sal_True;
4631 else
4633 bDoCell = sal_True;
4636 if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
4637 bDoCell = false;
4639 const ScPatternAttr* pPattern = NULL;
4640 const SfxItemSet* pCondSet = NULL;
4641 if (bDoCell)
4643 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 &&
4644 !mpDoc->ColHidden(nCellX, nTab) )
4646 CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1];
4647 pPattern = rCellInfo.pPatternAttr;
4648 pCondSet = rCellInfo.pConditionSet;
4649 pCell = rCellInfo.pCell;
4651 else // get from document
4653 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
4654 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
4655 GetVisibleCell( nCellX, nCellY, nTab, pCell );
4657 if ( !pCell )
4658 bDoCell = false;
4660 if (bDoCell)
4662 if (!pEngine)
4663 pEngine = CreateOutputEditEngine();
4664 else
4665 lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False)
4667 // fdo#32530: Check if the first character is RTL.
4668 rtl::OUString aStr = mpDoc->GetString(nCellX, nCellY, nTab);
4670 DrawEditParam aParam(pPattern, pCondSet, lcl_SafeIsValue(pCell));
4671 aParam.mbPixelToLogic = bPixelToLogic;
4672 aParam.mbHyphenatorSet = bHyphenatorSet;
4673 aParam.mbRTL = beginsWithRTLCharacter(aStr);
4674 aParam.mpEngine = pEngine;
4675 aParam.mpCell = pCell;
4676 aParam.mnArrY = nArrY;
4677 aParam.mnX = nX;
4678 aParam.mnY = nY;
4679 aParam.mnCellX = nCellX;
4680 aParam.mnCellY = nCellY;
4681 aParam.mnPosX = nPosX;
4682 aParam.mnPosY = nPosY;
4683 aParam.mnInitPosX = nInitPosX;
4684 aParam.mpOldPattern = pOldPattern;
4685 aParam.mpOldCondSet = pOldCondSet;
4686 aParam.mpThisRowInfo = pThisRowInfo;
4687 if (aParam.meHorJust == SVX_HOR_JUSTIFY_REPEAT)
4689 // ignore orientation/rotation if "repeat" is active
4690 aParam.meOrient = SVX_ORIENTATION_STANDARD;
4692 switch (aParam.meOrient)
4694 case SVX_ORIENTATION_BOTTOMTOP:
4695 DrawEditBottomTop(aParam);
4696 break;
4697 case SVX_ORIENTATION_TOPBOTTOM:
4698 DrawEditTopBottom(aParam);
4699 break;
4700 case SVX_ORIENTATION_STACKED:
4701 // this can be vertically stacked or asian vertical.
4702 DrawEditStacked(aParam);
4703 break;
4704 default:
4705 DrawEditStandard(aParam);
4708 // Retrieve parameters for next iteration.
4709 pOldPattern = aParam.mpOldPattern;
4710 pOldCondSet = aParam.mpOldCondSet;
4711 bHyphenatorSet = aParam.mbHyphenatorSet;
4714 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
4717 nRowPosY += pRowInfo[nArrY].nHeight;
4720 delete pEngine;
4722 if (bAnyRotated)
4723 DrawRotated(bPixelToLogic); //! von aussen rufen ?
4726 // -------------------------------------------------------------------------------
4728 void ScOutputData::DrawRotated(sal_Bool bPixelToLogic)
4730 //! nRotMax speichern
4731 SCCOL nRotMax = nX2;
4732 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
4733 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
4734 nRotMax = pRowInfo[nRotY].nRotMaxCol;
4737 ScModule* pScMod = SC_MOD();
4738 sal_Int32 nConfBackColor = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
4739 sal_Bool bCellContrast = mbUseStyleColor &&
4740 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
4742 ScFieldEditEngine* pEngine = NULL;
4743 sal_Bool bHyphenatorSet = false;
4744 const ScPatternAttr* pPattern;
4745 const SfxItemSet* pCondSet;
4746 const ScPatternAttr* pOldPattern = NULL;
4747 const SfxItemSet* pOldCondSet = NULL;
4748 ScBaseCell* pCell = NULL;
4750 long nInitPosX = nScrX;
4751 if ( bLayoutRTL )
4753 nInitPosX += nMirrorW - 1;
4755 long nLayoutSign = bLayoutRTL ? -1 : 1;
4757 long nRowPosY = nScrY;
4758 for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 fuer Reste von zusammengefassten
4760 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
4761 long nCellHeight = (long) pThisRowInfo->nHeight;
4762 if (nArrY==1) nRowPosY = nScrY; // vorher wird einzeln berechnet
4764 if ( ( pThisRowInfo->bChanged || nArrY==0 ) && pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE )
4766 long nPosX = 0;
4767 for (SCCOL nX=0; nX<=nRotMax; nX++)
4769 if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually
4771 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
4772 if ( pInfo->nRotateDir != SC_ROTDIR_NONE )
4774 SCROW nY = pThisRowInfo->nRowNo;
4776 sal_Bool bHidden = false;
4777 if (bEditMode)
4778 if ( nX == nEditCol && nY == nEditRow )
4779 bHidden = sal_True;
4781 if (!bHidden)
4783 if (!pEngine)
4784 pEngine = CreateOutputEditEngine();
4785 else
4786 lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False)
4788 long nPosY = nRowPosY;
4789 sal_Bool bVisChanged = false;
4791 //! Rest von zusammengefasster Zelle weiter oben funktioniert nicht!
4793 sal_Bool bFromDoc = false;
4794 pPattern = pInfo->pPatternAttr;
4795 pCondSet = pInfo->pConditionSet;
4796 if (!pPattern)
4798 pPattern = mpDoc->GetPattern( nX, nY, nTab );
4799 bFromDoc = sal_True;
4801 pCell = pInfo->pCell;
4802 if (bFromDoc)
4803 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
4805 if (!pCell && nX>nX2)
4806 GetVisibleCell( nX, nY, nTab, pCell );
4808 if ( !pCell || IsEmptyCellText( pThisRowInfo, nX, nY ) )
4809 bHidden = sal_True; // nRotateDir is also set without a cell
4811 long nCellWidth = (long) pRowInfo[0].pCellInfo[nX+1].nWidth;
4813 SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
4814 pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet)).GetValue();
4815 sal_Bool bBreak = ( eHorJust == SVX_HOR_JUSTIFY_BLOCK ) ||
4816 ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue();
4817 sal_Bool bRepeat = ( eHorJust == SVX_HOR_JUSTIFY_REPEAT && !bBreak );
4818 sal_Bool bShrink = !bBreak && !bRepeat && static_cast<const SfxBoolItem&>
4819 (pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
4820 SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
4822 const ScMergeAttr* pMerge =
4823 (ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
4824 sal_Bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4826 long nStartX = nPosX;
4827 long nStartY = nPosY;
4828 if (nX<nX1)
4830 if ((bBreak || eOrient!=SVX_ORIENTATION_STANDARD) && !bMerged)
4831 bHidden = sal_True;
4832 else
4834 nStartX = nInitPosX;
4835 SCCOL nCol = nX1;
4836 while (nCol > nX)
4838 --nCol;
4839 nStartX -= nLayoutSign * (long) pRowInfo[0].pCellInfo[nCol+1].nWidth;
4843 long nCellStartX = nStartX;
4845 // Ersatzdarstellung fuer zu kleinen Text weggelassen
4847 if (!bHidden)
4849 long nOutWidth = nCellWidth - 1;
4850 long nOutHeight = nCellHeight;
4852 if ( bMerged ) // Zusammengefasst
4854 SCCOL nCountX = pMerge->GetColMerge();
4855 for (SCCOL i=1; i<nCountX; i++)
4856 nOutWidth += (long) ( mpDoc->GetColWidth(nX+i,nTab) * mnPPTX );
4857 SCROW nCountY = pMerge->GetRowMerge();
4858 nOutHeight += (long) mpDoc->GetScaledRowHeight( nY+1, nY+nCountY-1, nTab, mnPPTY);
4861 SvxCellVerJustify eVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&)
4862 pPattern->GetItem(ATTR_VER_JUSTIFY, pCondSet)).GetValue();
4864 // Syntax-Modus wird hier ignoriert...
4866 // StringDiffer doesn't look at hyphenate, language items
4867 if ( pPattern != pOldPattern || pCondSet != pOldCondSet )
4869 SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
4870 pPattern->FillEditItemSet( pSet, pCondSet );
4872 // Ausrichtung fuer EditEngine
4873 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
4874 if (eOrient==SVX_ORIENTATION_STACKED)
4875 eSvxAdjust = SVX_ADJUST_CENTER;
4876 // Adjustment fuer bBreak ist hier weggelassen
4877 pSet->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
4879 pEngine->SetDefaults( pSet );
4880 pOldPattern = pPattern;
4881 pOldCondSet = pCondSet;
4883 sal_uLong nControl = pEngine->GetControlWord();
4884 if (eOrient==SVX_ORIENTATION_STACKED)
4885 nControl |= EE_CNTRL_ONECHARPERLINE;
4886 else
4887 nControl &= ~EE_CNTRL_ONECHARPERLINE;
4888 pEngine->SetControlWord( nControl );
4890 if ( !bHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() )
4892 // set hyphenator the first time it is needed
4893 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
4894 pEngine->SetHyphenator( xXHyphenator );
4895 bHyphenatorSet = sal_True;
4898 Color aBackCol = ((const SvxBrushItem&)
4899 pPattern->GetItem( ATTR_BACKGROUND, pCondSet )).GetColor();
4900 if ( mbUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) )
4901 aBackCol.SetColor( nConfBackColor );
4902 pEngine->SetBackgroundColor( aBackCol );
4905 // Raender
4907 //! Position und Papersize auf EditUtil umstellen !!!
4909 const SvxMarginItem* pMargin = (const SvxMarginItem*)
4910 &pPattern->GetItem(ATTR_MARGIN, pCondSet);
4911 sal_uInt16 nIndent = 0;
4912 if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
4913 nIndent = ((const SfxUInt16Item&)pPattern->
4914 GetItem(ATTR_INDENT, pCondSet)).GetValue();
4916 long nTotalHeight = nOutHeight; // ohne Rand abzuziehen
4917 if ( bPixelToLogic )
4918 nTotalHeight = mpRefDevice->PixelToLogic(Size(0,nTotalHeight)).Height();
4920 long nLeftM = (long) ( (pMargin->GetLeftMargin() + nIndent) * mnPPTX );
4921 long nTopM = (long) ( pMargin->GetTopMargin() * mnPPTY );
4922 long nRightM = (long) ( pMargin->GetRightMargin() * mnPPTX );
4923 long nBottomM = (long) ( pMargin->GetBottomMargin() * mnPPTY );
4924 nStartX += nLeftM;
4925 nStartY += nTopM;
4926 nOutWidth -= nLeftM + nRightM;
4927 nOutHeight -= nTopM + nBottomM;
4929 // Rotation schon hier, um bei Umbruch auch PaperSize anzupassen
4930 long nAttrRotate = 0;
4931 double nSin = 0.0;
4932 double nCos = 1.0;
4933 SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
4934 if ( eOrient == SVX_ORIENTATION_STANDARD )
4936 nAttrRotate = ((const SfxInt32Item&)pPattern->
4937 GetItem(ATTR_ROTATE_VALUE, pCondSet)).GetValue();
4938 if ( nAttrRotate )
4940 eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
4941 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
4943 if ( nAttrRotate == 18000 )
4944 eRotMode = SVX_ROTATE_MODE_STANDARD; // keinen Ueberlauf
4946 if ( bLayoutRTL )
4947 nAttrRotate = -nAttrRotate;
4949 double nRealOrient = nAttrRotate * F_PI18000; // 1/100 Grad
4950 nCos = cos( nRealOrient );
4951 nSin = sin( nRealOrient );
4955 Size aPaperSize = Size( 1000000, 1000000 );
4956 if (eOrient==SVX_ORIENTATION_STACKED)
4957 aPaperSize.Width() = nOutWidth; // zum Zentrieren
4958 else if (bBreak)
4960 if (nAttrRotate)
4962 //! richtige PaperSize fuer Umbruch haengt von der Zeilenzahl
4963 //! ab, solange die Zeilen nicht einzeln versetzt ausgegeben
4964 //! werden koennen -> darum unbegrenzt, also kein Umbruch.
4965 //! Mit versetzten Zeilen waere das folgende richtig:
4966 aPaperSize.Width() = (long)(nOutHeight / fabs(nSin));
4968 else if (eOrient == SVX_ORIENTATION_STANDARD)
4969 aPaperSize.Width() = nOutWidth;
4970 else
4971 aPaperSize.Width() = nOutHeight - 1;
4973 if (bPixelToLogic)
4974 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4975 else
4976 pEngine->SetPaperSize(aPaperSize); // Scale ist immer 1
4978 // Daten aus Zelle lesen
4980 if (pCell)
4982 if (pCell->GetCellType() == CELLTYPE_EDIT)
4984 const EditTextObject* pData;
4985 ((ScEditCell*)pCell)->GetData(pData);
4987 if (pData)
4988 pEngine->SetText(*pData);
4989 else
4991 OSL_FAIL("pData == 0");
4994 else
4996 sal_uLong nFormat = pPattern->GetNumberFormat(
4997 mpDoc->GetFormatTable(), pCondSet );
4998 rtl::OUString aString;
4999 Color* pColor;
5000 ScCellFormat::GetString( pCell,
5001 nFormat,aString, &pColor,
5002 *mpDoc->GetFormatTable(),
5003 mbShowNullValues,
5004 mbShowFormulas,
5005 ftCheck );
5007 pEngine->SetText(aString);
5008 if ( pColor && !mbSyntaxMode && !( mbUseStyleColor && mbForceAutoColor ) )
5009 lcl_SetEditColor( *pEngine, *pColor );
5012 if ( mbSyntaxMode )
5013 SetEditSyntaxColor( *pEngine, pCell );
5014 else if ( mbUseStyleColor && mbForceAutoColor )
5015 lcl_SetEditColor( *pEngine, COL_AUTO ); //! or have a flag at EditEngine
5017 else
5019 OSL_FAIL("pCell == NULL");
5022 pEngine->SetUpdateMode( sal_True ); // after SetText, before CalcTextWidth/GetTextHeight
5024 long nEngineWidth = (long) pEngine->CalcTextWidth();
5025 long nEngineHeight = pEngine->GetTextHeight();
5027 if (nAttrRotate && bBreak)
5029 double nAbsCos = fabs( nCos );
5030 double nAbsSin = fabs( nSin );
5032 // adjust witdh of papersize for height of text
5033 int nSteps = 5;
5034 while (nSteps > 0)
5036 // everything is in pixels
5037 long nEnginePixel = mpRefDevice->LogicToPixel(
5038 Size(0,nEngineHeight)).Height();
5039 long nEffHeight = nOutHeight - (long)(nEnginePixel * nAbsCos) + 2;
5040 long nNewWidth = (long)(nEffHeight / nAbsSin) + 2;
5041 sal_Bool bFits = ( nNewWidth >= aPaperSize.Width() );
5042 if ( bFits )
5043 nSteps = 0;
5044 else
5046 if ( nNewWidth < 4 )
5048 // can't fit -> fall back to using half height
5049 nEffHeight = nOutHeight / 2;
5050 nNewWidth = (long)(nEffHeight / nAbsSin) + 2;
5051 nSteps = 0;
5053 else
5054 --nSteps;
5056 // set paper width and get new text height
5057 aPaperSize.Width() = nNewWidth;
5058 if (bPixelToLogic)
5059 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
5060 else
5061 pEngine->SetPaperSize(aPaperSize); // Scale ist immer 1
5062 //pEngine->QuickFormatDoc( sal_True );
5063 nEngineWidth = (long) pEngine->CalcTextWidth();
5064 nEngineHeight = pEngine->GetTextHeight();
5069 long nRealWidth = nEngineWidth;
5070 long nRealHeight = nEngineHeight;
5072 // wenn gedreht, Groesse anpassen
5073 if (nAttrRotate)
5075 double nAbsCos = fabs( nCos );
5076 double nAbsSin = fabs( nSin );
5078 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
5079 nEngineWidth = (long) ( nRealWidth * nAbsCos +
5080 nRealHeight * nAbsSin );
5081 else
5082 nEngineWidth = (long) ( nRealHeight / nAbsSin );
5083 //! begrenzen !!!
5085 nEngineHeight = (long) ( nRealHeight * nAbsCos +
5086 nRealWidth * nAbsSin );
5089 if (!nAttrRotate) // hier nur gedrehter Text
5090 bHidden = sal_True; //! vorher abfragen !!!
5092 //! weglassen, was nicht hereinragt
5094 if (!bHidden)
5096 sal_Bool bClip = false;
5097 Size aClipSize = Size( nScrX+nScrW-nStartX, nScrY+nScrH-nStartY );
5099 // weiterschreiben
5101 Size aCellSize;
5102 if (bPixelToLogic)
5103 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
5104 else
5105 aCellSize = Size( nOutWidth, nOutHeight ); // Scale ist 1
5107 long nGridWidth = nEngineWidth;
5108 sal_Bool bNegative = false;
5109 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5111 nGridWidth = aCellSize.Width() +
5112 Abs((long) ( aCellSize.Height() * nCos / nSin ));
5113 bNegative = ( pInfo->nRotateDir == SC_ROTDIR_LEFT );
5114 if ( bLayoutRTL )
5115 bNegative = !bNegative;
5118 // use GetOutputArea to hide the grid
5119 // (clip region is done manually below)
5120 OutputAreaParam aAreaParam;
5122 SCCOL nCellX = nX;
5123 SCROW nCellY = nY;
5124 SvxCellHorJustify eOutHorJust = eHorJust;
5125 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5126 eOutHorJust = bNegative ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT;
5127 long nNeededWidth = nGridWidth; // in pixel for GetOutputArea
5128 if ( bPixelToLogic )
5129 nNeededWidth = mpRefDevice->LogicToPixel(Size(nNeededWidth,0)).Width();
5131 GetOutputArea( nX, nArrY, nCellStartX, nPosY, nCellX, nCellY, nNeededWidth,
5132 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
5133 false, false, sal_True, aAreaParam );
5135 if ( bShrink )
5137 long nPixelWidth = bPixelToLogic ?
5138 mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width() : nEngineWidth;
5139 long nNeededPixel = nPixelWidth + nLeftM + nRightM;
5141 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = sal_True;
5143 // always do height
5144 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
5145 false, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic,
5146 nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
5148 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
5150 // do width only if rotating within the cell (standard mode)
5151 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
5152 sal_True, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic,
5153 nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
5156 // nEngineWidth/nEngineHeight is updated in ShrinkEditEngine
5157 // (but width is only valid for standard mode)
5158 nRealWidth = (long) pEngine->CalcTextWidth();
5159 nRealHeight = pEngine->GetTextHeight();
5161 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5162 nEngineWidth = (long) ( nRealHeight / fabs( nSin ) );
5165 long nClipStartX = nStartX;
5166 if (nX<nX1)
5168 //! Clipping unnoetig, wenn links am Fenster
5170 bClip = sal_True; // nur Rest ausgeben!
5171 if (nStartX<nScrX)
5173 long nDif = nScrX - nStartX;
5174 nClipStartX = nScrX;
5175 aClipSize.Width() -= nDif;
5179 long nClipStartY = nStartY;
5180 if (nArrY==0 || bVisChanged)
5182 if ( nClipStartY < nRowPosY )
5184 long nDif = nRowPosY - nClipStartY;
5185 bClip = sal_True;
5186 nClipStartY = nRowPosY;
5187 aClipSize.Height() -= nDif;
5191 bClip = sal_True; // always clip at the window/page border
5193 //Rectangle aClipRect;
5194 if (bClip)
5196 if ( nAttrRotate /* && eRotMode != SVX_ROTATE_MODE_STANDARD */ )
5198 // gedrehten, ausgerichteten Text nur an den
5199 // Seitengrenzen clippen
5200 nClipStartX = nScrX;
5201 aClipSize.Width() = nScrW;
5204 if (bPixelToLogic)
5205 aAreaParam.maClipRect = mpRefDevice->PixelToLogic( Rectangle(
5206 Point(nClipStartX,nClipStartY), aClipSize ) );
5207 else
5208 aAreaParam.maClipRect = Rectangle(Point(nClipStartX, nClipStartY),
5209 aClipSize ); // Scale = 1
5211 if (bMetaFile)
5213 mpDev->Push();
5214 mpDev->IntersectClipRegion( aAreaParam.maClipRect );
5216 else
5217 mpDev->SetClipRegion( Region( aAreaParam.maClipRect ) );
5220 Point aLogicStart;
5221 if (bPixelToLogic)
5222 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
5223 else
5224 aLogicStart = Point(nStartX, nStartY);
5225 if ( eOrient!=SVX_ORIENTATION_STANDARD || !bBreak )
5227 long nAvailWidth = aCellSize.Width();
5228 if (eType==OUTTYPE_WINDOW &&
5229 eOrient!=SVX_ORIENTATION_STACKED &&
5230 pInfo && pInfo->bAutoFilter)
5232 // filter drop-down width is now independent from row height
5233 if (bPixelToLogic)
5234 nAvailWidth -= mpRefDevice->PixelToLogic(Size(0,DROPDOWN_BITMAP_SIZE)).Height();
5235 else
5236 nAvailWidth -= DROPDOWN_BITMAP_SIZE;
5237 long nComp = nEngineWidth;
5238 if (nAvailWidth<nComp) nAvailWidth=nComp;
5241 // horizontale Ausrichtung
5243 if (eOrient==SVX_ORIENTATION_STANDARD && !nAttrRotate)
5245 if (eHorJust==SVX_HOR_JUSTIFY_RIGHT ||
5246 eHorJust==SVX_HOR_JUSTIFY_CENTER)
5248 pEngine->SetUpdateMode( false );
5250 SvxAdjust eSvxAdjust =
5251 (eHorJust==SVX_HOR_JUSTIFY_RIGHT) ?
5252 SVX_ADJUST_RIGHT : SVX_ADJUST_CENTER;
5253 pEngine->SetDefaultItem(
5254 SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
5256 aPaperSize.Width() = nOutWidth;
5257 if (bPixelToLogic)
5258 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
5259 else
5260 pEngine->SetPaperSize(aPaperSize);
5262 pEngine->SetUpdateMode( sal_True );
5265 else
5267 // bei gedrehtem Text ist Standard zentriert
5268 if (eHorJust==SVX_HOR_JUSTIFY_RIGHT)
5269 aLogicStart.X() += nAvailWidth - nEngineWidth;
5270 else if (eHorJust==SVX_HOR_JUSTIFY_CENTER ||
5271 eHorJust==SVX_HOR_JUSTIFY_STANDARD)
5272 aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2;
5276 if ( bLayoutRTL )
5278 if (bPixelToLogic)
5279 aLogicStart.X() -= mpRefDevice->PixelToLogic(
5280 Size( nCellWidth, 0 ) ).Width();
5281 else
5282 aLogicStart.X() -= nCellWidth;
5285 if ( eOrient==SVX_ORIENTATION_STANDARD ||
5286 eOrient==SVX_ORIENTATION_STACKED || !bBreak )
5288 if (eVerJust==SVX_VER_JUSTIFY_BOTTOM ||
5289 eVerJust==SVX_VER_JUSTIFY_STANDARD)
5291 if (bPixelToLogic)
5292 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0,
5293 mpRefDevice->LogicToPixel(aCellSize).Height() -
5294 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
5295 )).Height();
5296 else
5297 aLogicStart.Y() += aCellSize.Height() - nEngineHeight;
5300 else if (eVerJust==SVX_VER_JUSTIFY_CENTER)
5302 if (bPixelToLogic)
5303 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0,(
5304 mpRefDevice->LogicToPixel(aCellSize).Height() -
5305 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height())
5306 / 2)).Height();
5307 else
5308 aLogicStart.Y() += (aCellSize.Height() - nEngineHeight) / 2;
5312 // TOPBOTTON and BOTTOMTOP are handled in DrawStrings/DrawEdit
5313 OSL_ENSURE( eOrient == SVX_ORIENTATION_STANDARD && nAttrRotate,
5314 "DrawRotated: no rotation" );
5316 long nOriVal = 0;
5317 if ( nAttrRotate )
5319 // Attribut ist 1/100, Font 1/10 Grad
5320 nOriVal = nAttrRotate / 10;
5322 double nAddX = 0.0;
5323 double nAddY = 0.0;
5324 if ( nCos > 0.0 && eRotMode != SVX_ROTATE_MODE_STANDARD )
5326 //! begrenzen !!!
5327 double nH = nRealHeight * nCos;
5328 nAddX += nH * ( nCos / fabs(nSin) );
5330 if ( nCos < 0.0 && eRotMode == SVX_ROTATE_MODE_STANDARD )
5331 nAddX -= nRealWidth * nCos;
5332 if ( nSin < 0.0 )
5333 nAddX -= nRealHeight * nSin;
5334 if ( nSin > 0.0 )
5335 nAddY += nRealWidth * nSin;
5336 if ( nCos < 0.0 )
5337 nAddY -= nRealHeight * nCos;
5339 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5341 //! begrenzen !!!
5342 double nSkew = nTotalHeight * nCos / fabs(nSin);
5343 if ( eRotMode == SVX_ROTATE_MODE_CENTER )
5344 nAddX -= nSkew * 0.5;
5345 if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nSin > 0.0 ) ||
5346 ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nSin < 0.0 ) )
5347 nAddX -= nSkew;
5349 long nUp = 0;
5350 if ( eVerJust == SVX_VER_JUSTIFY_CENTER )
5351 nUp = ( aCellSize.Height() - nEngineHeight ) / 2;
5352 else if ( eVerJust == SVX_VER_JUSTIFY_TOP )
5354 if ( nSin > 0.0 )
5355 nUp = aCellSize.Height() - nEngineHeight;
5357 else // BOTTOM / STANDARD
5359 if ( nSin < 0.0 )
5360 nUp = aCellSize.Height() - nEngineHeight;
5362 if ( nUp )
5363 nAddX += ( nUp * nCos / fabs(nSin) );
5366 aLogicStart.X() += (long) nAddX;
5367 aLogicStart.Y() += (long) nAddY;
5370 // bSimClip is not used here (because nOriVal is set)
5372 if ( pEngine->IsRightToLeft( 0 ) )
5374 // For right-to-left, EditEngine always calculates its lines
5375 // beginning from the right edge, but EditLine::nStartPosX is
5376 // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX.
5377 Size aLogicPaper = pEngine->GetPaperSize();
5378 if ( aLogicPaper.Width() > USHRT_MAX )
5380 aLogicPaper.Width() = USHRT_MAX;
5381 pEngine->SetPaperSize(aLogicPaper);
5385 pEngine->Draw( mpDev, aLogicStart, (short)nOriVal );
5387 if (bClip)
5389 if (bMetaFile)
5390 mpDev->Pop();
5391 else
5392 mpDev->SetClipRegion();
5398 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
5401 nRowPosY += pRowInfo[nArrY].nHeight;
5404 delete pEngine;
5409 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */