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