| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sc.hxx" |
| |
| |
| |
| |
| // INCLUDE --------------------------------------------------------------- |
| |
| #include "scitems.hxx" |
| #include <editeng/eeitem.hxx> |
| |
| |
| #include <editeng/adjitem.hxx> |
| #include <svx/algitem.hxx> |
| #include <editeng/brshitem.hxx> |
| #include <svtools/colorcfg.hxx> |
| #include <editeng/colritem.hxx> |
| #include <editeng/editobj.hxx> |
| #include <editeng/editstat.hxx> |
| #include <editeng/fhgtitem.hxx> |
| #include <editeng/forbiddencharacterstable.hxx> |
| #include <editeng/frmdiritem.hxx> |
| #include <editeng/langitem.hxx> |
| #include <svx/rotmodit.hxx> |
| #include <editeng/scripttypeitem.hxx> |
| #include <editeng/udlnitem.hxx> |
| #include <editeng/unolingu.hxx> |
| #include <svl/zforlist.hxx> |
| #include <svl/zformat.hxx> |
| #include <vcl/svapp.hxx> |
| #include <vcl/metric.hxx> |
| #include <vcl/outdev.hxx> |
| #include <vcl/pdfextoutdevdata.hxx> |
| |
| #ifndef _SVSTDARR_USHORTS |
| #define _SVSTDARR_USHORTS |
| #include <svl/svstdarr.hxx> |
| #endif |
| |
| #include "output.hxx" |
| #include "document.hxx" |
| #include "cell.hxx" |
| #include "attrib.hxx" |
| #include "patattr.hxx" |
| #include "cellform.hxx" |
| #include "editutil.hxx" |
| #include "progress.hxx" |
| #include "scmod.hxx" |
| #include "fillinfo.hxx" |
| |
| #include <math.h> |
| |
| //! Autofilter-Breite mit column.cxx zusammenfassen |
| #define DROPDOWN_BITMAP_SIZE 18 |
| |
| #define DRAWTEXT_MAX 32767 |
| |
| const sal_uInt16 SC_SHRINKAGAIN_MAX = 7; |
| |
| // STATIC DATA ----------------------------------------------------------- |
| |
| |
| // ----------------------------------------------------------------------- |
| |
| class ScDrawStringsVars |
| { |
| ScOutputData* pOutput; // Verbindung |
| |
| const ScPatternAttr* pPattern; // Attribute |
| const SfxItemSet* pCondSet; // aus bedingter Formatierung |
| |
| Font aFont; // aus Attributen erzeugt |
| FontMetric aMetric; |
| long nAscentPixel; // always pixels |
| SvxCellOrientation eAttrOrient; |
| SvxCellHorJustify eAttrHorJust; |
| SvxCellVerJustify eAttrVerJust; |
| const SvxMarginItem* pMargin; |
| sal_uInt16 nIndent; |
| sal_Bool bRotated; |
| |
| String aString; // Inhalte |
| Size aTextSize; |
| long nOriginalWidth; |
| long nMaxDigitWidth; |
| long nSignWidth; |
| long nDotWidth; |
| long nExpWidth; |
| |
| ScBaseCell* pLastCell; |
| sal_uLong nValueFormat; |
| sal_Bool bLineBreak; |
| sal_Bool bRepeat; |
| sal_Bool bShrink; |
| |
| sal_Bool bPixelToLogic; |
| sal_Bool bCellContrast; |
| |
| Color aBackConfigColor; // used for ScPatternAttr::GetFont calls |
| Color aTextConfigColor; |
| |
| public: |
| ScDrawStringsVars(ScOutputData* pData, sal_Bool bPTL); |
| ~ScDrawStringsVars(); |
| |
| // SetPattern = ex-SetVars |
| // SetPatternSimple: ohne Font |
| |
| void SetPattern( const ScPatternAttr* pNew, const SfxItemSet* pSet, ScBaseCell* pCell, sal_uInt8 nScript ); |
| void SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet ); |
| |
| sal_Bool SetText( ScBaseCell* pCell ); // sal_True -> pOldPattern vergessen |
| void SetTextToWidthOrHash( ScBaseCell* pCell, long nWidth ); |
| void SetAutoText( const String& rAutoText ); |
| |
| const ScPatternAttr* GetPattern() const { return pPattern; } |
| SvxCellOrientation GetOrient() const { return eAttrOrient; } |
| SvxCellHorJustify GetHorJust() const { return eAttrHorJust; } |
| SvxCellVerJustify GetVerJust() const { return eAttrVerJust; } |
| const SvxMarginItem* GetMargin() const { return pMargin; } |
| |
| sal_uInt16 GetLeftTotal() const { return pMargin->GetLeftMargin() + nIndent; } |
| |
| const String& GetString() const { return aString; } |
| const Size& GetTextSize() const { return aTextSize; } |
| long GetOriginalWidth() const { return nOriginalWidth; } |
| |
| sal_uLong GetResultValueFormat( const ScBaseCell* pCell ) const; |
| |
| sal_uLong GetValueFormat() const { return nValueFormat; } |
| sal_Bool GetLineBreak() const { return bLineBreak; } |
| sal_Bool IsRepeat() const { return bRepeat; } |
| sal_Bool IsShrink() const { return bShrink; } |
| |
| long GetAscent() const { return nAscentPixel; } |
| sal_Bool IsRotated() const { return bRotated; } |
| |
| void SetShrinkScale( long nScale, sal_uInt8 nScript ); |
| |
| sal_Bool HasCondHeight() const { return pCondSet && SFX_ITEM_SET == |
| pCondSet->GetItemState( ATTR_FONT_HEIGHT, sal_True ); } |
| |
| sal_Bool HasEditCharacters() const; |
| |
| private: |
| void SetHashText(); |
| long GetMaxDigitWidth(); // in logic units |
| long GetSignWidth(); |
| long GetDotWidth(); |
| long GetExpWidth(); |
| void TextChanged(); |
| }; |
| |
| //================================================================== |
| |
| ScDrawStringsVars::ScDrawStringsVars(ScOutputData* pData, sal_Bool bPTL) : |
| pOutput ( pData ), |
| pPattern ( NULL ), |
| pCondSet ( NULL ), |
| eAttrOrient ( SVX_ORIENTATION_STANDARD ), |
| eAttrHorJust( SVX_HOR_JUSTIFY_STANDARD ), |
| eAttrVerJust( SVX_VER_JUSTIFY_BOTTOM ), |
| pMargin ( NULL ), |
| nIndent ( 0 ), |
| bRotated ( sal_False ), |
| nOriginalWidth( 0 ), |
| nMaxDigitWidth( 0 ), |
| nSignWidth( 0 ), |
| nDotWidth( 0 ), |
| nExpWidth( 0 ), |
| pLastCell ( NULL ), |
| nValueFormat( 0 ), |
| bLineBreak ( sal_False ), |
| bRepeat ( sal_False ), |
| bShrink ( sal_False ), |
| bPixelToLogic( bPTL ) |
| { |
| ScModule* pScMod = SC_MOD(); |
| // #105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True) |
| bCellContrast = pOutput->bUseStyleColor && |
| Application::GetSettings().GetStyleSettings().GetHighContrastMode(); |
| |
| const svtools::ColorConfig& rColorConfig = pScMod->GetColorConfig(); |
| aBackConfigColor.SetColor( rColorConfig.GetColorValue(svtools::DOCCOLOR).nColor ); |
| aTextConfigColor.SetColor( rColorConfig.GetColorValue(svtools::FONTCOLOR).nColor ); |
| } |
| |
| ScDrawStringsVars::~ScDrawStringsVars() |
| { |
| } |
| |
| void ScDrawStringsVars::SetShrinkScale( long nScale, sal_uInt8 nScript ) |
| { |
| // text remains valid, size is updated |
| |
| OutputDevice* pDev = pOutput->pDev; |
| OutputDevice* pRefDevice = pOutput->pRefDevice; |
| OutputDevice* pFmtDevice = pOutput->pFmtDevice; |
| |
| // call GetFont with a modified fraction, use only the height |
| |
| Fraction aFraction( nScale, 100 ); |
| if ( !bPixelToLogic ) |
| aFraction *= pOutput->aZoomY; |
| Font aTmpFont; |
| pPattern->GetFont( aTmpFont, SC_AUTOCOL_RAW, pFmtDevice, &aFraction, pCondSet, nScript ); |
| long nNewHeight = aTmpFont.GetHeight(); |
| if ( nNewHeight > 0 ) |
| aFont.SetHeight( nNewHeight ); |
| |
| // set font and dependent variables as in SetPattern |
| |
| pDev->SetFont( aFont ); |
| if ( pFmtDevice != pDev ) |
| pFmtDevice->SetFont( aFont ); |
| |
| aMetric = pFmtDevice->GetFontMetric(); |
| if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 ) |
| { |
| OutputDevice* pDefaultDev = Application::GetDefaultDevice(); |
| MapMode aOld = pDefaultDev->GetMapMode(); |
| pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() ); |
| aMetric = pDefaultDev->GetFontMetric( aFont ); |
| pDefaultDev->SetMapMode( aOld ); |
| } |
| |
| nAscentPixel = aMetric.GetAscent(); |
| if ( bPixelToLogic ) |
| nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height(); |
| |
| SetAutoText( aString ); // same text again, to get text size |
| } |
| |
| void ScDrawStringsVars::SetPattern( const ScPatternAttr* pNew, const SfxItemSet* pSet, |
| ScBaseCell* pCell, sal_uInt8 nScript ) |
| { |
| nMaxDigitWidth = 0; |
| nSignWidth = 0; |
| nDotWidth = 0; |
| nExpWidth = 0; |
| |
| pPattern = pNew; |
| pCondSet = pSet; |
| |
| // pPattern auswerten |
| |
| OutputDevice* pDev = pOutput->pDev; |
| OutputDevice* pRefDevice = pOutput->pRefDevice; |
| OutputDevice* pFmtDevice = pOutput->pFmtDevice; |
| |
| // Font |
| |
| ScAutoFontColorMode eColorMode; |
| if ( pOutput->bUseStyleColor ) |
| { |
| if ( pOutput->bForceAutoColor ) |
| eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREALL : SC_AUTOCOL_IGNOREFONT; |
| else |
| eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREBACK : SC_AUTOCOL_DISPLAY; |
| } |
| else |
| eColorMode = SC_AUTOCOL_PRINT; |
| |
| if ( bPixelToLogic ) |
| pPattern->GetFont( aFont, eColorMode, pFmtDevice, NULL, pCondSet, nScript, |
| &aBackConfigColor, &aTextConfigColor ); |
| else |
| pPattern->GetFont( aFont, eColorMode, pFmtDevice, &pOutput->aZoomY, pCondSet, nScript, |
| &aBackConfigColor, &aTextConfigColor ); |
| aFont.SetAlign(ALIGN_BASELINE); |
| |
| // Orientierung |
| |
| eAttrOrient = pPattern->GetCellOrientation( pCondSet ); |
| |
| // alignment |
| |
| eAttrHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue(); |
| |
| eAttrVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&)pPattern->GetItem( ATTR_VER_JUSTIFY, pCondSet )).GetValue(); |
| if ( eAttrVerJust == SVX_VER_JUSTIFY_STANDARD ) |
| eAttrVerJust = SVX_VER_JUSTIFY_BOTTOM; |
| |
| // line break |
| |
| bLineBreak = ((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK, pCondSet )).GetValue(); |
| |
| // handle "repeat" alignment |
| |
| bRepeat = ( eAttrHorJust == SVX_HOR_JUSTIFY_REPEAT ); |
| if ( bRepeat ) |
| { |
| // "repeat" disables rotation (before constructing the font) |
| eAttrOrient = SVX_ORIENTATION_STANDARD; |
| |
| // #i31843# "repeat" with "line breaks" is treated as default alignment (but rotation is still disabled) |
| if ( bLineBreak ) |
| eAttrHorJust = SVX_HOR_JUSTIFY_STANDARD; |
| } |
| |
| short nRot; |
| switch (eAttrOrient) |
| { |
| case SVX_ORIENTATION_STANDARD: |
| nRot = 0; |
| bRotated = (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE, pCondSet )).GetValue() != 0) && |
| !bRepeat; |
| break; |
| case SVX_ORIENTATION_STACKED: |
| nRot = 0; |
| bRotated = sal_False; |
| break; |
| case SVX_ORIENTATION_TOPBOTTOM: |
| nRot = 2700; |
| bRotated = sal_False; |
| break; |
| case SVX_ORIENTATION_BOTTOMTOP: |
| nRot = 900; |
| bRotated = sal_False; |
| break; |
| default: |
| DBG_ERROR("Falscher SvxCellOrientation Wert"); |
| nRot = 0; |
| bRotated = sal_False; |
| break; |
| } |
| aFont.SetOrientation( nRot ); |
| |
| // Syntax-Modus |
| |
| if (pOutput->bSyntaxMode) |
| pOutput->SetSyntaxColor( &aFont, pCell ); |
| |
| pDev->SetFont( aFont ); |
| if ( pFmtDevice != pDev ) |
| pFmtDevice->SetFont( aFont ); |
| |
| aMetric = pFmtDevice->GetFontMetric(); |
| |
| // |
| // Wenn auf dem Drucker das Leading 0 ist, gibt es Probleme |
| // -> Metric vom Bildschirm nehmen (wie EditEngine!) |
| // |
| |
| if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 ) |
| { |
| OutputDevice* pDefaultDev = Application::GetDefaultDevice(); |
| MapMode aOld = pDefaultDev->GetMapMode(); |
| pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() ); |
| aMetric = pDefaultDev->GetFontMetric( aFont ); |
| pDefaultDev->SetMapMode( aOld ); |
| } |
| |
| nAscentPixel = aMetric.GetAscent(); |
| if ( bPixelToLogic ) |
| nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height(); |
| |
| Color aULineColor( ((const SvxUnderlineItem&)pPattern->GetItem( ATTR_FONT_UNDERLINE, pCondSet )).GetColor() ); |
| pDev->SetTextLineColor( aULineColor ); |
| |
| Color aOLineColor( ((const SvxOverlineItem&)pPattern->GetItem( ATTR_FONT_OVERLINE, pCondSet )).GetColor() ); |
| pDev->SetOverlineColor( aOLineColor ); |
| |
| // Zahlenformat |
| |
| // sal_uLong nOld = nValueFormat; |
| nValueFormat = pPattern->GetNumberFormat( pOutput->pDoc->GetFormatTable(), pCondSet ); |
| |
| /* s.u. |
| if (nValueFormat != nOld) |
| pLastCell = NULL; // immer neu formatieren |
| */ |
| // Raender |
| |
| pMargin = (const SvxMarginItem*)&pPattern->GetItem( ATTR_MARGIN, pCondSet ); |
| if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT ) |
| nIndent = ((const SfxUInt16Item&)pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue(); |
| else |
| nIndent = 0; |
| |
| // "Shrink to fit" |
| |
| bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue(); |
| |
| // zumindest die Text-Groesse muss neu geholt werden |
| //! unterscheiden, und den Text nicht neu vom Numberformatter holen? |
| |
| pLastCell = NULL; |
| } |
| |
| void ScDrawStringsVars::SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet ) |
| { |
| nMaxDigitWidth = 0; |
| nSignWidth = 0; |
| nDotWidth = 0; |
| nExpWidth = 0; |
| // wird gerufen, wenn sich die Font-Variablen nicht aendern (!StringDiffer) |
| |
| pPattern = pNew; |
| pCondSet = pSet; //! noetig ??? |
| |
| // Zahlenformat |
| |
| sal_uLong nOld = nValueFormat; |
| // nValueFormat = pPattern->GetNumberFormat( pFormatter ); |
| const SfxPoolItem* pFormItem; |
| if ( !pCondSet || pCondSet->GetItemState(ATTR_VALUE_FORMAT,sal_True,&pFormItem) != SFX_ITEM_SET ) |
| pFormItem = &pPattern->GetItem(ATTR_VALUE_FORMAT); |
| const SfxPoolItem* pLangItem; |
| if ( !pCondSet || pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT,sal_True,&pLangItem) != SFX_ITEM_SET ) |
| pLangItem = &pPattern->GetItem(ATTR_LANGUAGE_FORMAT); |
| nValueFormat = pOutput->pDoc->GetFormatTable()->GetFormatForLanguageIfBuiltIn( |
| ((SfxUInt32Item*)pFormItem)->GetValue(), |
| ((SvxLanguageItem*)pLangItem)->GetLanguage() ); |
| |
| if (nValueFormat != nOld) |
| pLastCell = NULL; // immer neu formatieren |
| |
| // Raender |
| |
| pMargin = (const SvxMarginItem*)&pPattern->GetItem( ATTR_MARGIN, pCondSet ); |
| |
| if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT ) |
| nIndent = ((const SfxUInt16Item&)pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue(); |
| else |
| nIndent = 0; |
| |
| // "Shrink to fit" |
| |
| bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue(); |
| } |
| |
| inline sal_Bool SameValue( ScBaseCell* pCell, ScBaseCell* pOldCell ) // pCell ist != 0 |
| { |
| return pOldCell && pOldCell->GetCellType() == CELLTYPE_VALUE && |
| pCell->GetCellType() == CELLTYPE_VALUE && |
| ((ScValueCell*)pCell)->GetValue() == ((ScValueCell*)pOldCell)->GetValue(); |
| } |
| |
| sal_Bool ScDrawStringsVars::SetText( ScBaseCell* pCell ) |
| { |
| sal_Bool bChanged = sal_False; |
| |
| if (pCell) |
| { |
| if ( !SameValue( pCell, pLastCell ) ) |
| { |
| pLastCell = pCell; // Zelle merken |
| |
| Color* pColor; |
| sal_uLong nFormat = GetValueFormat(); |
| ScCellFormat::GetString( pCell, |
| nFormat, aString, &pColor, |
| *pOutput->pDoc->GetFormatTable(), |
| pOutput->bShowNullValues, |
| pOutput->bShowFormulas, |
| ftCheck ); |
| |
| if (aString.Len() > DRAWTEXT_MAX) |
| aString.Erase(DRAWTEXT_MAX); |
| |
| if ( pColor && !pOutput->bSyntaxMode && !( pOutput->bUseStyleColor && pOutput->bForceAutoColor ) ) |
| { |
| OutputDevice* pDev = pOutput->pDev; |
| aFont.SetColor(*pColor); |
| pDev->SetFont( aFont ); // nur fuer Ausgabe |
| bChanged = sal_True; |
| pLastCell = NULL; // naechstes Mal wieder hierherkommen |
| } |
| |
| TextChanged(); |
| } |
| // sonst String/Groesse behalten |
| } |
| else |
| { |
| aString.Erase(); |
| pLastCell = NULL; |
| aTextSize = Size(0,0); |
| nOriginalWidth = 0; |
| } |
| |
| return bChanged; |
| } |
| |
| void ScDrawStringsVars::SetHashText() |
| { |
| SetAutoText( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("###")) ); |
| } |
| |
| void ScDrawStringsVars::SetTextToWidthOrHash( ScBaseCell* pCell, long nWidth ) |
| { |
| // #i113045# do the single-character width calculations in logic units |
| if (bPixelToLogic) |
| nWidth = pOutput->pRefDevice->PixelToLogic(Size(nWidth,0)).Width(); |
| |
| if (!pCell) |
| return; |
| |
| CellType eType = pCell->GetCellType(); |
| if (eType != CELLTYPE_VALUE && eType != CELLTYPE_FORMULA) |
| // must be a value or formula cell. |
| return; |
| |
| if (eType == CELLTYPE_FORMULA) |
| { |
| ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell); |
| if (pFCell->GetErrCode() != 0 || pOutput->bShowFormulas) |
| { |
| SetHashText(); // If the error string doesn't fit, always use "###". Also for "display formulas" (#i116691#) |
| return; |
| } |
| // If it's formula, the result must be a value. |
| if (!pFCell->IsValue()) |
| return; |
| } |
| |
| sal_uLong nFormat = GetResultValueFormat(pCell); |
| if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0) |
| { |
| // Not 'General' number format. Set hash text and bail out. |
| SetHashText(); |
| return; |
| } |
| |
| double fVal = (eType == CELLTYPE_VALUE) ? |
| static_cast<ScValueCell*>(pCell)->GetValue() : static_cast<ScFormulaCell*>(pCell)->GetValue(); |
| |
| const SvNumberformat* pNumFormat = pOutput->pDoc->GetFormatTable()->GetEntry(nFormat); |
| if (!pNumFormat) |
| return; |
| |
| long nMaxDigit = GetMaxDigitWidth(); |
| sal_uInt16 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit); |
| |
| if (!pNumFormat->GetOutputString(fVal, nNumDigits, aString)) |
| // Failed to get output string. Bail out. |
| return; |
| |
| sal_uInt8 nSignCount = 0, nDecimalCount = 0, nExpCount = 0; |
| xub_StrLen nLen = aString.Len(); |
| sal_Unicode cDecSep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator.getStr()[0]; |
| for (xub_StrLen i = 0; i < nLen; ++i) |
| { |
| sal_Unicode c = aString.GetChar(i); |
| if (c == sal_Unicode('-')) |
| ++nSignCount; |
| else if (c == cDecSep) |
| ++nDecimalCount; |
| else if (c == sal_Unicode('E')) |
| ++nExpCount; |
| } |
| |
| // #i112250# A small value might be formatted as "0" when only counting the digits, |
| // but fit into the column when considering the smaller width of the decimal separator. |
| if (aString.EqualsAscii("0") && fVal != 0.0) |
| nDecimalCount = 1; |
| |
| if (nDecimalCount) |
| nWidth += (nMaxDigit - GetDotWidth()) * nDecimalCount; |
| if (nSignCount) |
| nWidth += (nMaxDigit - GetSignWidth()) * nSignCount; |
| if (nExpCount) |
| nWidth += (nMaxDigit - GetExpWidth()) * nExpCount; |
| |
| if (nDecimalCount || nSignCount || nExpCount) |
| { |
| // Re-calculate. |
| nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit); |
| if (!pNumFormat->GetOutputString(fVal, nNumDigits, aString)) |
| // Failed to get output string. Bail out. |
| return; |
| } |
| |
| long nActualTextWidth = pOutput->pFmtDevice->GetTextWidth(aString); |
| if (nActualTextWidth > nWidth) |
| { |
| // Even after the decimal adjustment the text doesn't fit. Give up. |
| SetHashText(); |
| return; |
| } |
| |
| TextChanged(); |
| pLastCell = NULL; // #i113022# equal cell and format in another column may give different string |
| } |
| |
| void ScDrawStringsVars::SetAutoText( const String& rAutoText ) |
| { |
| aString = rAutoText; |
| |
| OutputDevice* pRefDevice = pOutput->pRefDevice; |
| OutputDevice* pFmtDevice = pOutput->pFmtDevice; |
| aTextSize.Width() = pFmtDevice->GetTextWidth( aString ); |
| aTextSize.Height() = pFmtDevice->GetTextHeight(); |
| |
| if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER ) |
| { |
| double fMul = pOutput->GetStretch(); |
| aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5); |
| } |
| |
| aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent(); |
| if ( GetOrient() != SVX_ORIENTATION_STANDARD ) |
| { |
| long nTemp = aTextSize.Height(); |
| aTextSize.Height() = aTextSize.Width(); |
| aTextSize.Width() = nTemp; |
| } |
| |
| nOriginalWidth = aTextSize.Width(); |
| if ( bPixelToLogic ) |
| aTextSize = pRefDevice->LogicToPixel( aTextSize ); |
| |
| pLastCell = NULL; // derselbe Text kann in der naechsten Zelle wieder passen |
| } |
| |
| long ScDrawStringsVars::GetMaxDigitWidth() |
| { |
| if (nMaxDigitWidth > 0) |
| return nMaxDigitWidth; |
| |
| sal_Char cZero = '0'; |
| for (sal_Char i = 0; i < 10; ++i) |
| { |
| sal_Char cDigit = cZero + i; |
| long n = pOutput->pFmtDevice->GetTextWidth(String(cDigit)); |
| nMaxDigitWidth = ::std::max(nMaxDigitWidth, n); |
| } |
| return nMaxDigitWidth; |
| } |
| |
| long ScDrawStringsVars::GetSignWidth() |
| { |
| if (nSignWidth > 0) |
| return nSignWidth; |
| |
| nSignWidth = pOutput->pFmtDevice->GetTextWidth(String('-')); |
| return nSignWidth; |
| } |
| |
| long ScDrawStringsVars::GetDotWidth() |
| { |
| if (nDotWidth > 0) |
| return nDotWidth; |
| |
| const ::rtl::OUString& sep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator; |
| nDotWidth = pOutput->pFmtDevice->GetTextWidth(sep); |
| return nDotWidth; |
| } |
| |
| long ScDrawStringsVars::GetExpWidth() |
| { |
| if (nExpWidth > 0) |
| return nExpWidth; |
| |
| nExpWidth = pOutput->pFmtDevice->GetTextWidth(String('E')); |
| return nExpWidth; |
| } |
| |
| void ScDrawStringsVars::TextChanged() |
| { |
| OutputDevice* pRefDevice = pOutput->pRefDevice; |
| OutputDevice* pFmtDevice = pOutput->pFmtDevice; |
| aTextSize.Width() = pFmtDevice->GetTextWidth( aString ); |
| aTextSize.Height() = pFmtDevice->GetTextHeight(); |
| |
| if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER ) |
| { |
| double fMul = pOutput->GetStretch(); |
| aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5); |
| } |
| |
| aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent(); |
| if ( GetOrient() != SVX_ORIENTATION_STANDARD ) |
| { |
| long nTemp = aTextSize.Height(); |
| aTextSize.Height() = aTextSize.Width(); |
| aTextSize.Width() = nTemp; |
| } |
| |
| nOriginalWidth = aTextSize.Width(); |
| if ( bPixelToLogic ) |
| aTextSize = pRefDevice->LogicToPixel( aTextSize ); |
| } |
| |
| sal_Bool ScDrawStringsVars::HasEditCharacters() const |
| { |
| static const sal_Unicode pChars[] = |
| { |
| CHAR_NBSP, CHAR_SHY, CHAR_ZWSP, CHAR_LRM, CHAR_RLM, CHAR_NBHY, CHAR_ZWNBSP, 0 |
| }; |
| return aString.SearchChar( pChars ) != STRING_NOTFOUND; |
| } |
| |
| sal_uLong ScDrawStringsVars::GetResultValueFormat( const ScBaseCell* pCell ) const |
| { |
| // Get the effective number format, including formula result types. |
| // This assumes that a formula cell has already been calculated. |
| |
| if ( (nValueFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) |
| return static_cast<const ScFormulaCell*>(pCell)->GetStandardFormat(*pOutput->pDoc->GetFormatTable(), nValueFormat); |
| else |
| return nValueFormat; |
| } |
| |
| //================================================================== |
| |
| double ScOutputData::GetStretch() |
| { |
| if ( pRefDevice->IsMapMode() ) |
| { |
| // #95920# If a non-trivial MapMode is set, its scale is now already |
| // taken into account in the OutputDevice's font handling |
| // (OutputDevice::ImplNewFont, see #95414#). |
| // The old handling below is only needed for pixel output. |
| return 1.0; |
| } |
| |
| // calculation in double is faster than Fraction multiplication |
| // and doesn't overflow |
| |
| if ( pRefDevice == pFmtDevice ) |
| { |
| MapMode aOld = pRefDevice->GetMapMode(); |
| return ((double)aOld.GetScaleY()) / ((double)aOld.GetScaleX()) * ((double)aZoomY) / ((double)aZoomX); |
| } |
| else |
| { |
| // when formatting for printer, device map mode has already been taken care of |
| return ((double)aZoomY) / ((double)aZoomX); |
| } |
| } |
| |
| //================================================================== |
| |
| // |
| // output strings |
| // |
| |
| void lcl_DoHyperlinkResult( OutputDevice* pDev, const Rectangle& rRect, ScBaseCell* pCell ) |
| { |
| vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() ); |
| |
| String aCellText; |
| String aURL; |
| if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) |
| { |
| ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell); |
| if ( pFCell->IsHyperLinkCell() ) |
| pFCell->GetURLResult( aURL, aCellText ); |
| } |
| |
| if ( aURL.Len() && pPDFData ) |
| { |
| vcl::PDFExtOutDevBookmarkEntry aBookmark; |
| aBookmark.nLinkId = pPDFData->CreateLink( rRect ); |
| aBookmark.aBookmark = aURL; |
| std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFData->GetBookmarks(); |
| rBookmarks.push_back( aBookmark ); |
| } |
| } |
| |
| void ScOutputData::SetSyntaxColor( Font* pFont, ScBaseCell* pCell ) |
| { |
| if (pCell) |
| { |
| switch (pCell->GetCellType()) |
| { |
| case CELLTYPE_VALUE: |
| pFont->SetColor( *pValueColor ); |
| break; |
| case CELLTYPE_STRING: |
| pFont->SetColor( *pTextColor ); |
| break; |
| case CELLTYPE_FORMULA: |
| pFont->SetColor( *pFormulaColor ); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| } |
| |
| void lcl_SetEditColor( EditEngine& rEngine, const Color& rColor ) |
| { |
| ESelection aSel( 0, 0, rEngine.GetParagraphCount(), 0 ); |
| SfxItemSet aSet( rEngine.GetEmptyItemSet() ); |
| aSet.Put( SvxColorItem( rColor, EE_CHAR_COLOR ) ); |
| rEngine.QuickSetAttribs( aSet, aSel ); |
| // function is called with update mode set to FALSE |
| } |
| |
| void ScOutputData::SetEditSyntaxColor( EditEngine& rEngine, ScBaseCell* pCell ) |
| { |
| if (pCell) |
| { |
| Color aColor; |
| switch (pCell->GetCellType()) |
| { |
| case CELLTYPE_VALUE: |
| aColor = *pValueColor; |
| break; |
| case CELLTYPE_STRING: |
| aColor = *pTextColor; |
| break; |
| case CELLTYPE_FORMULA: |
| aColor = *pFormulaColor; |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| lcl_SetEditColor( rEngine, aColor ); |
| } |
| } |
| |
| sal_Bool ScOutputData::GetMergeOrigin( SCCOL nX, SCROW nY, SCSIZE nArrY, |
| SCCOL& rOverX, SCROW& rOverY, |
| sal_Bool bVisRowChanged ) |
| { |
| sal_Bool bDoMerge = sal_False; |
| sal_Bool bIsLeft = ( nX == nVisX1 ); |
| sal_Bool bIsTop = ( nY == nVisY1 ) || bVisRowChanged; |
| |
| CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nX+1]; |
| if ( pInfo->bHOverlapped && pInfo->bVOverlapped ) |
| bDoMerge = bIsLeft && bIsTop; |
| else if ( pInfo->bHOverlapped ) |
| bDoMerge = bIsLeft; |
| else if ( pInfo->bVOverlapped ) |
| bDoMerge = bIsTop; |
| |
| // weiter solange versteckt |
| /* if (!bDoMerge) |
| return sal_False; |
| */ |
| |
| rOverX = nX; |
| rOverY = nY; |
| sal_Bool bHOver = pInfo->bHOverlapped; |
| sal_Bool bVOver = pInfo->bVOverlapped; |
| sal_Bool bHidden; |
| |
| while (bHOver) // nY konstant |
| { |
| --rOverX; |
| bHidden = pDoc->ColHidden(rOverX, nTab); |
| if ( !bDoMerge && !bHidden ) |
| return sal_False; |
| |
| if (rOverX >= nX1 && !bHidden) |
| { |
| // rVirtPosX -= pRowInfo[0].pCellInfo[rOverX+1].nWidth; |
| bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped; |
| bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped; |
| } |
| else |
| { |
| // if (!bClipVirt) |
| // rVirtPosX -= (long) (pDoc->GetColWidth( rOverX, nTab ) * nPPTX); |
| sal_uInt16 nOverlap = ((ScMergeFlagAttr*)pDoc->GetAttr( |
| rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue(); |
| bHOver = ((nOverlap & SC_MF_HOR) != 0); |
| bVOver = ((nOverlap & SC_MF_VER) != 0); |
| } |
| } |
| |
| while (bVOver) |
| { |
| --rOverY; |
| bHidden = pDoc->RowHidden(rOverY, nTab); |
| if ( !bDoMerge && !bHidden ) |
| return sal_False; |
| |
| if (nArrY>0) |
| --nArrY; // lokale Kopie ! |
| |
| if (rOverX >= nX1 && rOverY >= nY1 && |
| !pDoc->ColHidden(rOverX, nTab) && |
| !pDoc->RowHidden(rOverY, nTab) && |
| pRowInfo[nArrY].nRowNo == rOverY) |
| { |
| // rVirtPosY -= pRowInfo[nArrY].nHeight; |
| bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped; |
| bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped; |
| } |
| else |
| { |
| // if (!bClipVirt) |
| // rVirtPosY -= (long) (pDoc->GetRowHeight( rOverY, nTab ) * nPPTY); |
| sal_uInt16 nOverlap = ((ScMergeFlagAttr*)pDoc->GetAttr( |
| rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue(); |
| bHOver = ((nOverlap & SC_MF_HOR) != 0); |
| bVOver = ((nOverlap & SC_MF_VER) != 0); |
| } |
| } |
| |
| return sal_True; |
| } |
| |
| inline sal_Bool StringDiffer( const ScPatternAttr*& rpOldPattern, const ScPatternAttr*& rpNewPattern ) |
| { |
| DBG_ASSERT( rpNewPattern, "pNewPattern" ); |
| |
| if ( rpNewPattern == rpOldPattern ) |
| return sal_False; |
| else if ( !rpOldPattern ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT ) != &rpOldPattern->GetItem( ATTR_FONT ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_HEIGHT ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_WEIGHT ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_FONT_POSTURE ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_POSTURE ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_POSTURE ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT_UNDERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_UNDERLINE ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT_OVERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_OVERLINE ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT_WORDLINE ) != &rpOldPattern->GetItem( ATTR_FONT_WORDLINE ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT_CROSSEDOUT ) != &rpOldPattern->GetItem( ATTR_FONT_CROSSEDOUT ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT_CONTOUR ) != &rpOldPattern->GetItem( ATTR_FONT_CONTOUR ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT_SHADOWED ) != &rpOldPattern->GetItem( ATTR_FONT_SHADOWED ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT_COLOR ) != &rpOldPattern->GetItem( ATTR_FONT_COLOR ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_HOR_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_VER_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_STACKED ) != &rpOldPattern->GetItem( ATTR_STACKED ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_LINEBREAK ) != &rpOldPattern->GetItem( ATTR_LINEBREAK ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_MARGIN ) != &rpOldPattern->GetItem( ATTR_MARGIN ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_ROTATE_VALUE ) != &rpOldPattern->GetItem( ATTR_ROTATE_VALUE ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FORBIDDEN_RULES ) != &rpOldPattern->GetItem( ATTR_FORBIDDEN_RULES ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT_EMPHASISMARK ) != &rpOldPattern->GetItem( ATTR_FONT_EMPHASISMARK ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_FONT_RELIEF ) != &rpOldPattern->GetItem( ATTR_FONT_RELIEF ) ) |
| return sal_True; |
| else if ( &rpNewPattern->GetItem( ATTR_BACKGROUND ) != &rpOldPattern->GetItem( ATTR_BACKGROUND ) ) |
| return sal_True; // needed with automatic text color |
| else |
| { |
| rpOldPattern = rpNewPattern; |
| return sal_False; |
| } |
| } |
| |
| inline void lcl_CreateInterpretProgress( sal_Bool& bProgress, ScDocument* pDoc, |
| ScFormulaCell* pFCell ) |
| { |
| if ( !bProgress && pFCell->GetDirty() ) |
| { |
| ScProgress::CreateInterpretProgress( pDoc, sal_True ); |
| bProgress = sal_True; |
| } |
| } |
| |
| inline sal_uInt8 GetScriptType( ScDocument* pDoc, ScBaseCell* pCell, |
| const ScPatternAttr* pPattern, |
| const SfxItemSet* pCondSet ) |
| { |
| return pDoc->GetCellScriptType( pCell, pPattern->GetNumberFormat( pDoc->GetFormatTable(), pCondSet ) ); |
| } |
| |
| inline sal_Bool IsAmbiguousScript( sal_uInt8 nScript ) |
| { |
| return ( nScript != SCRIPTTYPE_LATIN && |
| nScript != SCRIPTTYPE_ASIAN && |
| nScript != SCRIPTTYPE_COMPLEX ); |
| } |
| |
| sal_Bool ScOutputData::IsEmptyCellText( RowInfo* pThisRowInfo, SCCOL nX, SCROW nY ) |
| { |
| // pThisRowInfo may be NULL |
| |
| sal_Bool bEmpty; |
| if ( pThisRowInfo && nX <= nX2 ) |
| bEmpty = pThisRowInfo->pCellInfo[nX+1].bEmptyCellText; |
| else |
| bEmpty = ( pDoc->GetCell( ScAddress( nX, nY, nTab ) ) == NULL ); |
| |
| if ( !bEmpty && ( nX < nX1 || nX > nX2 || !pThisRowInfo ) ) |
| { |
| // for the range nX1..nX2 in RowInfo, cell protection attribute is already evaluated |
| // into bEmptyCellText in ScDocument::FillInfo / lcl_HidePrint (printfun) |
| |
| sal_Bool bIsPrint = ( eType == OUTTYPE_PRINTER ); |
| |
| if ( bIsPrint || bTabProtected ) |
| { |
| const ScProtectionAttr* pAttr = (const ScProtectionAttr*) |
| pDoc->GetEffItem( nX, nY, nTab, ATTR_PROTECTION ); |
| if ( bIsPrint && pAttr->GetHidePrint() ) |
| bEmpty = sal_True; |
| else if ( bTabProtected ) |
| { |
| if ( pAttr->GetHideCell() ) |
| bEmpty = sal_True; |
| else if ( bShowFormulas && pAttr->GetHideFormula() ) |
| { |
| ScBaseCell* pCell = pDoc->GetCell( ScAddress( nX, nY, nTab ) ); |
| if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) |
| bEmpty = sal_True; |
| } |
| } |
| } |
| } |
| return bEmpty; |
| } |
| |
| void ScOutputData::GetVisibleCell( SCCOL nCol, SCROW nRow, SCTAB nTabP, ScBaseCell*& rpCell ) |
| { |
| pDoc->GetCell( nCol, nRow, nTabP, rpCell ); |
| if ( rpCell && IsEmptyCellText( NULL, nCol, nRow ) ) |
| rpCell = NULL; |
| } |
| |
| sal_Bool ScOutputData::IsAvailable( SCCOL nX, SCROW nY ) |
| { |
| // apply the same logic here as in DrawStrings/DrawEdit: |
| // Stop at non-empty or merged or overlapped cell, |
| // where a note is empty as well as a cell that's hidden by protection settings |
| |
| const ScBaseCell* pCell = pDoc->GetCell( ScAddress( nX, nY, nTab ) ); |
| if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE && !IsEmptyCellText( NULL, nX, nY ) ) |
| { |
| return sal_False; |
| } |
| |
| const ScPatternAttr* pPattern = pDoc->GetPattern( nX, nY, nTab ); |
| if ( ((const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE)).IsMerged() || |
| ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).IsOverlapped() ) |
| { |
| return sal_False; |
| } |
| |
| return sal_True; |
| } |
| |
| // nX, nArrY: loop variables from DrawStrings / DrawEdit |
| // nPosX, nPosY: corresponding positions for nX, nArrY |
| // nCellX, nCellY: position of the cell that contains the text |
| // nNeeded: Text width, including margin |
| // rPattern: cell format at nCellX, nCellY |
| // nHorJustify: horizontal alignment (visual) to determine which cells to use for long strings |
| // bCellIsValue: if set, don't extend into empty cells |
| // bBreak: if set, don't extend, and don't set clip marks (but rLeftClip/rRightClip is set) |
| // bOverwrite: if set, also extend into non-empty cells (for rotated text) |
| // rParam output: various area parameters. |
| |
| void ScOutputData::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 ) |
| { |
| // rThisRowInfo may be for a different row than nCellY, is still used for clip marks |
| RowInfo& rThisRowInfo = pRowInfo[nArrY]; |
| |
| long nLayoutSign = bLayoutRTL ? -1 : 1; |
| |
| long nCellPosX = nPosX; // find nCellX position, starting at nX/nPosX |
| SCCOL nCompCol = nX; |
| while ( nCellX > nCompCol ) |
| { |
| //! extra member function for width? |
| long nColWidth = ( nCompCol <= nX2 ) ? |
| pRowInfo[0].pCellInfo[nCompCol+1].nWidth : |
| (long) ( pDoc->GetColWidth( nCompCol, nTab ) * nPPTX ); |
| nCellPosX += nColWidth * nLayoutSign; |
| ++nCompCol; |
| } |
| while ( nCellX < nCompCol ) |
| { |
| --nCompCol; |
| long nColWidth = ( nCompCol <= nX2 ) ? |
| pRowInfo[0].pCellInfo[nCompCol+1].nWidth : |
| (long) ( pDoc->GetColWidth( nCompCol, nTab ) * nPPTX ); |
| nCellPosX -= nColWidth * nLayoutSign; |
| } |
| |
| long nCellPosY = nPosY; // find nCellY position, starting at nArrY/nPosY |
| SCSIZE nCompArr = nArrY; |
| SCROW nCompRow = pRowInfo[nCompArr].nRowNo; |
| while ( nCellY > nCompRow ) |
| { |
| if ( nCompArr + 1 < nArrCount ) |
| { |
| nCellPosY += pRowInfo[nCompArr].nHeight; |
| ++nCompArr; |
| nCompRow = pRowInfo[nCompArr].nRowNo; |
| } |
| else |
| { |
| sal_uInt16 nDocHeight = pDoc->GetRowHeight( nCompRow, nTab ); |
| if ( nDocHeight ) |
| nCellPosY += (long) ( nDocHeight * nPPTY ); |
| ++nCompRow; |
| } |
| } |
| nCellPosY -= (long) pDoc->GetScaledRowHeight( nCellY, nCompRow-1, nTab, nPPTY ); |
| |
| const ScMergeAttr* pMerge = (const ScMergeAttr*)&rPattern.GetItem( ATTR_MERGE ); |
| sal_Bool bMerged = pMerge->IsMerged(); |
| long nMergeCols = pMerge->GetColMerge(); |
| if ( nMergeCols == 0 ) |
| nMergeCols = 1; |
| long nMergeRows = pMerge->GetRowMerge(); |
| if ( nMergeRows == 0 ) |
| nMergeRows = 1; |
| |
| long i; |
| long nMergeSizeX = 0; |
| for ( i=0; i<nMergeCols; i++ ) |
| { |
| long nColWidth = ( nCellX+i <= nX2 ) ? |
| pRowInfo[0].pCellInfo[nCellX+i+1].nWidth : |
| (long) ( pDoc->GetColWidth( sal::static_int_cast<SCCOL>(nCellX+i), nTab ) * nPPTX ); |
| nMergeSizeX += nColWidth; |
| } |
| long nMergeSizeY = 0; |
| short nDirect = 0; |
| if ( rThisRowInfo.nRowNo == nCellY ) |
| { |
| // take first row's height from row info |
| nMergeSizeY += rThisRowInfo.nHeight; |
| nDirect = 1; // skip in loop |
| } |
| // following rows always from document |
| nMergeSizeY += (long) pDoc->GetScaledRowHeight( nCellY+nDirect, nCellY+nMergeRows-1, nTab, nPPTY); |
| |
| --nMergeSizeX; // leave out the grid horizontally, also for alignment (align between grid lines) |
| |
| rParam.mnColWidth = nMergeSizeX; // store the actual column width. |
| |
| // |
| // construct the rectangles using logical left/right values (justify is called at the end) |
| // |
| |
| // rAlignRect is the single cell or merged area, used for alignment. |
| |
| rParam.maAlignRect.Left() = nCellPosX; |
| rParam.maAlignRect.Right() = nCellPosX + ( nMergeSizeX - 1 ) * nLayoutSign; |
| rParam.maAlignRect.Top() = nCellPosY; |
| rParam.maAlignRect.Bottom() = nCellPosY + nMergeSizeY - 1; |
| |
| // rClipRect is all cells that are used for output. |
| // For merged cells this is the same as rAlignRect, otherwise neighboring cells can also be used. |
| |
| rParam.maClipRect = rParam.maAlignRect; |
| if ( nNeeded > nMergeSizeX ) |
| { |
| SvxCellHorJustify eHorJust = (SvxCellHorJustify)nHorJustify; |
| |
| long nMissing = nNeeded - nMergeSizeX; |
| long nLeftMissing = 0; |
| long nRightMissing = 0; |
| switch ( eHorJust ) |
| { |
| case SVX_HOR_JUSTIFY_LEFT: |
| nRightMissing = nMissing; |
| break; |
| case SVX_HOR_JUSTIFY_RIGHT: |
| nLeftMissing = nMissing; |
| break; |
| case SVX_HOR_JUSTIFY_CENTER: |
| nLeftMissing = nMissing / 2; |
| nRightMissing = nMissing - nLeftMissing; |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| |
| // nLeftMissing, nRightMissing are logical, eHorJust values are visual |
| if ( bLayoutRTL ) |
| ::std::swap( nLeftMissing, nRightMissing ); |
| |
| SCCOL nRightX = nCellX; |
| SCCOL nLeftX = nCellX; |
| if ( !bMerged && !bCellIsValue && !bBreak ) |
| { |
| // look for empty cells into which the text can be extended |
| |
| while ( nRightMissing > 0 && nRightX < MAXCOL && ( bOverwrite || IsAvailable( nRightX+1, nCellY ) ) ) |
| { |
| ++nRightX; |
| long nAdd = (long) ( pDoc->GetColWidth( nRightX, nTab ) * nPPTX ); |
| nRightMissing -= nAdd; |
| rParam.maClipRect.Right() += nAdd * nLayoutSign; |
| |
| if ( rThisRowInfo.nRowNo == nCellY && nRightX >= nX1 && nRightX <= nX2 ) |
| rThisRowInfo.pCellInfo[nRightX].bHideGrid = sal_True; |
| } |
| |
| while ( nLeftMissing > 0 && nLeftX > 0 && ( bOverwrite || IsAvailable( nLeftX-1, nCellY ) ) ) |
| { |
| if ( rThisRowInfo.nRowNo == nCellY && nLeftX >= nX1 && nLeftX <= nX2 ) |
| rThisRowInfo.pCellInfo[nLeftX].bHideGrid = sal_True; |
| |
| --nLeftX; |
| long nAdd = (long) ( pDoc->GetColWidth( nLeftX, nTab ) * nPPTX ); |
| nLeftMissing -= nAdd; |
| rParam.maClipRect.Left() -= nAdd * nLayoutSign; |
| } |
| } |
| |
| // Set flag and reserve space for clipping mark triangle, |
| // even if rThisRowInfo isn't for nCellY (merged cells). |
| if ( nRightMissing > 0 && bMarkClipped && nRightX >= nX1 && nRightX <= nX2 && !bBreak && !bCellIsValue ) |
| { |
| rThisRowInfo.pCellInfo[nRightX+1].nClipMark |= SC_CLIPMARK_RIGHT; |
| bAnyClipped = sal_True; |
| long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX ); |
| rParam.maClipRect.Right() -= nMarkPixel * nLayoutSign; |
| } |
| if ( nLeftMissing > 0 && bMarkClipped && nLeftX >= nX1 && nLeftX <= nX2 && !bBreak && !bCellIsValue ) |
| { |
| rThisRowInfo.pCellInfo[nLeftX+1].nClipMark |= SC_CLIPMARK_LEFT; |
| bAnyClipped = sal_True; |
| long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX ); |
| rParam.maClipRect.Left() += nMarkPixel * nLayoutSign; |
| } |
| |
| rParam.mbLeftClip = ( nLeftMissing > 0 ); |
| rParam.mbRightClip = ( nRightMissing > 0 ); |
| } |
| else |
| { |
| rParam.mbLeftClip = rParam.mbRightClip = sal_False; |
| |
| // leave space for AutoFilter on screen |
| // (for automatic line break: only if not formatting for printer, as in ScColumn::GetNeededSize) |
| |
| if ( eType==OUTTYPE_WINDOW && |
| ( static_cast<const ScMergeFlagAttr&>(rPattern.GetItem(ATTR_MERGE_FLAG)).GetValue() & SC_MF_AUTO ) && |
| ( !bBreak || pRefDevice == pFmtDevice ) ) |
| { |
| // filter drop-down width is now independent from row height |
| const long nFilter = DROPDOWN_BITMAP_SIZE; |
| sal_Bool bFit = ( nNeeded + nFilter <= nMergeSizeX ); |
| if ( bFit || bCellIsValue ) |
| { |
| // content fits even in the remaining area without the filter button |
| // -> align within that remaining area |
| |
| rParam.maAlignRect.Right() -= nFilter * nLayoutSign; |
| rParam.maClipRect.Right() -= nFilter * nLayoutSign; |
| |
| // if a number doesn't fit, don't hide part of the number behind the button |
| // -> set clip flags, so "###" replacement is used (but also within the smaller area) |
| |
| if ( !bFit ) |
| rParam.mbLeftClip = rParam.mbRightClip = sal_True; |
| } |
| } |
| } |
| |
| // justify both rectangles for alignment calculation, use with DrawText etc. |
| |
| rParam.maAlignRect.Justify(); |
| rParam.maClipRect.Justify(); |
| |
| #if 0 |
| //! Test !!! |
| pDev->Push(); |
| pDev->SetLineColor(); |
| pDev->SetFillColor( COL_LIGHTGREEN ); |
| pDev->DrawRect( pDev->PixelToLogic(rParam.maClipRect) ); |
| pDev->DrawRect( rParam.maClipRect ); // print preview |
| pDev->Pop(); |
| //! Test !!! |
| #endif |
| } |
| |
| void ScOutputData::DrawStrings( sal_Bool bPixelToLogic ) |
| { |
| DBG_ASSERT( pDev == pRefDevice || |
| pDev->GetMapMode().GetMapUnit() == pRefDevice->GetMapMode().GetMapUnit(), |
| "DrawStrings: unterschiedliche MapUnits ?!?!" ); |
| |
| vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() ); |
| |
| sal_Bool bWasIdleDisabled = pDoc->IsIdleDisabled(); |
| pDoc->DisableIdle( sal_True ); |
| Size aMinSize = pRefDevice->PixelToLogic(Size(0,100)); // erst darueber wird ausgegeben |
| // sal_uInt32 nMinHeight = aMinSize.Height() / 200; // 1/2 Pixel |
| |
| ScDrawStringsVars aVars( this, bPixelToLogic ); |
| |
| sal_Bool bProgress = sal_False; |
| |
| long nInitPosX = nScrX; |
| if ( bLayoutRTL ) |
| nInitPosX += nMirrorW - 1; // pixels |
| long nLayoutSign = bLayoutRTL ? -1 : 1; |
| |
| SCCOL nLastContentCol = MAXCOL; |
| if ( nX2 < MAXCOL ) |
| nLastContentCol = sal::static_int_cast<SCCOL>( |
| nLastContentCol - pDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) ); |
| SCCOL nLoopStartX = nX1; |
| if ( nX1 > 0 ) |
| --nLoopStartX; // start before nX1 for rest of long text to the left |
| |
| // variables for GetOutputArea |
| OutputAreaParam aAreaParam; |
| sal_Bool bCellIsValue = sal_False; |
| long nNeededWidth = 0; |
| SvxCellHorJustify eOutHorJust = SVX_HOR_JUSTIFY_STANDARD; |
| const ScPatternAttr* pPattern = NULL; |
| const SfxItemSet* pCondSet = NULL; |
| const ScPatternAttr* pOldPattern = NULL; |
| const SfxItemSet* pOldCondSet = NULL; |
| sal_uInt8 nOldScript = 0; |
| |
| long nPosY = nScrY; |
| for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++) |
| { |
| RowInfo* pThisRowInfo = &pRowInfo[nArrY]; |
| if ( pThisRowInfo->bChanged ) |
| { |
| SCROW nY = pThisRowInfo->nRowNo; |
| // long nCellHeight = (long) pThisRowInfo->nHeight; |
| long nPosX = nInitPosX; |
| if ( nLoopStartX < nX1 ) |
| nPosX -= pRowInfo[0].pCellInfo[nLoopStartX+1].nWidth * nLayoutSign; |
| for (SCCOL nX=nLoopStartX; nX<=nX2; nX++) |
| { |
| sal_Bool bMergeEmpty = sal_False; |
| CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1]; |
| sal_Bool bEmpty = nX < nX1 || pInfo->bEmptyCellText; |
| |
| SCCOL nCellX = nX; // position where the cell really starts |
| SCROW nCellY = nY; |
| sal_Bool bDoCell = sal_False; |
| sal_Bool bNeedEdit = sal_False; |
| |
| // |
| // Part of a merged cell? |
| // |
| |
| sal_Bool bOverlapped = ( pInfo->bHOverlapped || pInfo->bVOverlapped ); |
| if ( bOverlapped ) |
| { |
| bEmpty = sal_True; |
| |
| SCCOL nOverX; // start of the merged cells |
| SCROW nOverY; |
| sal_Bool bVisChanged = !pRowInfo[nArrY-1].bChanged; |
| if (GetMergeOrigin( nX,nY, nArrY, nOverX,nOverY, bVisChanged )) |
| { |
| nCellX = nOverX; |
| nCellY = nOverY; |
| bDoCell = sal_True; |
| } |
| else |
| bMergeEmpty = sal_True; |
| } |
| |
| // |
| // Rest of a long text further to the left? |
| // |
| |
| if ( bEmpty && !bMergeEmpty && nX < nX1 && !bOverlapped ) |
| { |
| SCCOL nTempX=nX1; |
| while (nTempX > 0 && IsEmptyCellText( pThisRowInfo, nTempX, nY )) |
| --nTempX; |
| |
| if ( nTempX < nX1 && |
| !IsEmptyCellText( pThisRowInfo, nTempX, nY ) && |
| !pDoc->HasAttrib( nTempX,nY,nTab, nX1,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) ) |
| { |
| nCellX = nTempX; |
| bDoCell = sal_True; |
| } |
| } |
| |
| // |
| // Rest of a long text further to the right? |
| // |
| |
| if ( bEmpty && !bMergeEmpty && nX == nX2 && !bOverlapped ) |
| { |
| // don't have to look further than nLastContentCol |
| |
| SCCOL nTempX=nX; |
| while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY )) |
| ++nTempX; |
| |
| if ( nTempX > nX && |
| !IsEmptyCellText( pThisRowInfo, nTempX, nY ) && |
| !pDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) ) |
| { |
| nCellX = nTempX; |
| bDoCell = sal_True; |
| } |
| } |
| |
| // |
| // normal visible cell |
| // |
| |
| if (!bEmpty) |
| bDoCell = sal_True; |
| |
| // |
| // don't output the cell that's being edited |
| // |
| |
| if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow ) |
| bDoCell = sal_False; |
| |
| // |
| // output the cell text |
| // |
| |
| ScBaseCell* pCell = NULL; |
| if (bDoCell) |
| { |
| if ( nCellY == nY && nCellX == nX && nCellX >= nX1 && nCellX <= nX2 ) |
| pCell = pThisRowInfo->pCellInfo[nCellX+1].pCell; |
| else |
| GetVisibleCell( nCellX, nCellY, nTab, pCell ); // get from document |
| if ( !pCell ) |
| bDoCell = sal_False; |
| else if ( pCell->GetCellType() == CELLTYPE_EDIT ) |
| bNeedEdit = sal_True; |
| } |
| if (bDoCell && !bNeedEdit) |
| { |
| if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 ) |
| { |
| CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1]; |
| pPattern = rCellInfo.pPatternAttr; |
| pCondSet = rCellInfo.pConditionSet; |
| |
| if ( !pPattern ) |
| { |
| // #i68085# pattern from cell info for hidden columns is null, |
| // test for null is quicker than using column flags |
| pPattern = pDoc->GetPattern( nCellX, nCellY, nTab ); |
| pCondSet = pDoc->GetCondResult( nCellX, nCellY, nTab ); |
| } |
| } |
| else // get from document |
| { |
| pPattern = pDoc->GetPattern( nCellX, nCellY, nTab ); |
| pCondSet = pDoc->GetCondResult( nCellX, nCellY, nTab ); |
| } |
| |
| sal_uInt8 nScript = GetScriptType( pDoc, pCell, pPattern, pCondSet ); |
| if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType(); |
| if ( pPattern != pOldPattern || pCondSet != pOldCondSet || |
| nScript != nOldScript || bSyntaxMode ) |
| { |
| if ( StringDiffer(pOldPattern,pPattern) || |
| pCondSet != pOldCondSet || nScript != nOldScript || bSyntaxMode ) |
| aVars.SetPattern( pPattern, pCondSet, pCell, nScript ); |
| else |
| aVars.SetPatternSimple( pPattern, pCondSet ); |
| pOldPattern = pPattern; |
| pOldCondSet = pCondSet; |
| nOldScript = nScript; |
| } |
| |
| // use edit engine for rotated, stacked or mixed-script text |
| if ( aVars.GetOrient() == SVX_ORIENTATION_STACKED || |
| aVars.IsRotated() || IsAmbiguousScript(nScript) ) |
| bNeedEdit = sal_True; |
| } |
| if (bDoCell && !bNeedEdit) |
| { |
| sal_Bool bFormulaCell = (pCell->GetCellType() == CELLTYPE_FORMULA ); |
| if ( bFormulaCell ) |
| lcl_CreateInterpretProgress( bProgress, pDoc, (ScFormulaCell*)pCell ); |
| if ( aVars.SetText(pCell) ) |
| pOldPattern = NULL; |
| bNeedEdit = aVars.HasEditCharacters() || |
| (bFormulaCell && ((ScFormulaCell*)pCell)->IsMultilineResult()); |
| } |
| long nTotalMargin = 0; |
| if (bDoCell && !bNeedEdit) |
| { |
| CellType eCellType = pCell->GetCellType(); |
| bCellIsValue = ( eCellType == CELLTYPE_VALUE ); |
| if ( eCellType == CELLTYPE_FORMULA ) |
| { |
| ScFormulaCell* pFCell = (ScFormulaCell*)pCell; |
| bCellIsValue = pFCell->IsRunning() || pFCell->IsValue(); |
| } |
| |
| eOutHorJust = ( aVars.GetHorJust() != SVX_HOR_JUSTIFY_STANDARD ) ? |
| aVars.GetHorJust() : |
| ( bCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT ); |
| |
| if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT ) |
| eOutHorJust = SVX_HOR_JUSTIFY_LEFT; // repeat is not yet implemented |
| |
| sal_Bool bBreak = ( aVars.GetLineBreak() || aVars.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK ); |
| |
| // #i111387# #o11817313# disable automatic line breaks only for "General" number format |
| if ( bBreak && bCellIsValue && ( aVars.GetResultValueFormat(pCell) % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 ) |
| bBreak = sal_False; |
| |
| sal_Bool bRepeat = aVars.IsRepeat() && !bBreak; |
| sal_Bool bShrink = aVars.IsShrink() && !bBreak && !bRepeat; |
| |
| nTotalMargin = |
| static_cast<long>(aVars.GetLeftTotal() * nPPTX) + |
| static_cast<long>(aVars.GetMargin()->GetRightMargin() * nPPTX); |
| |
| nNeededWidth = aVars.GetTextSize().Width() + nTotalMargin; |
| |
| // GetOutputArea gives justfied rectangles |
| GetOutputArea( nX, nArrY, nPosX, nPosY, nCellX, nCellY, nNeededWidth, |
| *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust), |
| bCellIsValue || bRepeat || bShrink, bBreak, sal_False, |
| aAreaParam ); |
| |
| if ( bShrink ) |
| { |
| if ( aVars.GetOrient() != SVX_ORIENTATION_STANDARD ) |
| { |
| // Only horizontal scaling is handled here. |
| // DrawEdit is used to vertically scale 90 deg rotated text. |
| bNeedEdit = sal_True; |
| } |
| else if ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) // horizontal |
| { |
| long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin; |
| long nScaleSize = aVars.GetTextSize().Width(); // without margin |
| |
| if ( nScaleSize > 0 ) // 0 if the text is empty (formulas, number formats) |
| { |
| long nScale = ( nAvailable * 100 ) / nScaleSize; |
| |
| aVars.SetShrinkScale( nScale, nOldScript ); |
| long nNewSize = aVars.GetTextSize().Width(); |
| |
| sal_uInt16 nShrinkAgain = 0; |
| while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX ) |
| { |
| // If the text is still too large, reduce the scale again by 10%, until it fits, |
| // at most 7 times (it's less than 50% of the calculated scale then). |
| |
| nScale = ( nScale * 9 ) / 10; |
| aVars.SetShrinkScale( nScale, nOldScript ); |
| nNewSize = aVars.GetTextSize().Width(); |
| ++nShrinkAgain; |
| } |
| // If even at half the size the font still isn't rendered smaller, |
| // fall back to normal clipping (showing ### for numbers). |
| if ( nNewSize <= nAvailable ) |
| aAreaParam.mbLeftClip = aAreaParam.mbRightClip = sal_False; |
| |
| pOldPattern = NULL; |
| } |
| } |
| } |
| |
| if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip ) |
| { |
| long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin; |
| long nRepeatSize = aVars.GetTextSize().Width(); // without margin |
| // When formatting for the printer, the text sizes don't always add up. |
| // Round down (too few repetitions) rather than exceeding the cell size then: |
| if ( pFmtDevice != pRefDevice ) |
| ++nRepeatSize; |
| if ( nRepeatSize > 0 ) |
| { |
| long nRepeatCount = nAvailable / nRepeatSize; |
| if ( nRepeatCount > 1 ) |
| { |
| String aCellStr = aVars.GetString(); |
| String aRepeated = aCellStr; |
| for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ ) |
| aRepeated.Append( aCellStr ); |
| aVars.SetAutoText( aRepeated ); |
| } |
| } |
| } |
| |
| // use edit engine if automatic line breaks are needed |
| if ( bBreak ) |
| { |
| if ( aVars.GetOrient() == SVX_ORIENTATION_STANDARD ) |
| bNeedEdit = ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ); |
| else |
| { |
| long nHeight = aVars.GetTextSize().Height() + |
| (long)(aVars.GetMargin()->GetTopMargin()*nPPTY) + |
| (long)(aVars.GetMargin()->GetBottomMargin()*nPPTY); |
| bNeedEdit = ( nHeight > aAreaParam.maClipRect.GetHeight() ); |
| } |
| } |
| } |
| if (bNeedEdit) |
| { |
| // mark the cell in CellInfo to be drawn in DrawEdit: |
| // Cells to the left are marked directly, cells to the |
| // right are handled by the flag for nX2 |
| SCCOL nMarkX = ( nCellX <= nX2 ) ? nCellX : nX2; |
| RowInfo* pMarkRowInfo = ( nCellY == nY ) ? pThisRowInfo : &pRowInfo[0]; |
| pMarkRowInfo->pCellInfo[nMarkX+1].bEditEngine = sal_True; |
| bDoCell = sal_False; // don't draw here |
| } |
| if ( bDoCell ) |
| { |
| if ( bCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) ) |
| { |
| // Adjust the decimals to fit the available column width. |
| aVars.SetTextToWidthOrHash(pCell, aAreaParam.mnColWidth - nTotalMargin); |
| nNeededWidth = aVars.GetTextSize().Width() + |
| (long) ( aVars.GetLeftTotal() * nPPTX ) + |
| (long) ( aVars.GetMargin()->GetRightMargin() * nPPTX ); |
| if ( nNeededWidth <= aAreaParam.maClipRect.GetWidth() ) |
| aAreaParam.mbLeftClip = aAreaParam.mbRightClip = sal_False; |
| |
| // If the "###" replacement doesn't fit into the cells, no clip marks |
| // are shown, as the "###" already denotes too little space. |
| // The rectangles from the first GetOutputArea call remain valid. |
| } |
| |
| long nJustPosX = aAreaParam.maAlignRect.Left(); // "justified" - effect of alignment will be added |
| long nJustPosY = aAreaParam.maAlignRect.Top(); |
| long nAvailWidth = aAreaParam.maAlignRect.GetWidth(); |
| long nOutHeight = aAreaParam.maAlignRect.GetHeight(); |
| |
| sal_Bool bOutside = ( aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW ); |
| if ( aAreaParam.maClipRect.Left() < nScrX ) |
| { |
| aAreaParam.maClipRect.Left() = nScrX; |
| aAreaParam.mbLeftClip = sal_True; |
| } |
| if ( aAreaParam.maClipRect.Right() > nScrX + nScrW ) |
| { |
| aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one? |
| aAreaParam.mbRightClip = sal_True; |
| } |
| |
| sal_Bool bHClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip; |
| sal_Bool bVClip = sal_False; |
| |
| if ( aAreaParam.maClipRect.Top() < nScrY ) |
| { |
| aAreaParam.maClipRect.Top() = nScrY; |
| bVClip = sal_True; |
| } |
| if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH ) |
| { |
| aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one? |
| bVClip = sal_True; |
| } |
| |
| // |
| // horizontalen Platz testen |
| // |
| |
| sal_Bool bRightAdjusted = sal_False; // to correct text width calculation later |
| sal_Bool bNeedEditEngine = sal_False; |
| if ( !bNeedEditEngine && !bOutside ) |
| { |
| switch (eOutHorJust) |
| { |
| case SVX_HOR_JUSTIFY_LEFT: |
| nJustPosX += (long) ( aVars.GetLeftTotal() * nPPTX ); |
| break; |
| case SVX_HOR_JUSTIFY_RIGHT: |
| nJustPosX += nAvailWidth - aVars.GetTextSize().Width() - |
| (long) ( aVars.GetMargin()->GetRightMargin() * nPPTX ); |
| bRightAdjusted = sal_True; |
| break; |
| case SVX_HOR_JUSTIFY_CENTER: |
| nJustPosX += ( nAvailWidth - aVars.GetTextSize().Width() + |
| (long) ( aVars.GetLeftTotal() * nPPTX ) - |
| (long) ( aVars.GetMargin()->GetRightMargin() * nPPTX ) ) / 2; |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| |
| long nTestClipHeight = aVars.GetTextSize().Height(); |
| switch (aVars.GetVerJust()) |
| { |
| case SVX_VER_JUSTIFY_TOP: |
| { |
| long nTop = (long)( aVars.GetMargin()->GetTopMargin() * nPPTY ); |
| nJustPosY += nTop; |
| nTestClipHeight += nTop; |
| } |
| break; |
| case SVX_VER_JUSTIFY_BOTTOM: |
| { |
| long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * nPPTY ); |
| nJustPosY += nOutHeight - aVars.GetTextSize().Height() - nBot; |
| nTestClipHeight += nBot; |
| } |
| break; |
| case SVX_VER_JUSTIFY_CENTER: |
| { |
| long nTop = (long)( aVars.GetMargin()->GetTopMargin() * nPPTY ); |
| long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * nPPTY ); |
| nJustPosY += ( nOutHeight + nTop - |
| aVars.GetTextSize().Height() - nBot ) / 2; |
| nTestClipHeight += Abs( nTop - nBot ); |
| } |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| |
| if ( nTestClipHeight > nOutHeight ) |
| { |
| // kein vertikales Clipping beim Drucken von Zellen mit |
| // optimaler Hoehe, ausser bei Groesse in bedingter Formatierung |
| if ( eType != OUTTYPE_PRINTER || |
| ( pDoc->GetRowFlags( nCellY, nTab ) & CR_MANUALSIZE ) || |
| ( aVars.HasCondHeight() ) ) |
| bVClip = sal_True; |
| } |
| |
| if ( bHClip || bVClip ) |
| { |
| // nur die betroffene Dimension clippen, |
| // damit bei nicht-proportionalem Resize nicht alle |
| // rechtsbuendigen Zahlen abgeschnitten werden: |
| |
| if (!bHClip) |
| { |
| aAreaParam.maClipRect.Left() = nScrX; |
| aAreaParam.maClipRect.Right() = nScrX+nScrW; |
| } |
| if (!bVClip) |
| { |
| aAreaParam.maClipRect.Top() = nScrY; |
| aAreaParam.maClipRect.Bottom() = nScrY+nScrH; |
| } |
| |
| // aClipRect is not used after SetClipRegion/IntersectClipRegion, |
| // so it can be modified here |
| if (bPixelToLogic) |
| aAreaParam.maClipRect = pRefDevice->PixelToLogic( aAreaParam.maClipRect ); |
| |
| if (bMetaFile) |
| { |
| pDev->Push(); |
| pDev->IntersectClipRegion( aAreaParam.maClipRect ); |
| } |
| else |
| pDev->SetClipRegion( Region( aAreaParam.maClipRect ) ); |
| } |
| |
| Point aURLStart( nJustPosX, nJustPosY ); // copy before modifying for orientation |
| |
| switch (aVars.GetOrient()) |
| { |
| case SVX_ORIENTATION_STANDARD: |
| nJustPosY += aVars.GetAscent(); |
| break; |
| case SVX_ORIENTATION_TOPBOTTOM: |
| nJustPosX += aVars.GetTextSize().Width() - aVars.GetAscent(); |
| break; |
| case SVX_ORIENTATION_BOTTOMTOP: |
| nJustPosY += aVars.GetTextSize().Height(); |
| nJustPosX += aVars.GetAscent(); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| |
| // When clipping, the visible part is now completely defined by the alignment, |
| // there's no more special handling to show the right part of RTL text. |
| |
| Point aDrawTextPos( nJustPosX, nJustPosY ); |
| if ( bPixelToLogic ) |
| { |
| // undo text width adjustment in pixels |
| if (bRightAdjusted) |
| aDrawTextPos.X() += aVars.GetTextSize().Width(); |
| |
| aDrawTextPos = pRefDevice->PixelToLogic( aDrawTextPos ); |
| |
| // redo text width adjustment in logic units |
| if (bRightAdjusted) |
| aDrawTextPos.X() -= aVars.GetOriginalWidth(); |
| } |
| |
| // in Metafiles immer DrawTextArray, damit die Positionen mit |
| // aufgezeichnet werden (fuer nicht-proportionales Resize): |
| |
| String aString = aVars.GetString(); |
| if (bMetaFile || pFmtDevice != pDev || aZoomX != aZoomY) |
| { |
| sal_Int32* pDX = new sal_Int32[aString.Len()]; |
| pFmtDevice->GetTextArray( aString, pDX ); |
| |
| if ( !pRefDevice->GetConnectMetaFile() || |
| pRefDevice->GetOutDevType() == OUTDEV_PRINTER ) |
| { |
| double fMul = GetStretch(); |
| xub_StrLen nLen = aString.Len(); |
| for (xub_StrLen i=0; i<nLen; i++) |
| pDX[i] = (long)(pDX[i] / fMul + 0.5); |
| } |
| |
| pDev->DrawTextArray( aDrawTextPos, aString, pDX ); |
| delete[] pDX; |
| } |
| else |
| pDev->DrawText( aDrawTextPos, aString ); |
| |
| if ( bHClip || bVClip ) |
| { |
| if (bMetaFile) |
| pDev->Pop(); |
| else |
| pDev->SetClipRegion(); |
| } |
| |
| // PDF: whole-cell hyperlink from formula? |
| sal_Bool bHasURL = pPDFData && pCell && pCell->GetCellType() == CELLTYPE_FORMULA && |
| static_cast<ScFormulaCell*>(pCell)->IsHyperLinkCell(); |
| if ( bHasURL ) |
| { |
| Rectangle aURLRect( aURLStart, aVars.GetTextSize() ); |
| lcl_DoHyperlinkResult( pDev, aURLRect, pCell ); |
| } |
| } |
| } |
| nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign; |
| } |
| } |
| nPosY += pRowInfo[nArrY].nHeight; |
| } |
| if ( bProgress ) |
| ScProgress::DeleteInterpretProgress(); |
| pDoc->DisableIdle( bWasIdleDisabled ); |
| } |
| |
| // ------------------------------------------------------------------------------- |
| |
| ScFieldEditEngine* ScOutputData::CreateOutputEditEngine() |
| { |
| ScFieldEditEngine* pEngine = new ScFieldEditEngine( pDoc->GetEnginePool() ); |
| pEngine->SetUpdateMode( sal_False ); |
| // a RefDevice always has to be set, otherwise EditEngine would create a VirtualDevice |
| pEngine->SetRefDevice( pFmtDevice ); |
| sal_uInt32 nCtrl = pEngine->GetControlWord(); |
| if ( bShowSpellErrors ) |
| nCtrl |= EE_CNTRL_ONLINESPELLING; |
| if ( eType == OUTTYPE_PRINTER ) |
| nCtrl &= ~EE_CNTRL_MARKFIELDS; |
| if ( eType == OUTTYPE_WINDOW && pRefDevice == pFmtDevice ) |
| nCtrl &= ~EE_CNTRL_FORMAT100; // use the actual MapMode |
| pEngine->SetControlWord( nCtrl ); |
| pDoc->ApplyAsianEditSettings( *pEngine ); |
| pEngine->EnableAutoColor( bUseStyleColor ); |
| pEngine->SetDefaultHorizontalTextDirection( (EEHorizontalTextDirection)pDoc->GetEditTextDirection( nTab ) ); |
| return pEngine; |
| } |
| |
| void lcl_ClearEdit( EditEngine& rEngine ) // Text und Attribute |
| { |
| rEngine.SetUpdateMode( sal_False ); |
| |
| rEngine.SetText(EMPTY_STRING); |
| // keine Para-Attribute uebrigbehalten... |
| const SfxItemSet& rPara = rEngine.GetParaAttribs(0); |
| if (rPara.Count()) |
| rEngine.SetParaAttribs( 0, |
| SfxItemSet( *rPara.GetPool(), rPara.GetRanges() ) ); |
| } |
| |
| sal_Bool lcl_SafeIsValue( ScBaseCell* pCell ) |
| { |
| if (!pCell) |
| return sal_False; |
| |
| sal_Bool bRet = sal_False; |
| switch ( pCell->GetCellType() ) |
| { |
| case CELLTYPE_VALUE: |
| bRet = sal_True; |
| break; |
| case CELLTYPE_FORMULA: |
| { |
| ScFormulaCell* pFCell = (ScFormulaCell*)pCell; |
| if ( pFCell->IsRunning() || pFCell->IsValue() ) |
| bRet = sal_True; |
| } |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| return bRet; |
| } |
| |
| void lcl_ScaleFonts( EditEngine& rEngine, long nPercent ) |
| { |
| sal_Bool bUpdateMode = rEngine.GetUpdateMode(); |
| if ( bUpdateMode ) |
| rEngine.SetUpdateMode( sal_False ); |
| |
| sal_uInt16 nParCount = rEngine.GetParagraphCount(); |
| for (sal_uInt16 nPar=0; nPar<nParCount; nPar++) |
| { |
| SvUShorts aPortions; |
| rEngine.GetPortions( nPar, aPortions ); |
| |
| sal_uInt16 nPCount = aPortions.Count(); |
| sal_uInt16 nStart = 0; |
| for ( sal_uInt16 nPos=0; nPos<nPCount; nPos++ ) |
| { |
| sal_uInt16 nEnd = aPortions.GetObject( nPos ); |
| ESelection aSel( nPar, nStart, nPar, nEnd ); |
| SfxItemSet aAttribs = rEngine.GetAttribs( aSel ); |
| |
| long nWestern = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT)).GetHeight(); |
| long nCJK = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CJK)).GetHeight(); |
| long nCTL = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CTL)).GetHeight(); |
| |
| nWestern = ( nWestern * nPercent ) / 100; |
| nCJK = ( nCJK * nPercent ) / 100; |
| nCTL = ( nCTL * nPercent ) / 100; |
| |
| aAttribs.Put( SvxFontHeightItem( nWestern, 100, EE_CHAR_FONTHEIGHT ) ); |
| aAttribs.Put( SvxFontHeightItem( nCJK, 100, EE_CHAR_FONTHEIGHT_CJK ) ); |
| aAttribs.Put( SvxFontHeightItem( nCTL, 100, EE_CHAR_FONTHEIGHT_CTL ) ); |
| |
| rEngine.QuickSetAttribs( aAttribs, aSel ); //! remove paragraph attributes from aAttribs? |
| |
| nStart = nEnd; |
| } |
| } |
| |
| if ( bUpdateMode ) |
| rEngine.SetUpdateMode( sal_True ); |
| } |
| |
| long lcl_GetEditSize( EditEngine& rEngine, sal_Bool bWidth, sal_Bool bSwap, long nAttrRotate ) |
| { |
| if ( bSwap ) |
| bWidth = !bWidth; |
| |
| if ( nAttrRotate ) |
| { |
| long nRealWidth = (long) rEngine.CalcTextWidth(); |
| long nRealHeight = rEngine.GetTextHeight(); |
| |
| // assuming standard mode, otherwise width isn't used |
| |
| double nRealOrient = nAttrRotate * F_PI18000; // 1/100th degrees |
| double nAbsCos = fabs( cos( nRealOrient ) ); |
| double nAbsSin = fabs( sin( nRealOrient ) ); |
| if ( bWidth ) |
| return (long) ( nRealWidth * nAbsCos + nRealHeight * nAbsSin ); |
| else |
| return (long) ( nRealHeight * nAbsCos + nRealWidth * nAbsSin ); |
| } |
| else if ( bWidth ) |
| return (long) rEngine.CalcTextWidth(); |
| else |
| return rEngine.GetTextHeight(); |
| } |
| |
| |
| void ScOutputData::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 ) |
| { |
| if ( !bWidth ) |
| { |
| // vertical |
| |
| long nScaleSize = bPixelToLogic ? |
| pRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight; |
| |
| // Don't scale if it fits already. |
| // Allowing to extend into the margin, to avoid scaling at optimal height. |
| if ( nScaleSize <= rAlignRect.GetHeight() ) |
| return; |
| |
| sal_Bool bSwap = ( nOrient == SVX_ORIENTATION_TOPBOTTOM || nOrient == SVX_ORIENTATION_BOTTOMTOP ); |
| long nAvailable = rAlignRect.GetHeight() - nTopM - nBottomM; |
| long nScale = ( nAvailable * 100 ) / nScaleSize; |
| |
| lcl_ScaleFonts( rEngine, nScale ); |
| rEngineHeight = lcl_GetEditSize( rEngine, sal_False, bSwap, nAttrRotate ); |
| long nNewSize = bPixelToLogic ? |
| pRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight; |
| |
| sal_uInt16 nShrinkAgain = 0; |
| while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX ) |
| { |
| // further reduce, like in DrawStrings |
| lcl_ScaleFonts( rEngine, 90 ); // reduce by 10% |
| rEngineHeight = lcl_GetEditSize( rEngine, sal_False, bSwap, nAttrRotate ); |
| nNewSize = bPixelToLogic ? |
| pRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight; |
| ++nShrinkAgain; |
| } |
| |
| // sizes for further processing (alignment etc): |
| rEngineWidth = lcl_GetEditSize( rEngine, sal_True, bSwap, nAttrRotate ); |
| long nPixelWidth = bPixelToLogic ? |
| pRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth; |
| rNeededPixel = nPixelWidth + nLeftM + nRightM; |
| } |
| else if ( rLeftClip || rRightClip ) |
| { |
| // horizontal |
| |
| long nAvailable = rAlignRect.GetWidth() - nLeftM - nRightM; |
| long nScaleSize = rNeededPixel - nLeftM - nRightM; // without margin |
| |
| if ( nScaleSize <= nAvailable ) |
| return; |
| |
| long nScale = ( nAvailable * 100 ) / nScaleSize; |
| |
| lcl_ScaleFonts( rEngine, nScale ); |
| rEngineWidth = lcl_GetEditSize( rEngine, sal_True, sal_False, nAttrRotate ); |
| long nNewSize = bPixelToLogic ? |
| pRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth; |
| |
| sal_uInt16 nShrinkAgain = 0; |
| while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX ) |
| { |
| // further reduce, like in DrawStrings |
| lcl_ScaleFonts( rEngine, 90 ); // reduce by 10% |
| rEngineWidth = lcl_GetEditSize( rEngine, sal_True, sal_False, nAttrRotate ); |
| nNewSize = bPixelToLogic ? |
| pRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth; |
| ++nShrinkAgain; |
| } |
| if ( nNewSize <= nAvailable ) |
| rLeftClip = rRightClip = sal_False; |
| |
| // sizes for further processing (alignment etc): |
| rNeededPixel = nNewSize + nLeftM + nRightM; |
| rEngineHeight = lcl_GetEditSize( rEngine, sal_False, sal_False, nAttrRotate ); |
| } |
| } |
| |
| void ScOutputData::DrawEdit(sal_Bool bPixelToLogic) |
| { |
| vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() ); |
| |
| Size aMinSize = pRefDevice->PixelToLogic(Size(0,100)); // erst darueber wird ausgegeben |
| // sal_uInt32 nMinHeight = aMinSize.Height() / 200; // 1/2 Pixel |
| |
| ScModule* pScMod = SC_MOD(); |
| sal_Int32 nConfBackColor = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; |
| // #105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True) |
| sal_Bool bCellContrast = bUseStyleColor && |
| Application::GetSettings().GetStyleSettings().GetHighContrastMode(); |
| |
| ScFieldEditEngine* pEngine = NULL; |
| sal_Bool bHyphenatorSet = sal_False; |
| const ScPatternAttr* pOldPattern = NULL; |
| const SfxItemSet* pOldCondSet = NULL; |
| ScBaseCell* pCell = NULL; |
| |
| Size aRefOne = pRefDevice->PixelToLogic(Size(1,1)); |
| |
| long nInitPosX = nScrX; |
| if ( bLayoutRTL ) |
| { |
| #if 0 |
| Size aOnePixel = pDev->PixelToLogic(Size(1,1)); |
| long nOneX = aOnePixel.Width(); |
| nInitPosX += nMirrorW - nOneX; |
| #endif |
| nInitPosX += nMirrorW - 1; |
| } |
| long nLayoutSign = bLayoutRTL ? -1 : 1; |
| |
| //! store nLastContentCol as member! |
| SCCOL nLastContentCol = MAXCOL; |
| if ( nX2 < MAXCOL ) |
| nLastContentCol = sal::static_int_cast<SCCOL>( |
| nLastContentCol - pDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) ); |
| |
| long nRowPosY = nScrY; |
| for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 fuer Reste von zusammengefassten |
| { |
| RowInfo* pThisRowInfo = &pRowInfo[nArrY]; |
| // long nCellHeight = (long) pThisRowInfo->nHeight; |
| if (nArrY==1) nRowPosY = nScrY; // vorher wird einzeln berechnet |
| |
| if ( pThisRowInfo->bChanged || nArrY==0 ) |
| { |
| long nPosX = 0; |
| for (SCCOL nX=0; nX<=nX2; nX++) // wegen Ueberhaengen |
| { |
| if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually |
| |
| CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1]; |
| if (pInfo->bEditEngine) |
| { |
| SCROW nY = pThisRowInfo->nRowNo; |
| |
| SCCOL nCellX = nX; // position where the cell really starts |
| SCROW nCellY = nY; |
| sal_Bool bDoCell = sal_False; |
| |
| long nPosY = nRowPosY; |
| if ( nArrY == 0 ) |
| { |
| nPosY = nScrY; |
| nY = pRowInfo[1].nRowNo; |
| SCCOL nOverX; // start of the merged cells |
| SCROW nOverY; |
| if (GetMergeOrigin( nX,nY, 1, nOverX,nOverY, sal_True )) |
| { |
| nCellX = nOverX; |
| nCellY = nOverY; |
| bDoCell = sal_True; |
| } |
| } |
| else if ( nX == nX2 && !pThisRowInfo->pCellInfo[nX+1].pCell ) |
| { |
| // Rest of a long text further to the right? |
| |
| SCCOL nTempX=nX; |
| while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY )) |
| ++nTempX; |
| |
| if ( nTempX > nX && |
| !IsEmptyCellText( pThisRowInfo, nTempX, nY ) && |
| !pDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) ) |
| { |
| nCellX = nTempX; |
| bDoCell = sal_True; |
| } |
| } |
| else |
| { |
| bDoCell = sal_True; |
| } |
| |
| if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow ) |
| bDoCell = sal_False; |
| |
| const ScPatternAttr* pPattern = NULL; |
| const SfxItemSet* pCondSet = NULL; |
| if (bDoCell) |
| { |
| if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 && |
| !pDoc->ColHidden(nCellX, nTab) ) |
| { |
| CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1]; |
| pPattern = rCellInfo.pPatternAttr; |
| pCondSet = rCellInfo.pConditionSet; |
| pCell = rCellInfo.pCell; |
| } |
| else // get from document |
| { |
| pPattern = pDoc->GetPattern( nCellX, nCellY, nTab ); |
| pCondSet = pDoc->GetCondResult( nCellX, nCellY, nTab ); |
| GetVisibleCell( nCellX, nCellY, nTab, pCell ); |
| } |
| if ( !pCell ) |
| bDoCell = sal_False; |
| } |
| if (bDoCell) |
| { |
| sal_Bool bHidden = sal_False; |
| |
| // |
| // Create EditEngine |
| // |
| |
| if (!pEngine) |
| pEngine = CreateOutputEditEngine(); |
| else |
| lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False) |
| |
| sal_Bool bCellIsValue = lcl_SafeIsValue(pCell); |
| |
| SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&) |
| pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet)).GetValue(); |
| sal_Bool bBreak = ( eHorJust == SVX_HOR_JUSTIFY_BLOCK ) || |
| ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue(); |
| sal_Bool bRepeat = ( eHorJust == SVX_HOR_JUSTIFY_REPEAT && !bBreak ); |
| sal_Bool bShrink = !bBreak && !bRepeat && static_cast<const SfxBoolItem&> |
| (pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue(); |
| SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet ); |
| long nAttrRotate = ((const SfxInt32Item&)pPattern-> |
| GetItem(ATTR_ROTATE_VALUE, pCondSet)).GetValue(); |
| if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT ) |
| { |
| // ignore orientation/rotation if "repeat" is active |
| eOrient = SVX_ORIENTATION_STANDARD; |
| nAttrRotate = 0; |
| |
| // #i31843# "repeat" with "line breaks" is treated as default alignment |
| // (but rotation is still disabled) |
| if ( bBreak ) |
| eHorJust = SVX_HOR_JUSTIFY_STANDARD; |
| } |
| if ( eOrient==SVX_ORIENTATION_STANDARD && nAttrRotate ) |
| { |
| //! Flag setzen, um die Zelle in DrawRotated wiederzufinden ? |
| //! (oder Flag schon bei DrawBackground, dann hier keine Abfrage) |
| bHidden = sal_True; // gedreht wird getrennt ausgegeben |
| } |
| |
| sal_Bool bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED && |
| ((const SfxBoolItem&)pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() ); |
| if ( bAsianVertical ) |
| { |
| // in asian mode, use EditEngine::SetVertical instead of EE_CNTRL_ONECHARPERLINE |
| eOrient = SVX_ORIENTATION_STANDARD; |
| // default alignment for asian vertical mode is top-right |
| if ( eHorJust == SVX_HOR_JUSTIFY_STANDARD ) |
| eHorJust = SVX_HOR_JUSTIFY_RIGHT; |
| } |
| |
| SvxCellHorJustify eOutHorJust = |
| ( eHorJust != SVX_HOR_JUSTIFY_STANDARD ) ? eHorJust : |
| ( bCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT ); |
| |
| if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT ) |
| eOutHorJust = SVX_HOR_JUSTIFY_LEFT; // repeat is not yet implemented |
| |
| |
| //! if ( !bHidden && eType == OUTTYPE_PRINTER && |
| //! pDev->GetOutDevType() == OUTDEV_WINDOW && |
| //! ((const SvxFontHeightItem&)pPattern-> |
| //! GetItem(ATTR_FONT_HEIGHT)).GetHeight() <= nMinHeight ) |
| //! { |
| //! Point aPos( nStartX, nStartY ); |
| //! pDev->DrawPixel( aPos, |
| //! ((const SvxColorItem&)pPattern-> |
| //! GetItem( ATTR_FONT_COLOR )).GetValue() ); |
| //! bHidden = sal_True; |
| //! } |
| |
| if (!bHidden) |
| { |
| //! mirror margin values for RTL? |
| //! move margin down to after final GetOutputArea call |
| |
| const SvxMarginItem* pMargin = (const SvxMarginItem*) |
| &pPattern->GetItem(ATTR_MARGIN, pCondSet); |
| sal_uInt16 nIndent = 0; |
| if ( eHorJust == SVX_HOR_JUSTIFY_LEFT ) |
| nIndent = ((const SfxUInt16Item&)pPattern-> |
| GetItem(ATTR_INDENT, pCondSet)).GetValue(); |
| |
| long nLeftM = (long) ( (pMargin->GetLeftMargin() + nIndent) * nPPTX ); |
| long nTopM = (long) ( pMargin->GetTopMargin() * nPPTY ); |
| long nRightM = (long) ( pMargin->GetRightMargin() * nPPTX ); |
| long nBottomM = (long) ( pMargin->GetBottomMargin() * nPPTY ); |
| |
| SCCOL nXForPos = nX; |
| if ( nXForPos < nX1 ) |
| { |
| nXForPos = nX1; |
| nPosX = nInitPosX; |
| } |
| SCSIZE nArrYForPos = nArrY; |
| if ( nArrYForPos < 1 ) |
| { |
| nArrYForPos = 1; |
| nPosY = nScrY; |
| } |
| |
| OutputAreaParam aAreaParam; |
| |
| // |
| // Initial page size - large for normal text, cell size for automatic line breaks |
| // |
| |
| Size aPaperSize = Size( 1000000, 1000000 ); |
| if ( bBreak || eOrient == SVX_ORIENTATION_STACKED || bAsianVertical ) |
| { |
| //! also stacked, AsianVertical |
| |
| // call GetOutputArea with nNeeded=0, to get only the cell width |
| |
| //! handle nArrY == 0 |
| GetOutputArea( nXForPos, nArrYForPos, nPosX, nPosY, nCellX, nCellY, 0, |
| *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust), |
| bCellIsValue, true, false, aAreaParam ); |
| |
| //! special ScEditUtil handling if formatting for printer |
| |
| if ( eOrient == SVX_ORIENTATION_TOPBOTTOM || eOrient == SVX_ORIENTATION_BOTTOMTOP ) |
| aPaperSize.Width() = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM; |
| else |
| aPaperSize.Width() = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM; |
| |
| if (bAsianVertical && bBreak) |
| { |
| // add some extra height (default margin value) for safety |
| // as long as GetEditArea isn't used below |
| long nExtraHeight = (long)( 20 * nPPTY ); |
| aPaperSize.Height() = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM + nExtraHeight; |
| } |
| } |
| if (bPixelToLogic) |
| { |
| Size aLogicSize = pRefDevice->PixelToLogic(aPaperSize); |
| if ( bBreak && !bAsianVertical && pRefDevice != pFmtDevice ) |
| { |
| // #i85342# screen display and formatting for printer, |
| // use same GetEditArea call as in ScViewData::SetEditEngine |
| |
| Fraction aFract(1,1); |
| Rectangle aUtilRect = ScEditUtil( pDoc, nCellX, nCellY, nTab, Point(0,0), pFmtDevice, |
| HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( pPattern, sal_False ); |
| aLogicSize.Width() = aUtilRect.GetWidth(); |
| } |
| pEngine->SetPaperSize(aLogicSize); |
| } |
| else |
| pEngine->SetPaperSize(aPaperSize); |
| |
| // |
| // Fill the EditEngine (cell attributes and text) |
| // |
| |
| SvxCellVerJustify eVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&) |
| pPattern->GetItem(ATTR_VER_JUSTIFY, pCondSet)).GetValue(); |
| |
| // default alignment for asian vertical mode is top-right |
| if ( bAsianVertical && eVerJust == SVX_VER_JUSTIFY_STANDARD ) |
| eVerJust = SVX_VER_JUSTIFY_TOP; |
| |
| // syntax highlighting mode is ignored here |
| // StringDiffer doesn't look at hyphenate, language items |
| if ( pPattern != pOldPattern || pCondSet != pOldCondSet ) |
| { |
| SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() ); |
| pPattern->FillEditItemSet( pSet, pCondSet ); |
| |
| pEngine->SetDefaults( pSet ); |
| pOldPattern = pPattern; |
| pOldCondSet = pCondSet; |
| |
| sal_uLong nControl = pEngine->GetControlWord(); |
| if (eOrient==SVX_ORIENTATION_STACKED) |
| nControl |= EE_CNTRL_ONECHARPERLINE; |
| else |
| nControl &= ~EE_CNTRL_ONECHARPERLINE; |
| pEngine->SetControlWord( nControl ); |
| |
| if ( !bHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) |
| { |
| // set hyphenator the first time it is needed |
| com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() ); |
| pEngine->SetHyphenator( xXHyphenator ); |
| bHyphenatorSet = sal_True; |
| } |
| |
| Color aBackCol = ((const SvxBrushItem&) |
| pPattern->GetItem( ATTR_BACKGROUND, pCondSet )).GetColor(); |
| if ( bUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) ) |
| aBackCol.SetColor( nConfBackColor ); |
| pEngine->SetBackgroundColor( aBackCol ); |
| } |
| |
| // horizontal alignment now may depend on cell content |
| // (for values with number formats with mixed script types) |
| // -> always set adjustment |
| |
| SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT; |
| if (eOrient==SVX_ORIENTATION_STACKED) |
| eSvxAdjust = SVX_ADJUST_CENTER; |
| else if (bBreak) |
| { |
| if (eOrient==SVX_ORIENTATION_STANDARD && !bAsianVertical) |
| switch (eHorJust) |
| { |
| case SVX_HOR_JUSTIFY_STANDARD: |
| eSvxAdjust = bCellIsValue ? SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT; |
| break; |
| case SVX_HOR_JUSTIFY_LEFT: |
| case SVX_HOR_JUSTIFY_REPEAT: // nicht implementiert |
| eSvxAdjust = SVX_ADJUST_LEFT; |
| break; |
| case SVX_HOR_JUSTIFY_RIGHT: |
| eSvxAdjust = SVX_ADJUST_RIGHT; |
| break; |
| case SVX_HOR_JUSTIFY_CENTER: |
| eSvxAdjust = SVX_ADJUST_CENTER; |
| break; |
| case SVX_HOR_JUSTIFY_BLOCK: |
| eSvxAdjust = SVX_ADJUST_BLOCK; |
| break; |
| } |
| else |
| switch (eVerJust) |
| { |
| case SVX_VER_JUSTIFY_TOP: |
| eSvxAdjust = (eOrient==SVX_ORIENTATION_TOPBOTTOM || bAsianVertical) ? |
| SVX_ADJUST_LEFT : SVX_ADJUST_RIGHT; |
| break; |
| case SVX_VER_JUSTIFY_CENTER: |
| eSvxAdjust = SVX_ADJUST_CENTER; |
| break; |
| case SVX_VER_JUSTIFY_BOTTOM: |
| case SVX_HOR_JUSTIFY_STANDARD: |
| eSvxAdjust = (eOrient==SVX_ORIENTATION_TOPBOTTOM || bAsianVertical) ? |
| SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT; |
| break; |
| } |
| } |
| pEngine->SetDefaultItem( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) ); |
| |
| // Read content from cell |
| |
| sal_Bool bWrapFields = sal_False; |
| if (pCell) |
| { |
| if (pCell->GetCellType() == CELLTYPE_EDIT) |
| { |
| const EditTextObject* pData; |
| ((ScEditCell*)pCell)->GetData(pData); |
| |
| if (pData) |
| { |
| pEngine->SetText(*pData); |
| |
| if ( bBreak && !bAsianVertical && pData->HasField() ) |
| { |
| // Fields aren't wrapped, so clipping is enabled to prevent |
| // a field from being drawn beyond the cell size |
| |
| bWrapFields = sal_True; |
| } |
| } |
| else |
| { |
| DBG_ERROR("pData == 0"); |
| } |
| } |
| else |
| { |
| sal_uLong nFormat = pPattern->GetNumberFormat( |
| pDoc->GetFormatTable(), pCondSet ); |
| String aString; |
| Color* pColor; |
| ScCellFormat::GetString( pCell, |
| nFormat,aString, &pColor, |
| *pDoc->GetFormatTable(), |
| bShowNullValues, |
| bShowFormulas, |
| ftCheck ); |
| |
| pEngine->SetText(aString); |
| if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) ) |
| lcl_SetEditColor( *pEngine, *pColor ); |
| } |
| |
| if ( bSyntaxMode ) |
| SetEditSyntaxColor( *pEngine, pCell ); |
| else if ( bUseStyleColor && bForceAutoColor ) |
| lcl_SetEditColor( *pEngine, COL_AUTO ); //! or have a flag at EditEngine |
| } |
| else |
| { |
| DBG_ERROR("pCell == NULL"); |
| } |
| |
| pEngine->SetVertical( bAsianVertical ); |
| pEngine->SetUpdateMode( sal_True ); // after SetText, before CalcTextWidth/GetTextHeight |
| |
| // |
| // Get final output area using the calculated width |
| // |
| |
| long nEngineWidth; |
| if ( bBreak && eOrient != SVX_ORIENTATION_STACKED && !bAsianVertical ) |
| nEngineWidth = 0; |
| else |
| nEngineWidth = (long) pEngine->CalcTextWidth(); |
| long nEngineHeight = pEngine->GetTextHeight(); |
| |
| if (eOrient != SVX_ORIENTATION_STANDARD && |
| eOrient != SVX_ORIENTATION_STACKED) |
| { |
| long nTemp = nEngineWidth; |
| nEngineWidth = nEngineHeight; |
| nEngineHeight = nTemp; |
| } |
| |
| if (eOrient == SVX_ORIENTATION_STACKED) |
| nEngineWidth = nEngineWidth * 11 / 10; |
| |
| long nNeededPixel = nEngineWidth; |
| if (bPixelToLogic) |
| nNeededPixel = pRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width(); |
| nNeededPixel += nLeftM + nRightM; |
| |
| if ( ( !bBreak && eOrient != SVX_ORIENTATION_STACKED ) || bAsianVertical || bShrink ) |
| { |
| // for break, the first GetOutputArea call is sufficient |
| GetOutputArea( nXForPos, nArrYForPos, nPosX, nPosY, nCellX, nCellY, nNeededPixel, |
| *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust), |
| bCellIsValue || bRepeat || bShrink, false, false, aAreaParam ); |
| |
| if ( bShrink ) |
| { |
| sal_Bool bWidth = ( eOrient == SVX_ORIENTATION_STANDARD && !bAsianVertical ); |
| ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, |
| nLeftM, nTopM, nRightM, nBottomM, bWidth, |
| sal::static_int_cast<sal_uInt16>(eOrient), 0, bPixelToLogic, |
| nEngineWidth, nEngineHeight, nNeededPixel, |
| aAreaParam.mbLeftClip, aAreaParam.mbRightClip ); |
| } |
| |
| if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && pEngine->GetParagraphCount() == 1 ) |
| { |
| // First check if twice the space for the formatted text is available |
| // (otherwise just keep it unchanged). |
| |
| long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin |
| long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM; |
| if ( nAvailable >= 2 * nFormatted ) |
| { |
| // "repeat" is handled with unformatted text (for performance reasons) |
| String aCellStr = pEngine->GetText(); |
| pEngine->SetText( aCellStr ); |
| |
| long nRepeatSize = (long) pEngine->CalcTextWidth(); |
| if (bPixelToLogic) |
| nRepeatSize = pRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width(); |
| if ( pFmtDevice != pRefDevice ) |
| ++nRepeatSize; |
| if ( nRepeatSize > 0 ) |
| { |
| long nRepeatCount = nAvailable / nRepeatSize; |
| if ( nRepeatCount > 1 ) |
| { |
| String aRepeated = aCellStr; |
| for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ ) |
| aRepeated.Append( aCellStr ); |
| pEngine->SetText( aRepeated ); |
| |
| nEngineHeight = pEngine->GetTextHeight(); |
| nEngineWidth = (long) pEngine->CalcTextWidth(); |
| if (bPixelToLogic) |
| nNeededPixel = pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width(); |
| else |
| nNeededPixel = nEngineWidth; |
| nNeededPixel += nLeftM + nRightM; |
| } |
| } |
| } |
| } |
| |
| if ( bCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) ) |
| { |
| pEngine->SetText( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("###")) ); |
| nEngineWidth = (long) pEngine->CalcTextWidth(); |
| if (bPixelToLogic) |
| nNeededPixel = pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width(); |
| else |
| nNeededPixel = nEngineWidth; |
| nNeededPixel += nLeftM + nRightM; |
| |
| // No clip marks if "###" doesn't fit (same as in DrawStrings) |
| } |
| |
| if ( eOutHorJust != SVX_HOR_JUSTIFY_LEFT && eOrient == SVX_ORIENTATION_STANDARD ) |
| { |
| aPaperSize.Width() = nNeededPixel + 1; |
| if (bPixelToLogic) |
| pEngine->SetPaperSize(pRefDevice->PixelToLogic(aPaperSize)); |
| else |
| pEngine->SetPaperSize(aPaperSize); |
| } |
| } |
| |
| long nStartX = aAreaParam.maAlignRect.Left(); |
| long nStartY = aAreaParam.maAlignRect.Top(); |
| long nCellWidth = aAreaParam.maAlignRect.GetWidth(); |
| long nOutWidth = nCellWidth - 1 - nLeftM - nRightM; |
| long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM; |
| |
| if ( bBreak || eOrient != SVX_ORIENTATION_STANDARD || bAsianVertical ) |
| { |
| // text with automatic breaks is aligned only within the |
| // edit engine's paper size, the output of the whole area |
| // is always left-aligned |
| |
| nStartX += nLeftM; |
| } |
| else |
| { |
| if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT ) |
| nStartX -= nNeededPixel - nCellWidth + nRightM + 1; |
| else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER ) |
| nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2; |
| else |
| nStartX += nLeftM; |
| } |
| |
| sal_Bool bOutside = ( aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW ); |
| if ( aAreaParam.maClipRect.Left() < nScrX ) |
| { |
| aAreaParam.maClipRect.Left() = nScrX; |
| aAreaParam.mbLeftClip = true; |
| } |
| if ( aAreaParam.maClipRect.Right() > nScrX + nScrW ) |
| { |
| aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one? |
| aAreaParam.mbRightClip = true; |
| } |
| |
| if ( !bHidden && !bOutside ) |
| { |
| bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip; |
| sal_Bool bSimClip = sal_False; |
| |
| if ( bWrapFields ) |
| { |
| // Fields in a cell with automatic breaks: clip to cell width |
| bClip = sal_True; |
| } |
| |
| if ( aAreaParam.maClipRect.Top() < nScrY ) |
| { |
| aAreaParam.maClipRect.Top() = nScrY; |
| bClip = sal_True; |
| } |
| if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH ) |
| { |
| aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one? |
| bClip = sal_True; |
| } |
| |
| Size aCellSize; // output area, excluding margins, in logical units |
| if (bPixelToLogic) |
| aCellSize = pRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) ); |
| else |
| aCellSize = Size( nOutWidth, nOutHeight ); |
| |
| if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() ) |
| { |
| const ScMergeAttr* pMerge = |
| (ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE); |
| sal_Bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1; |
| |
| // Don't clip for text height when printing rows with optimal height, |
| // except when font size is from conditional formatting. |
| //! Allow clipping when vertically merged? |
| if ( eType != OUTTYPE_PRINTER || |
| ( pDoc->GetRowFlags( nCellY, nTab ) & CR_MANUALSIZE ) || |
| ( pCondSet && SFX_ITEM_SET == |
| pCondSet->GetItemState(ATTR_FONT_HEIGHT, sal_True) ) ) |
| bClip = sal_True; |
| else |
| bSimClip = sal_True; |
| |
| // Show clip marks if height is at least 5pt too small and |
| // there are several lines of text. |
| // Not for asian vertical text, because that would interfere |
| // with the default right position of the text. |
| // Only with automatic line breaks, to avoid having to find |
| // the cells with the horizontal end of the text again. |
| if ( nEngineHeight - aCellSize.Height() > 100 && |
| ( bBreak || eOrient == SVX_ORIENTATION_STACKED ) && |
| !bAsianVertical && bMarkClipped && |
| ( pEngine->GetParagraphCount() > 1 || pEngine->GetLineCount(0) > 1 ) ) |
| { |
| CellInfo* pClipMarkCell = NULL; |
| if ( bMerged ) |
| { |
| // anywhere in the merged area... |
| SCCOL nClipX = ( nX < nX1 ) ? nX1 : nX; |
| pClipMarkCell = &pRowInfo[(nArrY != 0) ? nArrY : 1].pCellInfo[nClipX+1]; |
| } |
| else |
| pClipMarkCell = &pThisRowInfo->pCellInfo[nX+1]; |
| |
| pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left? |
| bAnyClipped = sal_True; |
| |
| long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX ); |
| if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() ) |
| aAreaParam.maClipRect.Right() -= nMarkPixel; |
| } |
| } |
| |
| #if 0 |
| long nClipStartY = nStartY; |
| if (nArrY==0 || bVisChanged) |
| { |
| if ( nClipStartY < nRowPosY ) |
| { |
| long nDif = nRowPosY - nClipStartY; |
| bClip = sal_True; |
| nClipStartY = nRowPosY; |
| aClipSize.Height() -= nDif; |
| } |
| } |
| #endif |
| |
| Rectangle aLogicClip; |
| if (bClip || bSimClip) |
| { |
| // Clip marks are already handled in GetOutputArea |
| |
| if (bPixelToLogic) |
| aLogicClip = pRefDevice->PixelToLogic( aAreaParam.maClipRect ); |
| else |
| aLogicClip = aAreaParam.maClipRect; |
| |
| if (bClip) // bei bSimClip nur aClipRect initialisieren |
| { |
| if (bMetaFile) |
| { |
| pDev->Push(); |
| pDev->IntersectClipRegion( aLogicClip ); |
| } |
| else |
| pDev->SetClipRegion( Region( aLogicClip ) ); |
| } |
| } |
| |
| Point aLogicStart; |
| if (bPixelToLogic) |
| aLogicStart = pRefDevice->PixelToLogic( Point(nStartX,nStartY) ); |
| else |
| aLogicStart = Point(nStartX, nStartY); |
| if ( eOrient!=SVX_ORIENTATION_STANDARD || bAsianVertical || !bBreak ) |
| { |
| long nAvailWidth = aCellSize.Width(); |
| // space for AutoFilter is already handled in GetOutputArea |
| |
| // horizontal alignment |
| |
| if (eOrient==SVX_ORIENTATION_STANDARD && !bAsianVertical) |
| { |
| if (eHorJust==SVX_HOR_JUSTIFY_RIGHT || |
| eHorJust==SVX_HOR_JUSTIFY_CENTER || |
| (eHorJust==SVX_HOR_JUSTIFY_STANDARD && bCellIsValue) ) |
| { |
| pEngine->SetUpdateMode( sal_False ); |
| |
| SvxAdjust eEditAdjust = |
| (eHorJust==SVX_HOR_JUSTIFY_CENTER) ? |
| SVX_ADJUST_CENTER : SVX_ADJUST_RIGHT; |
| pEngine->SetDefaultItem( |
| SvxAdjustItem( eEditAdjust, EE_PARA_JUST ) ); |
| |
| // #55142# reset adjustment for the next cell |
| pOldPattern = NULL; |
| |
| pEngine->SetUpdateMode( sal_True ); |
| } |
| } |
| else |
| { |
| if (eHorJust==SVX_HOR_JUSTIFY_RIGHT) |
| aLogicStart.X() += nAvailWidth - nEngineWidth; |
| else if (eHorJust==SVX_HOR_JUSTIFY_CENTER) |
| aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2; |
| } |
| } |
| |
| if ( bAsianVertical ) |
| { |
| // paper size is subtracted below |
| aLogicStart.X() += nEngineWidth; |
| } |
| |
| if ( ( bAsianVertical || eOrient == SVX_ORIENTATION_TOPBOTTOM || |
| eOrient == SVX_ORIENTATION_BOTTOMTOP ) && bBreak ) |
| { |
| // vertical adjustment is within the EditEngine |
| if (bPixelToLogic) |
| aLogicStart.Y() += pRefDevice->PixelToLogic(Size(0,nTopM)).Height(); |
| else |
| aLogicStart.Y() += nTopM; |
| } |
| |
| if ( ( eOrient==SVX_ORIENTATION_STANDARD && !bAsianVertical ) || |
| eOrient==SVX_ORIENTATION_STACKED || !bBreak ) |
| { |
| if (eVerJust==SVX_VER_JUSTIFY_BOTTOM || |
| eVerJust==SVX_VER_JUSTIFY_STANDARD) |
| { |
| //! if pRefDevice != pFmtDevice, keep heights in logic units, |
| //! only converting margin? |
| |
| if (bPixelToLogic) |
| aLogicStart.Y() += pRefDevice->PixelToLogic( Size(0, nTopM + |
| pRefDevice->LogicToPixel(aCellSize).Height() - |
| pRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() |
| )).Height(); |
| else |
| aLogicStart.Y() += nTopM + aCellSize.Height() - nEngineHeight; |
| } |
| else if (eVerJust==SVX_VER_JUSTIFY_CENTER) |
| { |
| if (bPixelToLogic) |
| aLogicStart.Y() += pRefDevice->PixelToLogic( Size(0, nTopM + ( |
| pRefDevice->LogicToPixel(aCellSize).Height() - |
| pRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() ) |
| / 2)).Height(); |
| else |
| aLogicStart.Y() += nTopM + (aCellSize.Height() - nEngineHeight) / 2; |
| } |
| else // top |
| { |
| if (bPixelToLogic) |
| aLogicStart.Y() += pRefDevice->PixelToLogic(Size(0,nTopM)).Height(); |
| else |
| aLogicStart.Y() += nTopM; |
| } |
| } |
| |
| Point aURLStart = aLogicStart; // copy before modifying for orientation |
| |
| short nOriVal = 0; |
| if (eOrient==SVX_ORIENTATION_TOPBOTTOM) |
| { |
| // nOriVal = -900; |
| nOriVal = 2700; |
| aLogicStart.X() += nEngineWidth; |
| } |
| else if (eOrient==SVX_ORIENTATION_BOTTOMTOP) |
| { |
| nOriVal = 900; |
| aLogicStart.Y() += bBreak ? pEngine->GetPaperSize().Width() : |
| nEngineHeight; |
| } |
| else if (eOrient==SVX_ORIENTATION_STACKED) |
| { |
| Size aPaperLogic = pEngine->GetPaperSize(); |
| aPaperLogic.Width() = nEngineWidth; |
| pEngine->SetPaperSize(aPaperLogic); |
| } |
| |
| if ( pEngine->IsRightToLeft( 0 ) ) |
| { |
| // For right-to-left, EditEngine always calculates its lines |
| // beginning from the right edge, but EditLine::nStartPosX is |
| // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX. |
| Size aLogicPaper = pEngine->GetPaperSize(); |
| if ( aLogicPaper.Width() > USHRT_MAX ) |
| { |
| aLogicPaper.Width() = USHRT_MAX; |
| pEngine->SetPaperSize(aLogicPaper); |
| } |
| } |
| |
| // bMoveClipped handling has been replaced by complete alignment |
| // handling (also extending to the left). |
| |
| if ( bSimClip && !nOriVal && !bAsianVertical ) |
| { |
| // kein hartes Clipping, aber nur die betroffenen |
| // Zeilen ausgeben |
| |
| Point aDocStart = aLogicClip.TopLeft(); |
| aDocStart -= aLogicStart; |
| pEngine->Draw( pDev, aLogicClip, aDocStart, sal_False ); |
| } |
| else |
| { |
| if (bAsianVertical) |
| { |
| // with SetVertical, the start position is top left of |
| // the whole output area, not the text itself |
| aLogicStart.X() -= pEngine->GetPaperSize().Width(); |
| } |
| pEngine->Draw( pDev, aLogicStart, nOriVal ); |
| } |
| |
| if (bClip) |
| { |
| if (bMetaFile) |
| pDev->Pop(); |
| else |
| pDev->SetClipRegion(); |
| } |
| |
| // PDF: whole-cell hyperlink from formula? |
| sal_Bool bHasURL = pPDFData && pCell && pCell->GetCellType() == CELLTYPE_FORMULA && |
| static_cast<ScFormulaCell*>(pCell)->IsHyperLinkCell(); |
| if ( bHasURL ) |
| { |
| long nURLWidth = (long) pEngine->CalcTextWidth(); |
| long nURLHeight = pEngine->GetTextHeight(); |
| if ( bBreak ) |
| { |
| Size aPaper = pEngine->GetPaperSize(); |
| if ( bAsianVertical ) |
| nURLHeight = aPaper.Height(); |
| else |
| nURLWidth = aPaper.Width(); |
| } |
| if ( eOrient == SVX_ORIENTATION_TOPBOTTOM || eOrient == SVX_ORIENTATION_BOTTOMTOP ) |
| std::swap( nURLWidth, nURLHeight ); |
| else if ( bAsianVertical ) |
| aURLStart.X() -= nURLWidth; |
| |
| Rectangle aURLRect( aURLStart, Size( nURLWidth, nURLHeight ) ); |
| lcl_DoHyperlinkResult( pDev, aURLRect, pCell ); |
| } |
| } |
| } |
| } |
| } |
| nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign; |
| } |
| } |
| nRowPosY += pRowInfo[nArrY].nHeight; |
| } |
| |
| delete pEngine; |
| |
| if (bAnyRotated) |
| DrawRotated(bPixelToLogic); //! von aussen rufen ? |
| } |
| |
| // ------------------------------------------------------------------------------- |
| |
| void ScOutputData::DrawRotated(sal_Bool bPixelToLogic) |
| { |
| //! nRotMax speichern |
| SCCOL nRotMax = nX2; |
| for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++) |
| if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax) |
| nRotMax = pRowInfo[nRotY].nRotMaxCol; |
| |
| |
| ScModule* pScMod = SC_MOD(); |
| sal_Int32 nConfBackColor = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; |
| // #105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True) |
| sal_Bool bCellContrast = bUseStyleColor && |
| Application::GetSettings().GetStyleSettings().GetHighContrastMode(); |
| |
| ScFieldEditEngine* pEngine = NULL; |
| sal_Bool bHyphenatorSet = sal_False; |
| const ScPatternAttr* pPattern; |
| const SfxItemSet* pCondSet; |
| const ScPatternAttr* pOldPattern = NULL; |
| const SfxItemSet* pOldCondSet = NULL; |
| ScBaseCell* pCell = NULL; |
| |
| long nInitPosX = nScrX; |
| if ( bLayoutRTL ) |
| { |
| #if 0 |
| Size aOnePixel = pDev->PixelToLogic(Size(1,1)); |
| long nOneX = aOnePixel.Width(); |
| nInitPosX += nMirrorW - nOneX; |
| #endif |
| nInitPosX += nMirrorW - 1; |
| } |
| long nLayoutSign = bLayoutRTL ? -1 : 1; |
| |
| long nRowPosY = nScrY; |
| for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 fuer Reste von zusammengefassten |
| { |
| RowInfo* pThisRowInfo = &pRowInfo[nArrY]; |
| long nCellHeight = (long) pThisRowInfo->nHeight; |
| if (nArrY==1) nRowPosY = nScrY; // vorher wird einzeln berechnet |
| |
| if ( ( pThisRowInfo->bChanged || nArrY==0 ) && pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE ) |
| { |
| long nPosX = 0; |
| for (SCCOL nX=0; nX<=nRotMax; nX++) |
| { |
| if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually |
| |
| CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1]; |
| if ( pInfo->nRotateDir != SC_ROTDIR_NONE ) |
| { |
| SCROW nY = pThisRowInfo->nRowNo; |
| |
| sal_Bool bHidden = sal_False; |
| if (bEditMode) |
| if ( nX == nEditCol && nY == nEditRow ) |
| bHidden = sal_True; |
| |
| if (!bHidden) |
| { |
| if (!pEngine) |
| pEngine = CreateOutputEditEngine(); |
| else |
| lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False) |
| |
| long nPosY = nRowPosY; |
| sal_Bool bVisChanged = sal_False; |
| |
| //! Rest von zusammengefasster Zelle weiter oben funktioniert nicht! |
| |
| sal_Bool bFromDoc = sal_False; |
| pPattern = pInfo->pPatternAttr; |
| pCondSet = pInfo->pConditionSet; |
| if (!pPattern) |
| { |
| pPattern = pDoc->GetPattern( nX, nY, nTab ); |
| bFromDoc = sal_True; |
| } |
| pCell = pInfo->pCell; |
| if (bFromDoc) |
| pCondSet = pDoc->GetCondResult( nX, nY, nTab ); |
| |
| if (!pCell && nX>nX2) |
| GetVisibleCell( nX, nY, nTab, pCell ); |
| |
| if ( !pCell || IsEmptyCellText( pThisRowInfo, nX, nY ) ) |
| bHidden = sal_True; // nRotateDir is also set without a cell |
| |
| long nCellWidth = (long) pRowInfo[0].pCellInfo[nX+1].nWidth; |
| |
| SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&) |
| pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet)).GetValue(); |
| sal_Bool bBreak = ( eHorJust == SVX_HOR_JUSTIFY_BLOCK ) || |
| ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue(); |
| sal_Bool bRepeat = ( eHorJust == SVX_HOR_JUSTIFY_REPEAT && !bBreak ); |
| sal_Bool bShrink = !bBreak && !bRepeat && static_cast<const SfxBoolItem&> |
| (pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue(); |
| SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet ); |
| |
| const ScMergeAttr* pMerge = |
| (ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE); |
| sal_Bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1; |
| |
| long nStartX = nPosX; |
| long nStartY = nPosY; |
| if (nX<nX1) |
| { |
| if ((bBreak || eOrient!=SVX_ORIENTATION_STANDARD) && !bMerged) |
| bHidden = sal_True; |
| else |
| { |
| nStartX = nInitPosX; |
| SCCOL nCol = nX1; |
| while (nCol > nX) |
| { |
| --nCol; |
| nStartX -= nLayoutSign * (long) pRowInfo[0].pCellInfo[nCol+1].nWidth; |
| } |
| } |
| } |
| long nCellStartX = nStartX; |
| |
| // Ersatzdarstellung fuer zu kleinen Text weggelassen |
| |
| if (!bHidden) |
| { |
| long nOutWidth = nCellWidth - 1; |
| long nOutHeight; |
| if (pInfo) |
| nOutHeight = nCellHeight; |
| else |
| nOutHeight = (long) ( pDoc->GetRowHeight(nY,nTab) * nPPTY ); |
| |
| if ( bMerged ) // Zusammengefasst |
| { |
| SCCOL nCountX = pMerge->GetColMerge(); |
| for (SCCOL i=1; i<nCountX; i++) |
| nOutWidth += (long) ( pDoc->GetColWidth(nX+i,nTab) * nPPTX ); |
| SCROW nCountY = pMerge->GetRowMerge(); |
| nOutHeight += (long) pDoc->GetScaledRowHeight( nY+1, nY+nCountY-1, nTab, nPPTY); |
| } |
| |
| SvxCellVerJustify eVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&) |
| pPattern->GetItem(ATTR_VER_JUSTIFY, pCondSet)).GetValue(); |
| |
| // Syntax-Modus wird hier ignoriert... |
| |
| // StringDiffer doesn't look at hyphenate, language items |
| if ( pPattern != pOldPattern || pCondSet != pOldCondSet ) |
| { |
| SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() ); |
| pPattern->FillEditItemSet( pSet, pCondSet ); |
| |
| // Ausrichtung fuer EditEngine |
| SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT; |
| if (eOrient==SVX_ORIENTATION_STACKED) |
| eSvxAdjust = SVX_ADJUST_CENTER; |
| // Adjustment fuer bBreak ist hier weggelassen |
| pSet->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) ); |
| |
| pEngine->SetDefaults( pSet ); |
| pOldPattern = pPattern; |
| pOldCondSet = pCondSet; |
| |
| sal_uLong nControl = pEngine->GetControlWord(); |
| if (eOrient==SVX_ORIENTATION_STACKED) |
| nControl |= EE_CNTRL_ONECHARPERLINE; |
| else |
| nControl &= ~EE_CNTRL_ONECHARPERLINE; |
| pEngine->SetControlWord( nControl ); |
| |
| if ( !bHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) |
| { |
| // set hyphenator the first time it is needed |
| com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() ); |
| pEngine->SetHyphenator( xXHyphenator ); |
| bHyphenatorSet = sal_True; |
| } |
| |
| Color aBackCol = ((const SvxBrushItem&) |
| pPattern->GetItem( ATTR_BACKGROUND, pCondSet )).GetColor(); |
| if ( bUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) ) |
| aBackCol.SetColor( nConfBackColor ); |
| pEngine->SetBackgroundColor( aBackCol ); |
| } |
| |
| // Raender |
| |
| //! Position und Papersize auf EditUtil umstellen !!! |
| |
| const SvxMarginItem* pMargin = (const SvxMarginItem*) |
| &pPattern->GetItem(ATTR_MARGIN, pCondSet); |
| sal_uInt16 nIndent = 0; |
| if ( eHorJust == SVX_HOR_JUSTIFY_LEFT ) |
| nIndent = ((const SfxUInt16Item&)pPattern-> |
| GetItem(ATTR_INDENT, pCondSet)).GetValue(); |
| |
| long nTotalHeight = nOutHeight; // ohne Rand abzuziehen |
| if ( bPixelToLogic ) |
| nTotalHeight = pRefDevice->PixelToLogic(Size(0,nTotalHeight)).Height(); |
| |
| long nLeftM = (long) ( (pMargin->GetLeftMargin() + nIndent) * nPPTX ); |
| long nTopM = (long) ( pMargin->GetTopMargin() * nPPTY ); |
| long nRightM = (long) ( pMargin->GetRightMargin() * nPPTX ); |
| long nBottomM = (long) ( pMargin->GetBottomMargin() * nPPTY ); |
| nStartX += nLeftM; |
| nStartY += nTopM; |
| nOutWidth -= nLeftM + nRightM; |
| nOutHeight -= nTopM + nBottomM; |
| |
| // Rotation schon hier, um bei Umbruch auch PaperSize anzupassen |
| long nAttrRotate = 0; |
| double nSin = 0.0; |
| double nCos = 1.0; |
| SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD; |
| if ( eOrient == SVX_ORIENTATION_STANDARD ) |
| { |
| nAttrRotate = ((const SfxInt32Item&)pPattern-> |
| GetItem(ATTR_ROTATE_VALUE, pCondSet)).GetValue(); |
| if ( nAttrRotate ) |
| { |
| eRotMode = (SvxRotateMode)((const SvxRotateModeItem&) |
| pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue(); |
| |
| if ( nAttrRotate == 18000 ) |
| eRotMode = SVX_ROTATE_MODE_STANDARD; // keinen Ueberlauf |
| |
| if ( bLayoutRTL ) |
| nAttrRotate = -nAttrRotate; |
| |
| double nRealOrient = nAttrRotate * F_PI18000; // 1/100 Grad |
| nCos = cos( nRealOrient ); |
| nSin = sin( nRealOrient ); |
| } |
| } |
| |
| Size aPaperSize = Size( 1000000, 1000000 ); |
| if (eOrient==SVX_ORIENTATION_STACKED) |
| aPaperSize.Width() = nOutWidth; // zum Zentrieren |
| else if (bBreak) |
| { |
| if (nAttrRotate) |
| { |
| //! richtige PaperSize fuer Umbruch haengt von der Zeilenzahl |
| //! ab, solange die Zeilen nicht einzeln versetzt ausgegeben |
| //! werden koennen -> darum unbegrenzt, also kein Umbruch. |
| //! Mit versetzten Zeilen waere das folgende richtig: |
| aPaperSize.Width() = (long)(nOutHeight / fabs(nSin)); |
| } |
| else if (eOrient == SVX_ORIENTATION_STANDARD) |
| aPaperSize.Width() = nOutWidth; |
| else |
| aPaperSize.Width() = nOutHeight - 1; |
| } |
| if (bPixelToLogic) |
| pEngine->SetPaperSize(pRefDevice->PixelToLogic(aPaperSize)); |
| else |
| pEngine->SetPaperSize(aPaperSize); // Scale ist immer 1 |
| |
| // Daten aus Zelle lesen |
| |
| if (pCell) |
| { |
| if (pCell->GetCellType() == CELLTYPE_EDIT) |
| { |
| const EditTextObject* pData; |
| ((ScEditCell*)pCell)->GetData(pData); |
| |
| if (pData) |
| pEngine->SetText(*pData); |
| else |
| { |
| DBG_ERROR("pData == 0"); |
| } |
| } |
| else |
| { |
| sal_uLong nFormat = pPattern->GetNumberFormat( |
| pDoc->GetFormatTable(), pCondSet ); |
| String aString; |
| Color* pColor; |
| ScCellFormat::GetString( pCell, |
| nFormat,aString, &pColor, |
| *pDoc->GetFormatTable(), |
| bShowNullValues, |
| bShowFormulas, |
| ftCheck ); |
| |
| pEngine->SetText(aString); |
| if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) ) |
| lcl_SetEditColor( *pEngine, *pColor ); |
| } |
| |
| if ( bSyntaxMode ) |
| SetEditSyntaxColor( *pEngine, pCell ); |
| else if ( bUseStyleColor && bForceAutoColor ) |
| lcl_SetEditColor( *pEngine, COL_AUTO ); //! or have a flag at EditEngine |
| } |
| else |
| { |
| DBG_ERROR("pCell == NULL"); |
| } |
| |
| pEngine->SetUpdateMode( sal_True ); // after SetText, before CalcTextWidth/GetTextHeight |
| |
| long nEngineWidth = (long) pEngine->CalcTextWidth(); |
| long nEngineHeight = pEngine->GetTextHeight(); |
| |
| if (nAttrRotate && bBreak) |
| { |
| double nAbsCos = fabs( nCos ); |
| double nAbsSin = fabs( nSin ); |
| |
| // #47740# adjust witdh of papersize for height of text |
| int nSteps = 5; |
| while (nSteps > 0) |
| { |
| // everything is in pixels |
| long nEnginePixel = pRefDevice->LogicToPixel( |
| Size(0,nEngineHeight)).Height(); |
| long nEffHeight = nOutHeight - (long)(nEnginePixel * nAbsCos) + 2; |
| long nNewWidth = (long)(nEffHeight / nAbsSin) + 2; |
| sal_Bool bFits = ( nNewWidth >= aPaperSize.Width() ); |
| if ( bFits ) |
| nSteps = 0; |
| else |
| { |
| if ( nNewWidth < 4 ) |
| { |
| // can't fit -> fall back to using half height |
| nEffHeight = nOutHeight / 2; |
| nNewWidth = (long)(nEffHeight / nAbsSin) + 2; |
| nSteps = 0; |
| } |
| else |
| --nSteps; |
| |
| // set paper width and get new text height |
| aPaperSize.Width() = nNewWidth; |
| if (bPixelToLogic) |
| pEngine->SetPaperSize(pRefDevice->PixelToLogic(aPaperSize)); |
| else |
| pEngine->SetPaperSize(aPaperSize); // Scale ist immer 1 |
| //pEngine->QuickFormatDoc( sal_True ); |
| nEngineWidth = (long) pEngine->CalcTextWidth(); |
| nEngineHeight = pEngine->GetTextHeight(); |
| } |
| } |
| } |
| |
| long nRealWidth = nEngineWidth; |
| long nRealHeight = nEngineHeight; |
| |
| // wenn gedreht, Groesse anpassen |
| if (nAttrRotate) |
| { |
| double nAbsCos = fabs( nCos ); |
| double nAbsSin = fabs( nSin ); |
| |
| if ( eRotMode == SVX_ROTATE_MODE_STANDARD ) |
| nEngineWidth = (long) ( nRealWidth * nAbsCos + |
| nRealHeight * nAbsSin ); |
| else |
| nEngineWidth = (long) ( nRealHeight / nAbsSin ); |
| //! begrenzen !!! |
| |
| nEngineHeight = (long) ( nRealHeight * nAbsCos + |
| nRealWidth * nAbsSin ); |
| } |
| |
| if (!nAttrRotate) // hier nur gedrehter Text |
| bHidden = sal_True; //! vorher abfragen !!! |
| |
| //! weglassen, was nicht hereinragt |
| |
| if (!bHidden) |
| { |
| sal_Bool bClip = sal_False; |
| Size aClipSize = Size( nScrX+nScrW-nStartX, nScrY+nScrH-nStartY ); |
| |
| // weiterschreiben |
| |
| Size aCellSize; |
| if (bPixelToLogic) |
| aCellSize = pRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) ); |
| else |
| aCellSize = Size( nOutWidth, nOutHeight ); // Scale ist 1 |
| |
| long nGridWidth = nEngineWidth; |
| sal_Bool bNegative = sal_False; |
| if ( eRotMode != SVX_ROTATE_MODE_STANDARD ) |
| { |
| nGridWidth = aCellSize.Width() + |
| Abs((long) ( aCellSize.Height() * nCos / nSin )); |
| bNegative = ( pInfo->nRotateDir == SC_ROTDIR_LEFT ); |
| if ( bLayoutRTL ) |
| bNegative = !bNegative; |
| } |
| |
| // use GetOutputArea to hide the grid |
| // (clip region is done manually below) |
| OutputAreaParam aAreaParam; |
| |
| SCCOL nCellX = nX; |
| SCROW nCellY = nY; |
| SvxCellHorJustify eOutHorJust = eHorJust; |
| if ( eRotMode != SVX_ROTATE_MODE_STANDARD ) |
| eOutHorJust = bNegative ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT; |
| long nNeededWidth = nGridWidth; // in pixel for GetOutputArea |
| if ( bPixelToLogic ) |
| nNeededWidth = pRefDevice->LogicToPixel(Size(nNeededWidth,0)).Width(); |
| |
| GetOutputArea( nX, nArrY, nCellStartX, nPosY, nCellX, nCellY, nNeededWidth, |
| *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust), |
| sal_False, sal_False, sal_True, aAreaParam ); |
| |
| if ( bShrink ) |
| { |
| long nPixelWidth = bPixelToLogic ? |
| pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width() : nEngineWidth; |
| long nNeededPixel = nPixelWidth + nLeftM + nRightM; |
| |
| aAreaParam.mbLeftClip = aAreaParam.mbRightClip = sal_True; |
| |
| // always do height |
| ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM, |
| sal_False, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic, |
| nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip ); |
| |
| if ( eRotMode == SVX_ROTATE_MODE_STANDARD ) |
| { |
| // do width only if rotating within the cell (standard mode) |
| ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM, |
| sal_True, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic, |
| nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip ); |
| } |
| |
| // nEngineWidth/nEngineHeight is updated in ShrinkEditEngine |
| // (but width is only valid for standard mode) |
| nRealWidth = (long) pEngine->CalcTextWidth(); |
| nRealHeight = pEngine->GetTextHeight(); |
| |
| if ( eRotMode != SVX_ROTATE_MODE_STANDARD ) |
| nEngineWidth = (long) ( nRealHeight / fabs( nSin ) ); |
| } |
| |
| // sal_Bool bVClip = ( nEngineHeight > aCellSize.Height() ); |
| |
| long nClipStartX = nStartX; |
| if (nX<nX1) |
| { |
| //! Clipping unnoetig, wenn links am Fenster |
| |
| bClip = sal_True; // nur Rest ausgeben! |
| if (nStartX<nScrX) |
| { |
| long nDif = nScrX - nStartX; |
| nClipStartX = nScrX; |
| aClipSize.Width() -= nDif; |
| } |
| } |
| |
| long nClipStartY = nStartY; |
| if (nArrY==0 || bVisChanged) |
| { |
| if ( nClipStartY < nRowPosY ) |
| { |
| long nDif = nRowPosY - nClipStartY; |
| bClip = sal_True; |
| nClipStartY = nRowPosY; |
| aClipSize.Height() -= nDif; |
| } |
| } |
| |
| bClip = sal_True; // always clip at the window/page border |
| |
| //Rectangle aClipRect; |
| if (bClip) |
| { |
| if ( nAttrRotate /* && eRotMode != SVX_ROTATE_MODE_STANDARD */ ) |
| { |
| // gedrehten, ausgerichteten Text nur an den |
| // Seitengrenzen clippen |
| nClipStartX = nScrX; |
| aClipSize.Width() = nScrW; |
| } |
| |
| if (bPixelToLogic) |
| aAreaParam.maClipRect = pRefDevice->PixelToLogic( Rectangle( |
| Point(nClipStartX,nClipStartY), aClipSize ) ); |
| else |
| aAreaParam.maClipRect = Rectangle(Point(nClipStartX, nClipStartY), |
| aClipSize ); // Scale = 1 |
| |
| if (bMetaFile) |
| { |
| pDev->Push(); |
| pDev->IntersectClipRegion( aAreaParam.maClipRect ); |
| } |
| else |
| pDev->SetClipRegion( Region( aAreaParam.maClipRect ) ); |
| } |
| |
| Point aLogicStart; |
| if (bPixelToLogic) |
| aLogicStart = pRefDevice->PixelToLogic( Point(nStartX,nStartY) ); |
| else |
| aLogicStart = Point(nStartX, nStartY); |
| if ( eOrient!=SVX_ORIENTATION_STANDARD || !bBreak ) |
| { |
| long nAvailWidth = aCellSize.Width(); |
| if (eType==OUTTYPE_WINDOW && |
| eOrient!=SVX_ORIENTATION_STACKED && |
| pInfo && pInfo->bAutoFilter) |
| { |
| // filter drop-down width is now independent from row height |
| if (bPixelToLogic) |
| nAvailWidth -= pRefDevice->PixelToLogic(Size(0,DROPDOWN_BITMAP_SIZE)).Height(); |
| else |
| nAvailWidth -= DROPDOWN_BITMAP_SIZE; |
| long nComp = nEngineWidth; |
| if (nAvailWidth<nComp) nAvailWidth=nComp; |
| } |
| |
| // horizontale Ausrichtung |
| |
| if (eOrient==SVX_ORIENTATION_STANDARD && !nAttrRotate) |
| { |
| if (eHorJust==SVX_HOR_JUSTIFY_RIGHT || |
| eHorJust==SVX_HOR_JUSTIFY_CENTER) |
| { |
| pEngine->SetUpdateMode( sal_False ); |
| |
| SvxAdjust eSvxAdjust = |
| (eHorJust==SVX_HOR_JUSTIFY_RIGHT) ? |
| SVX_ADJUST_RIGHT : SVX_ADJUST_CENTER; |
| pEngine->SetDefaultItem( |
| SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) ); |
| |
| aPaperSize.Width() = nOutWidth; |
| if (bPixelToLogic) |
| pEngine->SetPaperSize(pRefDevice->PixelToLogic(aPaperSize)); |
| else |
| pEngine->SetPaperSize(aPaperSize); |
| |
| pEngine->SetUpdateMode( sal_True ); |
| } |
| } |
| else |
| { |
| // bei gedrehtem Text ist Standard zentriert |
| if (eHorJust==SVX_HOR_JUSTIFY_RIGHT) |
| aLogicStart.X() += nAvailWidth - nEngineWidth; |
| else if (eHorJust==SVX_HOR_JUSTIFY_CENTER || |
| eHorJust==SVX_HOR_JUSTIFY_STANDARD) |
| aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2; |
| } |
| } |
| |
| if ( bLayoutRTL ) |
| { |
| if (bPixelToLogic) |
| aLogicStart.X() -= pRefDevice->PixelToLogic( |
| Size( nCellWidth, 0 ) ).Width(); |
| else |
| aLogicStart.X() -= nCellWidth; |
| } |
| |
| if ( eOrient==SVX_ORIENTATION_STANDARD || |
| eOrient==SVX_ORIENTATION_STACKED || !bBreak ) |
| { |
| if (eVerJust==SVX_VER_JUSTIFY_BOTTOM || |
| eVerJust==SVX_VER_JUSTIFY_STANDARD) |
| { |
| if (bPixelToLogic) |
| aLogicStart.Y() += pRefDevice->PixelToLogic( Size(0, |
| pRefDevice->LogicToPixel(aCellSize).Height() - |
| pRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() |
| )).Height(); |
| else |
| aLogicStart.Y() += aCellSize.Height() - nEngineHeight; |
| } |
| |
| else if (eVerJust==SVX_VER_JUSTIFY_CENTER) |
| { |
| if (bPixelToLogic) |
| aLogicStart.Y() += pRefDevice->PixelToLogic( Size(0,( |
| pRefDevice->LogicToPixel(aCellSize).Height() - |
| pRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()) |
| / 2)).Height(); |
| else |
| aLogicStart.Y() += (aCellSize.Height() - nEngineHeight) / 2; |
| } |
| } |
| |
| // TOPBOTTON and BOTTOMTOP are handled in DrawStrings/DrawEdit |
| DBG_ASSERT( eOrient == SVX_ORIENTATION_STANDARD && nAttrRotate, |
| "DrawRotated: no rotation" ); |
| |
| long nOriVal = 0; |
| if ( nAttrRotate ) |
| { |
| // Attribut ist 1/100, Font 1/10 Grad |
| nOriVal = nAttrRotate / 10; |
| |
| double nAddX = 0.0; |
| double nAddY = 0.0; |
| if ( nCos > 0.0 && eRotMode != SVX_ROTATE_MODE_STANDARD ) |
| { |
| //! begrenzen !!! |
| double nH = nRealHeight * nCos; |
| nAddX += nH * ( nCos / fabs(nSin) ); |
| } |
| if ( nCos < 0.0 && eRotMode == SVX_ROTATE_MODE_STANDARD ) |
| nAddX -= nRealWidth * nCos; |
| if ( nSin < 0.0 ) |
| nAddX -= nRealHeight * nSin; |
| if ( nSin > 0.0 ) |
| nAddY += nRealWidth * nSin; |
| if ( nCos < 0.0 ) |
| nAddY -= nRealHeight * nCos; |
| |
| if ( eRotMode != SVX_ROTATE_MODE_STANDARD ) |
| { |
| //! begrenzen !!! |
| double nSkew = nTotalHeight * nCos / fabs(nSin); |
| if ( eRotMode == SVX_ROTATE_MODE_CENTER ) |
| nAddX -= nSkew * 0.5; |
| if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nSin > 0.0 ) || |
| ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nSin < 0.0 ) ) |
| nAddX -= nSkew; |
| |
| long nUp = 0; |
| if ( eVerJust == SVX_VER_JUSTIFY_CENTER ) |
| nUp = ( aCellSize.Height() - nEngineHeight ) / 2; |
| else if ( eVerJust == SVX_VER_JUSTIFY_TOP ) |
| { |
| if ( nSin > 0.0 ) |
| nUp = aCellSize.Height() - nEngineHeight; |
| } |
| else // BOTTOM / STANDARD |
| { |
| if ( nSin < 0.0 ) |
| nUp = aCellSize.Height() - nEngineHeight; |
| } |
| if ( nUp ) |
| nAddX += ( nUp * nCos / fabs(nSin) ); |
| } |
| |
| aLogicStart.X() += (long) nAddX; |
| aLogicStart.Y() += (long) nAddY; |
| } |
| |
| // bSimClip is not used here (because nOriVal is set) |
| |
| if ( pEngine->IsRightToLeft( 0 ) ) |
| { |
| // For right-to-left, EditEngine always calculates its lines |
| // beginning from the right edge, but EditLine::nStartPosX is |
| // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX. |
| Size aLogicPaper = pEngine->GetPaperSize(); |
| if ( aLogicPaper.Width() > USHRT_MAX ) |
| { |
| aLogicPaper.Width() = USHRT_MAX; |
| pEngine->SetPaperSize(aLogicPaper); |
| } |
| } |
| |
| pEngine->Draw( pDev, aLogicStart, (short)nOriVal ); |
| |
| if (bClip) |
| { |
| if (bMetaFile) |
| pDev->Pop(); |
| else |
| pDev->SetClipRegion(); |
| } |
| } |
| } |
| } |
| } |
| nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign; |
| } |
| } |
| nRowPosY += pRowInfo[nArrY].nHeight; |
| } |
| |
| delete pEngine; |
| } |
| |
| |
| |