/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" // INCLUDE --------------------------------------------------------------- #include "scitems.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef _SVSTDARR_USHORTS #define _SVSTDARR_USHORTS #include #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 #include //! Autofilter-Breite mit column.cxx zusammenfassen #define DROPDOWN_BITMAP_SIZE 17 #define DRAWTEXT_MAX 32767 const USHORT 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; USHORT nIndent; BOOL bRotated; String aString; // Inhalte Size aTextSize; long nOriginalWidth; long nMaxDigitWidth; long nSignWidth; long nDotWidth; long nExpWidth; ScBaseCell* pLastCell; ULONG nValueFormat; BOOL bLineBreak; BOOL bRepeat; BOOL bShrink; BOOL bPixelToLogic; BOOL bCellContrast; Color aBackConfigColor; // used for ScPatternAttr::GetFont calls Color aTextConfigColor; public: ScDrawStringsVars(ScOutputData* pData, BOOL bPTL); ~ScDrawStringsVars(); // SetPattern = ex-SetVars // SetPatternSimple: ohne Font void SetPattern( const ScPatternAttr* pNew, const SfxItemSet* pSet, ScBaseCell* pCell, BYTE nScript ); void SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet ); BOOL SetText( ScBaseCell* pCell ); // 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; } USHORT GetLeftTotal() const { return pMargin->GetLeftMargin() + nIndent; } const String& GetString() const { return aString; } const Size& GetTextSize() const { return aTextSize; } long GetOriginalWidth() const { return nOriginalWidth; } ULONG GetValueFormat() const { return nValueFormat; } BOOL GetLineBreak() const { return bLineBreak; } BOOL IsRepeat() const { return bRepeat; } BOOL IsShrink() const { return bShrink; } long GetAscent() const { return nAscentPixel; } BOOL IsRotated() const { return bRotated; } void SetShrinkScale( long nScale, BYTE nScript ); BOOL HasCondHeight() const { return pCondSet && SFX_ITEM_SET == pCondSet->GetItemState( ATTR_FONT_HEIGHT, TRUE ); } BOOL HasEditCharacters() const; private: void SetHashText(); long GetMaxDigitWidth(); // in logic units long GetSignWidth(); long GetDotWidth(); long GetExpWidth(); void TextChanged(); }; //================================================================== ScDrawStringsVars::ScDrawStringsVars(ScOutputData* pData, 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 ( FALSE ), nOriginalWidth( 0 ), nMaxDigitWidth( 0 ), nSignWidth( 0 ), nDotWidth( 0 ), nExpWidth( 0 ), pLastCell ( NULL ), nValueFormat( 0 ), bLineBreak ( FALSE ), bRepeat ( FALSE ), bShrink ( FALSE ), bPixelToLogic( bPTL ) { ScModule* pScMod = SC_MOD(); // #105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed 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, BYTE 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, BYTE 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 = FALSE; break; case SVX_ORIENTATION_TOPBOTTOM: nRot = 2700; bRotated = FALSE; break; case SVX_ORIENTATION_BOTTOMTOP: nRot = 900; bRotated = FALSE; break; default: DBG_ERROR("Falscher SvxCellOrientation Wert"); nRot = 0; bRotated = 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 // 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(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 ULONG nOld = nValueFormat; // nValueFormat = pPattern->GetNumberFormat( pFormatter ); const SfxPoolItem* pFormItem; if ( !pCondSet || pCondSet->GetItemState(ATTR_VALUE_FORMAT,TRUE,&pFormItem) != SFX_ITEM_SET ) pFormItem = &pPattern->GetItem(ATTR_VALUE_FORMAT); const SfxPoolItem* pLangItem; if ( !pCondSet || pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT,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(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue(); } inline 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(); } BOOL ScDrawStringsVars::SetText( ScBaseCell* pCell ) { BOOL bChanged = FALSE; if (pCell) { if ( !SameValue( pCell, pLastCell ) ) { pLastCell = pCell; // Zelle merken Color* pColor; 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 = 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 && !static_cast(pCell)->IsValue()) // If it's formula, the result must be a value. return; ULONG nFormat = GetValueFormat(); 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(pCell)->GetValue() : static_cast(pCell)->GetValue(); const SvNumberformat* pNumFormat = pOutput->pDoc->GetFormatTable()->GetEntry(nFormat); if (!pNumFormat) return; long nMaxDigit = GetMaxDigitWidth(); sal_uInt16 nNumDigits = static_cast(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(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 ); } 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; } //================================================================== 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(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 ); } } BOOL ScOutputData::GetMergeOrigin( SCCOL nX, SCROW nY, SCSIZE nArrY, SCCOL& rOverX, SCROW& rOverY, BOOL bVisRowChanged ) { BOOL bDoMerge = FALSE; BOOL bIsLeft = ( nX == nVisX1 ); 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 FALSE; */ rOverX = nX; rOverY = nY; BOOL bHOver = pInfo->bHOverlapped; BOOL bVOver = pInfo->bVOverlapped; BOOL bHidden; while (bHOver) // nY konstant { --rOverX; bHidden = pDoc->ColHidden(rOverX, nTab); if ( !bDoMerge && !bHidden ) return 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); USHORT 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 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); USHORT nOverlap = ((ScMergeFlagAttr*)pDoc->GetAttr( rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue(); bHOver = ((nOverlap & SC_MF_HOR) != 0); bVOver = ((nOverlap & SC_MF_VER) != 0); } } return TRUE; } inline BOOL StringDiffer( const ScPatternAttr*& rpOldPattern, const ScPatternAttr*& rpNewPattern ) { DBG_ASSERT( rpNewPattern, "pNewPattern" ); if ( rpNewPattern == rpOldPattern ) return FALSE; else if ( !rpOldPattern ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT ) != &rpOldPattern->GetItem( ATTR_FONT ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_HEIGHT ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_WEIGHT ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_FONT_POSTURE ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_POSTURE ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_POSTURE ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT_UNDERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_UNDERLINE ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT_OVERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_OVERLINE ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT_WORDLINE ) != &rpOldPattern->GetItem( ATTR_FONT_WORDLINE ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT_CROSSEDOUT ) != &rpOldPattern->GetItem( ATTR_FONT_CROSSEDOUT ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT_CONTOUR ) != &rpOldPattern->GetItem( ATTR_FONT_CONTOUR ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT_SHADOWED ) != &rpOldPattern->GetItem( ATTR_FONT_SHADOWED ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT_COLOR ) != &rpOldPattern->GetItem( ATTR_FONT_COLOR ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_HOR_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_VER_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_STACKED ) != &rpOldPattern->GetItem( ATTR_STACKED ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_LINEBREAK ) != &rpOldPattern->GetItem( ATTR_LINEBREAK ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_MARGIN ) != &rpOldPattern->GetItem( ATTR_MARGIN ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_ROTATE_VALUE ) != &rpOldPattern->GetItem( ATTR_ROTATE_VALUE ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FORBIDDEN_RULES ) != &rpOldPattern->GetItem( ATTR_FORBIDDEN_RULES ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT_EMPHASISMARK ) != &rpOldPattern->GetItem( ATTR_FONT_EMPHASISMARK ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_FONT_RELIEF ) != &rpOldPattern->GetItem( ATTR_FONT_RELIEF ) ) return TRUE; else if ( &rpNewPattern->GetItem( ATTR_BACKGROUND ) != &rpOldPattern->GetItem( ATTR_BACKGROUND ) ) return TRUE; // needed with automatic text color else { rpOldPattern = rpNewPattern; return FALSE; } } inline void lcl_CreateInterpretProgress( BOOL& bProgress, ScDocument* pDoc, ScFormulaCell* pFCell ) { if ( !bProgress && pFCell->GetDirty() ) { ScProgress::CreateInterpretProgress( pDoc, TRUE ); bProgress = TRUE; } } inline BYTE GetScriptType( ScDocument* pDoc, ScBaseCell* pCell, const ScPatternAttr* pPattern, const SfxItemSet* pCondSet ) { return pDoc->GetCellScriptType( pCell, pPattern->GetNumberFormat( pDoc->GetFormatTable(), pCondSet ) ); } inline BOOL IsAmbiguousScript( BYTE nScript ) { return ( nScript != SCRIPTTYPE_LATIN && nScript != SCRIPTTYPE_ASIAN && nScript != SCRIPTTYPE_COMPLEX ); } BOOL ScOutputData::IsEmptyCellText( RowInfo* pThisRowInfo, SCCOL nX, SCROW nY ) { // pThisRowInfo may be NULL 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) 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 = TRUE; else if ( bTabProtected ) { if ( pAttr->GetHideCell() ) bEmpty = TRUE; else if ( bShowFormulas && pAttr->GetHideFormula() ) { ScBaseCell* pCell = pDoc->GetCell( ScAddress( nX, nY, nTab ) ); if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) bEmpty = 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; } 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 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 FALSE; } return 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, USHORT 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 { USHORT 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 ); 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; iGetColWidth( sal::static_int_cast(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 = TRUE; } while ( nLeftMissing > 0 && nLeftX > 0 && ( bOverwrite || IsAvailable( nLeftX-1, nCellY ) ) ) { if ( rThisRowInfo.nRowNo == nCellY && nLeftX >= nX1 && nLeftX <= nX2 ) rThisRowInfo.pCellInfo[nLeftX].bHideGrid = 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 = 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 = 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 = 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(rPattern.GetItem(ATTR_MERGE_FLAG)).GetValue() & SC_MF_AUTO ) && ( !bBreak || pRefDevice == pFmtDevice ) ) { long nFilter = Min( nMergeSizeY, (long) DROPDOWN_BITMAP_SIZE ); 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 = 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( BOOL bPixelToLogic ) { DBG_ASSERT( pDev == pRefDevice || pDev->GetMapMode().GetMapUnit() == pRefDevice->GetMapMode().GetMapUnit(), "DrawStrings: unterschiedliche MapUnits ?!?!" ); vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() ); BOOL bWasIdleDisabled = pDoc->IsIdleDisabled(); pDoc->DisableIdle( TRUE ); Size aMinSize = pRefDevice->PixelToLogic(Size(0,100)); // erst darueber wird ausgegeben // UINT32 nMinHeight = aMinSize.Height() / 200; // 1/2 Pixel ScDrawStringsVars aVars( this, bPixelToLogic ); BOOL bProgress = 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( 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; BOOL bCellIsValue = 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; BYTE nOldScript = 0; // alternative pattern instances in case we need to modify the pattern // before processing the cell value. ::boost::ptr_vector aAltPatterns; long nPosY = nScrY; for (SCSIZE nArrY=1; nArrY+1bChanged ) { 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++) { BOOL bMergeEmpty = FALSE; CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1]; BOOL bEmpty = nX < nX1 || pInfo->bEmptyCellText; SCCOL nCellX = nX; // position where the cell really starts SCROW nCellY = nY; BOOL bDoCell = FALSE; BOOL bNeedEdit = FALSE; // // Part of a merged cell? // BOOL bOverlapped = ( pInfo->bHOverlapped || pInfo->bVOverlapped ); if ( bOverlapped ) { bEmpty = TRUE; SCCOL nOverX; // start of the merged cells SCROW nOverY; BOOL bVisChanged = !pRowInfo[nArrY-1].bChanged; if (GetMergeOrigin( nX,nY, nArrY, nOverX,nOverY, bVisChanged )) { nCellX = nOverX; nCellY = nOverY; bDoCell = TRUE; } else bMergeEmpty = 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 = 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 = TRUE; } } // // normal visible cell // if (!bEmpty) bDoCell = TRUE; // // don't output the cell that's being edited // if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow ) bDoCell = 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 = FALSE; else if ( pCell->GetCellType() == CELLTYPE_EDIT ) bNeedEdit = 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 ); } if (pCell->HasValueData() && static_cast( pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue()) { // Disable line break when the cell content is numeric. aAltPatterns.push_back(new ScPatternAttr(*pPattern)); ScPatternAttr* pAltPattern = &aAltPatterns.back(); SfxBoolItem aLineBreak(ATTR_LINEBREAK, false); pAltPattern->GetItemSet().Put(aLineBreak); pPattern = pAltPattern; } BYTE 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 = TRUE; } if (bDoCell && !bNeedEdit) { 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 BOOL bBreak = ( aVars.GetLineBreak() || aVars.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK ); BOOL bRepeat = aVars.IsRepeat() && !bBreak; BOOL bShrink = aVars.IsShrink() && !bBreak && !bRepeat; nTotalMargin = static_cast(aVars.GetLeftTotal() * nPPTX) + static_cast(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(eOutHorJust), bCellIsValue || bRepeat || bShrink, bBreak, 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 = 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(); USHORT 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 = 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 = TRUE; bDoCell = 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 = 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(); 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; } BOOL bHClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip; BOOL bVClip = FALSE; if ( aAreaParam.maClipRect.Top() < nScrY ) { aAreaParam.maClipRect.Top() = nScrY; bVClip = TRUE; } if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH ) { aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one? bVClip = TRUE; } // // horizontalen Platz testen // BOOL bRightAdjusted = FALSE; // to correct text width calculation later BOOL bNeedEditEngine = 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 = 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 = 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; iDrawTextArray( 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? BOOL bHasURL = pPDFData && pCell && pCell->GetCellType() == CELLTYPE_FORMULA && static_cast(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 ); } // ------------------------------------------------------------------------------- void lcl_ClearEdit( EditEngine& rEngine ) // Text und Attribute { rEngine.SetUpdateMode( 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() ) ); } BOOL lcl_SafeIsValue( ScBaseCell* pCell ) { if (!pCell) return FALSE; BOOL bRet = FALSE; switch ( pCell->GetCellType() ) { case CELLTYPE_VALUE: bRet = TRUE; break; case CELLTYPE_FORMULA: { ScFormulaCell* pFCell = (ScFormulaCell*)pCell; if ( pFCell->IsRunning() || pFCell->IsValue() ) bRet = TRUE; } break; default: { // added to avoid warnings } } return bRet; } void lcl_ScaleFonts( EditEngine& rEngine, long nPercent ) { BOOL bUpdateMode = rEngine.GetUpdateMode(); if ( bUpdateMode ) rEngine.SetUpdateMode( FALSE ); USHORT nParCount = rEngine.GetParagraphCount(); for (USHORT nPar=0; nPar(aAttribs.Get(EE_CHAR_FONTHEIGHT)).GetHeight(); long nCJK = static_cast(aAttribs.Get(EE_CHAR_FONTHEIGHT_CJK)).GetHeight(); long nCTL = static_cast(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( TRUE ); } long lcl_GetEditSize( EditEngine& rEngine, BOOL bWidth, 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, BOOL bWidth, USHORT nOrient, long nAttrRotate, 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; 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, FALSE, bSwap, nAttrRotate ); long nNewSize = bPixelToLogic ? pRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight; USHORT 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, FALSE, bSwap, nAttrRotate ); nNewSize = bPixelToLogic ? pRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight; ++nShrinkAgain; } // sizes for further processing (alignment etc): rEngineWidth = lcl_GetEditSize( rEngine, 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, TRUE, FALSE, nAttrRotate ); long nNewSize = bPixelToLogic ? pRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth; USHORT 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, TRUE, FALSE, nAttrRotate ); nNewSize = bPixelToLogic ? pRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth; ++nShrinkAgain; } if ( nNewSize <= nAvailable ) rLeftClip = rRightClip = FALSE; // sizes for further processing (alignment etc): rNeededPixel = nNewSize + nLeftM + nRightM; rEngineHeight = lcl_GetEditSize( rEngine, FALSE, FALSE, nAttrRotate ); } } void ScOutputData::DrawEdit(BOOL bPixelToLogic) { vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() ); Size aMinSize = pRefDevice->PixelToLogic(Size(0,100)); // erst darueber wird ausgegeben // 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 TRUE) BOOL bCellContrast = bUseStyleColor && Application::GetSettings().GetStyleSettings().GetHighContrastMode(); ScFieldEditEngine* pEngine = NULL; BOOL bHyphenatorSet = 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( nLastContentCol - pDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) ); long nRowPosY = nScrY; for (SCSIZE nArrY=0; nArrY+1nHeight; 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; BOOL bDoCell = 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, TRUE )) { nCellX = nOverX; nCellY = nOverY; bDoCell = 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 = TRUE; } } else { bDoCell = TRUE; } if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow ) bDoCell = 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 = FALSE; } if (bDoCell) { BOOL bHidden = FALSE; // // Create EditEngine // if (!pEngine) { // Ein RefDevice muss auf jeden Fall gesetzt werden, // sonst legt sich die EditEngine ein VirtualDevice an! pEngine = new ScFieldEditEngine( pDoc->GetEnginePool() ); pEngine->SetUpdateMode( FALSE ); pEngine->SetRefDevice( pFmtDevice ); // always set ULONG nCtrl = pEngine->GetControlWord(); if ( bShowSpellErrors ) nCtrl |= EE_CNTRL_ONLINESPELLING; if ( eType == OUTTYPE_PRINTER ) nCtrl &= ~EE_CNTRL_MARKFIELDS; pEngine->SetControlWord( nCtrl ); pEngine->SetForbiddenCharsTable( pDoc->GetForbiddenCharacters() ); pEngine->SetAsianCompressionMode( pDoc->GetAsianCompression() ); pEngine->SetKernAsianPunctuation( pDoc->GetAsianKerning() ); pEngine->EnableAutoColor( bUseStyleColor ); pEngine->SetDefaultHorizontalTextDirection( (EEHorizontalTextDirection)pDoc->GetEditTextDirection( nTab ) ); } else lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(FALSE) BOOL bCellIsValue = lcl_SafeIsValue(pCell); SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&) pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet)).GetValue(); BOOL bBreak = ( eHorJust == SVX_HOR_JUSTIFY_BLOCK ) || ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue(); BOOL bRepeat = ( eHorJust == SVX_HOR_JUSTIFY_REPEAT && !bBreak ); BOOL bShrink = !bBreak && !bRepeat && static_cast (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 = TRUE; // gedreht wird getrennt ausgegeben } 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 = 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); USHORT 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(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, 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; 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 xXHyphenator( LinguMgr::GetHyphenator() ); pEngine->SetHyphenator( xXHyphenator ); bHyphenatorSet = 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 BOOL bWrapFields = 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 = TRUE; } } else { DBG_ERROR("pData == 0"); } } else { 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( 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(eOutHorJust), bCellIsValue || bRepeat || bShrink, false, false, aAreaParam ); if ( bShrink ) { BOOL bWidth = ( eOrient == SVX_ORIENTATION_STANDARD && !bAsianVertical ); ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM, bWidth, sal::static_int_cast(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; } 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; BOOL bSimClip = FALSE; if ( bWrapFields ) { // Fields in a cell with automatic breaks: clip to cell width bClip = TRUE; } if ( aAreaParam.maClipRect.Top() < nScrY ) { aAreaParam.maClipRect.Top() = nScrY; bClip = TRUE; } if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH ) { aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one? bClip = 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); 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, TRUE) ) ) bClip = TRUE; else bSimClip = 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 = 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 = 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( 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( 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 USHORT 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, 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? BOOL bHasURL = pPDFData && pCell && pCell->GetCellType() == CELLTYPE_FORMULA && static_cast(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(BOOL bPixelToLogic) { //! nRotMax speichern SCCOL nRotMax = nX2; for (SCSIZE nRotY=0; nRotY 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 TRUE) BOOL bCellContrast = bUseStyleColor && Application::GetSettings().GetStyleSettings().GetHighContrastMode(); ScFieldEditEngine* pEngine = NULL; BOOL bHyphenatorSet = 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+1nHeight; 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; BOOL bHidden = FALSE; if (bEditMode) if ( nX == nEditCol && nY == nEditRow ) bHidden = TRUE; if (!bHidden) { if (!pEngine) { // Ein RefDevice muss auf jeden Fall gesetzt werden, // sonst legt sich die EditEngine ein VirtualDevice an! pEngine = new ScFieldEditEngine( pDoc->GetEnginePool() ); pEngine->SetUpdateMode( FALSE ); pEngine->SetRefDevice( pFmtDevice ); // always set ULONG nCtrl = pEngine->GetControlWord(); if ( bShowSpellErrors ) nCtrl |= EE_CNTRL_ONLINESPELLING; if ( eType == OUTTYPE_PRINTER ) nCtrl &= ~EE_CNTRL_MARKFIELDS; pEngine->SetControlWord( nCtrl ); pEngine->SetForbiddenCharsTable( pDoc->GetForbiddenCharacters() ); pEngine->SetAsianCompressionMode( pDoc->GetAsianCompression() ); pEngine->SetKernAsianPunctuation( pDoc->GetAsianKerning() ); pEngine->EnableAutoColor( bUseStyleColor ); pEngine->SetDefaultHorizontalTextDirection( (EEHorizontalTextDirection)pDoc->GetEditTextDirection( nTab ) ); } else lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(FALSE) long nPosY = nRowPosY; BOOL bVisChanged = FALSE; //! Rest von zusammengefasster Zelle weiter oben funktioniert nicht! BOOL bFromDoc = FALSE; pPattern = pInfo->pPatternAttr; pCondSet = pInfo->pConditionSet; if (!pPattern) { pPattern = pDoc->GetPattern( nX, nY, nTab ); bFromDoc = 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 = 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(); BOOL bBreak = ( eHorJust == SVX_HOR_JUSTIFY_BLOCK ) || ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue(); BOOL bRepeat = ( eHorJust == SVX_HOR_JUSTIFY_REPEAT && !bBreak ); BOOL bShrink = !bBreak && !bRepeat && static_cast (pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue(); SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet ); const ScMergeAttr* pMerge = (ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE); BOOL bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1; long nStartX = nPosX; long nStartY = nPosY; if (nX 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; iGetColWidth(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; 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 xXHyphenator( LinguMgr::GetHyphenator() ); pEngine->SetHyphenator( xXHyphenator ); bHyphenatorSet = 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); USHORT 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 { 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( 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; 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( 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 = TRUE; //! vorher abfragen !!! //! weglassen, was nicht hereinragt if (!bHidden) { BOOL bClip = 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; BOOL bNegative = 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(eOutHorJust), FALSE, FALSE, TRUE, aAreaParam ); if ( bShrink ) { long nPixelWidth = bPixelToLogic ? pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width() : nEngineWidth; long nNeededPixel = nPixelWidth + nLeftM + nRightM; aAreaParam.mbLeftClip = aAreaParam.mbRightClip = TRUE; // always do height ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM, FALSE, sal::static_int_cast(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, TRUE, sal::static_int_cast(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 ) ); } // BOOL bVClip = ( nEngineHeight > aCellSize.Height() ); long nClipStartX = nStartX; if (nXPixelToLogic( 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) { if (pRowInfo[nArrY].nHeight < DROPDOWN_BITMAP_SIZE) { if (bPixelToLogic) nAvailWidth -= pRefDevice->PixelToLogic(Size(0,pRowInfo[nArrY].nHeight)).Height(); else nAvailWidth -= pRowInfo[nArrY].nHeight; } else { if (bPixelToLogic) nAvailWidth -= pRefDevice->PixelToLogic(Size(0,DROPDOWN_BITMAP_SIZE)).Height(); else nAvailWidth -= DROPDOWN_BITMAP_SIZE; } long nComp = nEngineWidth; if (nAvailWidthSetUpdateMode( 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( 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 USHORT 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; }