/************************************************************************* * * 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 "xistyle.hxx" #include #include #include #include #include "scitems.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "document.hxx" #include "docpool.hxx" #include "attrib.hxx" #include "stlpool.hxx" #include "stlsheet.hxx" #include "cell.hxx" #include "globstr.hrc" #include "xltracer.hxx" #include "xistream.hxx" #include "xicontent.hxx" #include "root.hxx" #include "colrowst.hxx" // PALETTE record - color information ========================================= XclImpPalette::XclImpPalette( const XclImpRoot& rRoot ) : XclDefaultPalette( rRoot ) { } void XclImpPalette::Initialize() { maColorTable.clear(); } ColorData XclImpPalette::GetColorData( sal_uInt16 nXclIndex ) const { if( nXclIndex >= EXC_COLOR_USEROFFSET ) { sal_uInt32 nIx = nXclIndex - EXC_COLOR_USEROFFSET; if( nIx < maColorTable.size() ) return maColorTable[ nIx ]; } return GetDefColorData( nXclIndex ); } void XclImpPalette::ReadPalette( XclImpStream& rStrm ) { sal_uInt16 nCount; rStrm >> nCount; DBG_ASSERT( rStrm.GetRecLeft() == static_cast< sal_Size >( 4 * nCount ), "XclImpPalette::ReadPalette - size mismatch" ); maColorTable.resize( nCount ); Color aColor; for( sal_uInt16 nIndex = 0; nIndex < nCount; ++nIndex ) { rStrm >> aColor; maColorTable[ nIndex ] = aColor.GetColor(); } } // FONT record - font information ============================================= XclImpFont::XclImpFont( const XclImpRoot& rRoot ) : XclImpRoot( rRoot ), mbHasCharSet( false ), mbHasWstrn( true ), mbHasAsian( false ), mbHasCmplx( false ) { SetAllUsedFlags( false ); } XclImpFont::XclImpFont( const XclImpRoot& rRoot, const XclFontData& rFontData ) : XclImpRoot( rRoot ) { SetFontData( rFontData, false ); } void XclImpFont::SetAllUsedFlags( bool bUsed ) { mbFontNameUsed = mbHeightUsed = mbColorUsed = mbWeightUsed = mbEscapemUsed = mbUnderlUsed = mbItalicUsed = mbStrikeUsed = mbOutlineUsed = mbShadowUsed = bUsed; } void XclImpFont::SetFontData( const XclFontData& rFontData, bool bHasCharSet ) { maData = rFontData; mbHasCharSet = bHasCharSet; if( maData.maStyle.Len() ) { if( SfxObjectShell* pDocShell = GetDocShell() ) { if( const SvxFontListItem* pInfoItem = static_cast< const SvxFontListItem* >( pDocShell->GetItem( SID_ATTR_CHAR_FONTLIST ) ) ) { if( const FontList* pFontList = pInfoItem->GetFontList() ) { FontInfo aFontInfo( pFontList->Get( maData.maName, maData.maStyle ) ); maData.SetScWeight( aFontInfo.GetWeight() ); maData.SetScPosture( aFontInfo.GetItalic() ); } } } maData.maStyle.Erase(); } GuessScriptType(); SetAllUsedFlags( true ); } rtl_TextEncoding XclImpFont::GetFontEncoding() const { // #i63105# use text encoding from FONT record // #i67768# BIFF2-BIFF4 FONT records do not contain character set rtl_TextEncoding eFontEnc = mbHasCharSet ? maData.GetFontEncoding() : GetTextEncoding(); return (eFontEnc == RTL_TEXTENCODING_DONTKNOW) ? GetTextEncoding() : eFontEnc; } void XclImpFont::ReadFont( XclImpStream& rStrm ) { switch( GetBiff() ) { case EXC_BIFF2: ReadFontData2( rStrm ); ReadFontName2( rStrm ); break; case EXC_BIFF3: case EXC_BIFF4: ReadFontData2( rStrm ); ReadFontColor( rStrm ); ReadFontName2( rStrm ); break; case EXC_BIFF5: ReadFontData5( rStrm ); ReadFontName2( rStrm ); break; case EXC_BIFF8: ReadFontData5( rStrm ); ReadFontName8( rStrm ); break; default: DBG_ERROR_BIFF(); return; } GuessScriptType(); SetAllUsedFlags( true ); } void XclImpFont::ReadEfont( XclImpStream& rStrm ) { ReadFontColor( rStrm ); } void XclImpFont::ReadCFFontBlock( XclImpStream& rStrm ) { DBG_ASSERT_BIFF( GetBiff() == EXC_BIFF8 ); if( GetBiff() != EXC_BIFF8 ) return; sal_uInt32 nHeight, nStyle, nColor, nFontFlags1, nFontFlags2, nFontFlags3; sal_uInt16 nWeight, nEscapem; sal_uInt8 nUnderl; rStrm.Ignore( 64 ); rStrm >> nHeight >> nStyle >> nWeight >> nEscapem >> nUnderl; rStrm.Ignore( 3 ); rStrm >> nColor; rStrm.Ignore( 4 ); rStrm >> nFontFlags1 >> nFontFlags2 >> nFontFlags3; rStrm.Ignore( 18 ); if( (mbHeightUsed = (nHeight <= 0x7FFF)) == true ) maData.mnHeight = static_cast< sal_uInt16 >( nHeight ); if( (mbWeightUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STYLE ) && (nWeight < 0x7FFF)) == true ) maData.mnWeight = static_cast< sal_uInt16 >( nWeight ); if( (mbItalicUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STYLE )) == true ) maData.mbItalic = ::get_flag( nStyle, EXC_CF_FONT_STYLE ); if( (mbUnderlUsed = !::get_flag( nFontFlags3, EXC_CF_FONT_UNDERL ) && (nUnderl <= 0x7F)) == true ) maData.mnUnderline = nUnderl; if( (mbColorUsed = (nColor <= 0x7FFF)) == true ) maData.maColor = GetPalette().GetColor( static_cast< sal_uInt16 >( nColor ) ); if( (mbStrikeUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STRIKEOUT )) == true ) maData.mbStrikeout = ::get_flag( nStyle, EXC_CF_FONT_STRIKEOUT ); } void XclImpFont::FillToItemSet( SfxItemSet& rItemSet, XclFontItemType eType, bool bSkipPoolDefs ) const { // true = edit engine Which-IDs (EE_CHAR_*); false = Calc Which-IDs (ATTR_*) bool bEE = eType != EXC_FONTITEM_CELL; // item = the item to put into the item set // sc_which = the Calc Which-ID of the item // ee_which = the edit engine Which-ID of the item #define PUTITEM( item, sc_which, ee_which ) \ ScfTools::PutItem( rItemSet, item, (bEE ? (ee_which) : (sc_which)), bSkipPoolDefs ) // Font item // #i36997# do not set default Tahoma font from notes bool bDefNoteFont = (eType == EXC_FONTITEM_NOTE) && (maData.maName.EqualsIgnoreCaseAscii( "Tahoma" )); if( mbFontNameUsed && !bDefNoteFont ) { rtl_TextEncoding eFontEnc = maData.GetFontEncoding(); rtl_TextEncoding eTempTextEnc = (bEE && (eFontEnc == GetTextEncoding())) ? ScfTools::GetSystemTextEncoding() : eFontEnc; SvxFontItem aFontItem( maData.GetScFamily( GetTextEncoding() ), maData.maName, EMPTY_STRING, PITCH_DONTKNOW, eTempTextEnc, ATTR_FONT ); // #91658# set only for valid script types if( mbHasWstrn ) PUTITEM( aFontItem, ATTR_FONT, EE_CHAR_FONTINFO ); if( mbHasAsian ) PUTITEM( aFontItem, ATTR_CJK_FONT, EE_CHAR_FONTINFO_CJK ); if( mbHasCmplx ) PUTITEM( aFontItem, ATTR_CTL_FONT, EE_CHAR_FONTINFO_CTL ); } // Font height (for all script types) if( mbHeightUsed ) { sal_Int32 nHeight = maData.mnHeight; if( bEE && (eType != EXC_FONTITEM_HF) ) // do not convert header/footer height nHeight = (nHeight * 127 + 36) / EXC_POINTS_PER_INCH; // #98527# 1 in == 72 pt SvxFontHeightItem aHeightItem( nHeight, 100, ATTR_FONT_HEIGHT ); PUTITEM( aHeightItem, ATTR_FONT_HEIGHT, EE_CHAR_FONTHEIGHT ); PUTITEM( aHeightItem, ATTR_CJK_FONT_HEIGHT, EE_CHAR_FONTHEIGHT_CJK ); PUTITEM( aHeightItem, ATTR_CTL_FONT_HEIGHT, EE_CHAR_FONTHEIGHT_CTL ); } // Font color - pass AUTO_COL to item if( mbColorUsed ) PUTITEM( SvxColorItem( maData.maColor, ATTR_FONT_COLOR ), ATTR_FONT_COLOR, EE_CHAR_COLOR ); // Font weight (for all script types) if( mbWeightUsed ) { SvxWeightItem aWeightItem( maData.GetScWeight(), ATTR_FONT_WEIGHT ); PUTITEM( aWeightItem, ATTR_FONT_WEIGHT, EE_CHAR_WEIGHT ); PUTITEM( aWeightItem, ATTR_CJK_FONT_WEIGHT, EE_CHAR_WEIGHT_CJK ); PUTITEM( aWeightItem, ATTR_CTL_FONT_WEIGHT, EE_CHAR_WEIGHT_CTL ); } // Font underline if( mbUnderlUsed ) { SvxUnderlineItem aUnderlItem( maData.GetScUnderline(), ATTR_FONT_UNDERLINE ); PUTITEM( aUnderlItem, ATTR_FONT_UNDERLINE, EE_CHAR_UNDERLINE ); } // Font posture (for all script types) if( mbItalicUsed ) { SvxPostureItem aPostItem( maData.GetScPosture(), ATTR_FONT_POSTURE ); PUTITEM( aPostItem, ATTR_FONT_POSTURE, EE_CHAR_ITALIC ); PUTITEM( aPostItem, ATTR_CJK_FONT_POSTURE, EE_CHAR_ITALIC_CJK ); PUTITEM( aPostItem, ATTR_CTL_FONT_POSTURE, EE_CHAR_ITALIC_CTL ); } // Boolean attributes crossed out, contoured, shadowed if( mbStrikeUsed ) PUTITEM( SvxCrossedOutItem( maData.GetScStrikeout(), ATTR_FONT_CROSSEDOUT ), ATTR_FONT_CROSSEDOUT, EE_CHAR_STRIKEOUT ); if( mbOutlineUsed ) PUTITEM( SvxContourItem( maData.mbOutline, ATTR_FONT_CONTOUR ), ATTR_FONT_CONTOUR, EE_CHAR_OUTLINE ); if( mbShadowUsed ) PUTITEM( SvxShadowedItem( maData.mbShadow, ATTR_FONT_SHADOWED ), ATTR_FONT_SHADOWED, EE_CHAR_SHADOW ); // Super-/subscript: only on edit engine objects if( mbEscapemUsed && bEE ) rItemSet.Put( SvxEscapementItem( maData.GetScEscapement(), EE_CHAR_ESCAPEMENT ) ); #undef PUTITEM } void XclImpFont::WriteFontProperties( ScfPropertySet& rPropSet, XclFontPropSetType eType, const Color* pFontColor ) const { GetFontPropSetHelper().WriteFontProperties( rPropSet, eType, maData, mbHasWstrn, mbHasAsian, mbHasCmplx, pFontColor ); } void XclImpFont::ReadFontData2( XclImpStream& rStrm ) { sal_uInt16 nFlags; rStrm >> maData.mnHeight >> nFlags; maData.mnWeight = ::get_flagvalue( nFlags, EXC_FONTATTR_BOLD, EXC_FONTWGHT_BOLD, EXC_FONTWGHT_NORMAL ); maData.mnUnderline = ::get_flagvalue( nFlags, EXC_FONTATTR_UNDERLINE, EXC_FONTUNDERL_SINGLE, EXC_FONTUNDERL_NONE ); maData.mbItalic = ::get_flag( nFlags, EXC_FONTATTR_ITALIC ); maData.mbStrikeout = ::get_flag( nFlags, EXC_FONTATTR_STRIKEOUT ); maData.mbOutline = ::get_flag( nFlags, EXC_FONTATTR_OUTLINE ); maData.mbShadow = ::get_flag( nFlags, EXC_FONTATTR_SHADOW ); mbHasCharSet = false; } void XclImpFont::ReadFontData5( XclImpStream& rStrm ) { sal_uInt16 nFlags; rStrm >> maData.mnHeight >> nFlags; ReadFontColor( rStrm ); rStrm >> maData.mnWeight >> maData.mnEscapem >> maData.mnUnderline >> maData.mnFamily >> maData.mnCharSet; rStrm.Ignore( 1 ); maData.mbItalic = ::get_flag( nFlags, EXC_FONTATTR_ITALIC ); maData.mbStrikeout = ::get_flag( nFlags, EXC_FONTATTR_STRIKEOUT ); maData.mbOutline = ::get_flag( nFlags, EXC_FONTATTR_OUTLINE ); maData.mbShadow = ::get_flag( nFlags, EXC_FONTATTR_SHADOW ); mbHasCharSet = true; } void XclImpFont::ReadFontColor( XclImpStream& rStrm ) { maData.maColor = GetPalette().GetColor( rStrm.ReaduInt16() ); } void XclImpFont::ReadFontName2( XclImpStream& rStrm ) { maData.maName = rStrm.ReadByteString( false ); } void XclImpFont::ReadFontName8( XclImpStream& rStrm ) { maData.maName = rStrm.ReadUniString( rStrm.ReaduInt8() ); } void XclImpFont::GuessScriptType() { mbHasWstrn = true; mbHasAsian = mbHasCmplx = false; // #91658# #113783# find the script types for which the font contains characters if( OutputDevice* pPrinter = GetPrinter() ) { Font aFont( maData.maName, Size( 0, 10 ) ); FontCharMap aCharMap; pPrinter->SetFont( aFont ); if( pPrinter->GetFontCharMap( aCharMap ) ) { // #91658# CJK fonts mbHasAsian = aCharMap.HasChar( 0x3041 ) || // 3040-309F: Hiragana aCharMap.HasChar( 0x30A1 ) || // 30A0-30FF: Katakana aCharMap.HasChar( 0x3111 ) || // 3100-312F: Bopomofo aCharMap.HasChar( 0x3131 ) || // 3130-318F: Hangul Compatibility Jamo aCharMap.HasChar( 0x3301 ) || // 3300-33FF: CJK Compatibility aCharMap.HasChar( 0x3401 ) || // 3400-4DBF: CJK Unified Ideographs Extension A aCharMap.HasChar( 0x4E01 ) || // 4E00-9FAF: CJK Unified Ideographs aCharMap.HasChar( 0x7E01 ) || // 4E00-9FAF: CJK unified ideographs aCharMap.HasChar( 0xA001 ) || // A001-A48F: Yi Syllables aCharMap.HasChar( 0xAC01 ) || // AC00-D7AF: Hangul Syllables aCharMap.HasChar( 0xCC01 ) || // AC00-D7AF: Hangul Syllables aCharMap.HasChar( 0xF901 ) || // F900-FAFF: CJK Compatibility Ideographs aCharMap.HasChar( 0xFF71 ); // FF00-FFEF: Halfwidth/Fullwidth Forms // #113783# CTL fonts mbHasCmplx = aCharMap.HasChar( 0x05D1 ) || // 0590-05FF: Hebrew aCharMap.HasChar( 0x0631 ) || // 0600-06FF: Arabic aCharMap.HasChar( 0x0721 ) || // 0700-074F: Syriac aCharMap.HasChar( 0x0911 ) || // 0900-0DFF: Indic scripts aCharMap.HasChar( 0x0E01 ) || // 0E00-0E7F: Thai aCharMap.HasChar( 0xFB21 ) || // FB1D-FB4F: Hebrew Presentation Forms aCharMap.HasChar( 0xFB51 ) || // FB50-FDFF: Arabic Presentation Forms-A aCharMap.HasChar( 0xFE71 ); // FE70-FEFF: Arabic Presentation Forms-B // Western fonts mbHasWstrn = (!mbHasAsian && !mbHasCmplx) || aCharMap.HasChar( 'A' ); } } } // ---------------------------------------------------------------------------- XclImpFontBuffer::XclImpFontBuffer( const XclImpRoot& rRoot ) : XclImpRoot( rRoot ), maFont4( rRoot ), maCtrlFont( rRoot ) { Initialize(); // default font for form controls without own font information XclFontData aCtrlFontData; switch( GetBiff() ) { case EXC_BIFF2: case EXC_BIFF3: case EXC_BIFF4: case EXC_BIFF5: aCtrlFontData.maName.AssignAscii( "Helv" ); aCtrlFontData.mnHeight = 160; aCtrlFontData.mnWeight = EXC_FONTWGHT_BOLD; break; case EXC_BIFF8: aCtrlFontData.maName.AssignAscii( "Tahoma" ); aCtrlFontData.mnHeight = 160; aCtrlFontData.mnWeight = EXC_FONTWGHT_NORMAL; break; default: DBG_ERROR_BIFF(); } maCtrlFont.SetFontData( aCtrlFontData, false ); } void XclImpFontBuffer::Initialize() { maFontList.Clear(); // application font for column width calculation, later filled with first font from font list XclFontData aAppFontData; aAppFontData.maName.AssignAscii( "Arial" ); aAppFontData.mnHeight = 200; aAppFontData.mnWeight = EXC_FONTWGHT_NORMAL; UpdateAppFont( aAppFontData, false ); } const XclImpFont* XclImpFontBuffer::GetFont( sal_uInt16 nFontIndex ) const { /* Font with index 4 is not stored in an Excel file, but used e.g. by BIFF5 form pushbutton objects. It is the bold default font. */ return (nFontIndex == 4) ? &maFont4 : maFontList.GetObject( (nFontIndex < 4) ? nFontIndex : (nFontIndex - 1) ); } void XclImpFontBuffer::ReadFont( XclImpStream& rStrm ) { XclImpFont* pFont = new XclImpFont( GetRoot() ); pFont->ReadFont( rStrm ); maFontList.Append( pFont ); if( maFontList.Count() == 1 ) { UpdateAppFont( pFont->GetFontData(), pFont->HasCharSet() ); // #i71033# set text encoding from application font, if CODEPAGE is missing SetAppFontEncoding( pFont->GetFontEncoding() ); } } void XclImpFontBuffer::ReadEfont( XclImpStream& rStrm ) { if( XclImpFont* pFont = maFontList.Last() ) pFont->ReadEfont( rStrm ); } void XclImpFontBuffer::FillToItemSet( SfxItemSet& rItemSet, XclFontItemType eType, sal_uInt16 nFontIdx, bool bSkipPoolDefs ) const { if( const XclImpFont* pFont = GetFont( nFontIdx ) ) pFont->FillToItemSet( rItemSet, eType, bSkipPoolDefs ); } void XclImpFontBuffer::WriteFontProperties( ScfPropertySet& rPropSet, XclFontPropSetType eType, sal_uInt16 nFontIdx, const Color* pFontColor ) const { if( const XclImpFont* pFont = GetFont( nFontIdx ) ) pFont->WriteFontProperties( rPropSet, eType, pFontColor ); } void XclImpFontBuffer::WriteDefaultCtrlFontProperties( ScfPropertySet& rPropSet ) const { maCtrlFont.WriteFontProperties( rPropSet, EXC_FONTPROPSET_CONTROL ); } void XclImpFontBuffer::UpdateAppFont( const XclFontData& rFontData, bool bHasCharSet ) { maAppFont = rFontData; // #i3006# Calculate the width of '0' from first font and current printer. SetCharWidth( maAppFont ); // font 4 is bold font 0 XclFontData aFont4Data( maAppFont ); aFont4Data.mnWeight = EXC_FONTWGHT_BOLD; maFont4.SetFontData( aFont4Data, bHasCharSet ); } // FORMAT record - number formats ============================================= XclImpNumFmtBuffer::XclImpNumFmtBuffer( const XclImpRoot& rRoot ) : XclNumFmtBuffer( rRoot ), XclImpRoot( rRoot ), mnNextXclIdx( 0 ) { } void XclImpNumFmtBuffer::Initialize() { maIndexMap.clear(); mnNextXclIdx = 0; InitializeImport(); // base class } void XclImpNumFmtBuffer::ReadFormat( XclImpStream& rStrm ) { String aFormat; switch( GetBiff() ) { case EXC_BIFF2: case EXC_BIFF3: aFormat = rStrm.ReadByteString( false ); break; case EXC_BIFF4: rStrm.Ignore( 2 ); // in BIFF4 the index field exists, but is undefined aFormat = rStrm.ReadByteString( false ); break; case EXC_BIFF5: rStrm >> mnNextXclIdx; aFormat = rStrm.ReadByteString( false ); break; case EXC_BIFF8: rStrm >> mnNextXclIdx; aFormat = rStrm.ReadUniString(); break; default: DBG_ERROR_BIFF(); return; } if( mnNextXclIdx < 0xFFFF ) { InsertFormat( mnNextXclIdx, aFormat ); ++mnNextXclIdx; } } void XclImpNumFmtBuffer::CreateScFormats() { DBG_ASSERT( maIndexMap.empty(), "XclImpNumFmtBuffer::CreateScFormats - already created" ); SvNumberFormatter& rFormatter = GetFormatter(); for( XclNumFmtMap::const_iterator aIt = GetFormatMap().begin(), aEnd = GetFormatMap().end(); aIt != aEnd; ++aIt ) { const XclNumFmt& rNumFmt = aIt->second; // insert/convert the Excel number format xub_StrLen nCheckPos; short nType = NUMBERFORMAT_DEFINED; sal_uInt32 nKey; if( rNumFmt.maFormat.Len() ) { String aFormat( rNumFmt.maFormat ); rFormatter.PutandConvertEntry( aFormat, nCheckPos, nType, nKey, LANGUAGE_ENGLISH_US, rNumFmt.meLanguage ); } else nKey = rFormatter.GetFormatIndex( rNumFmt.meOffset, rNumFmt.meLanguage ); // insert the resulting format key into the Excel->Calc index map maIndexMap[ aIt->first ] = nKey; } } ULONG XclImpNumFmtBuffer::GetScFormat( sal_uInt16 nXclNumFmt ) const { XclImpIndexMap::const_iterator aIt = maIndexMap.find( nXclNumFmt ); return (aIt != maIndexMap.end()) ? aIt->second : NUMBERFORMAT_ENTRY_NOT_FOUND; } void XclImpNumFmtBuffer::FillToItemSet( SfxItemSet& rItemSet, sal_uInt16 nXclNumFmt, bool bSkipPoolDefs ) const { ULONG nScNumFmt = GetScFormat( nXclNumFmt ); if( nScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND ) nScNumFmt = GetStdScNumFmt(); FillScFmtToItemSet( rItemSet, nScNumFmt, bSkipPoolDefs ); } void XclImpNumFmtBuffer::FillScFmtToItemSet( SfxItemSet& rItemSet, ULONG nScNumFmt, bool bSkipPoolDefs ) const { DBG_ASSERT( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND, "XclImpNumFmtBuffer::FillScFmtToItemSet - invalid number format" ); ScfTools::PutItem( rItemSet, SfxUInt32Item( ATTR_VALUE_FORMAT, nScNumFmt ), bSkipPoolDefs ); if( rItemSet.GetItemState( ATTR_VALUE_FORMAT, FALSE ) == SFX_ITEM_SET ) ScGlobal::AddLanguage( rItemSet, GetFormatter() ); } // XF, STYLE record - Cell formatting ========================================= void XclImpCellProt::FillFromXF2( sal_uInt8 nNumFmt ) { mbLocked = ::get_flag( nNumFmt, EXC_XF2_LOCKED ); mbHidden = ::get_flag( nNumFmt, EXC_XF2_HIDDEN ); } void XclImpCellProt::FillFromXF3( sal_uInt16 nProt ) { mbLocked = ::get_flag( nProt, EXC_XF_LOCKED ); mbHidden = ::get_flag( nProt, EXC_XF_HIDDEN ); } void XclImpCellProt::FillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const { ScfTools::PutItem( rItemSet, ScProtectionAttr( mbLocked, mbHidden ), bSkipPoolDefs ); } // ---------------------------------------------------------------------------- void XclImpCellAlign::FillFromXF2( sal_uInt8 nFlags ) { mnHorAlign = ::extract_value< sal_uInt8 >( nFlags, 0, 3 ); } void XclImpCellAlign::FillFromXF3( sal_uInt16 nAlign ) { mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 ); mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK ); // new in BIFF3 } void XclImpCellAlign::FillFromXF4( sal_uInt16 nAlign ) { FillFromXF3( nAlign ); mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 2 ); // new in BIFF4 mnOrient = ::extract_value< sal_uInt8 >( nAlign, 6, 2 ); // new in BIFF4 } void XclImpCellAlign::FillFromXF5( sal_uInt16 nAlign ) { mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 ); mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 ); mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK ); mnOrient = ::extract_value< sal_uInt8 >( nAlign, 8, 2 ); } void XclImpCellAlign::FillFromXF8( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib ) { mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 ); mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 ); mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK ); mnRotation = ::extract_value< sal_uInt8 >( nAlign, 8, 8 ); // new in BIFF8 mnIndent = ::extract_value< sal_uInt8 >( nMiscAttrib, 0, 4 ); // new in BIFF8 mbShrink = ::get_flag( nMiscAttrib, EXC_XF8_SHRINK ); // new in BIFF8 mnTextDir = ::extract_value< sal_uInt8 >( nMiscAttrib, 6, 2 ); // new in BIFF8 } void XclImpCellAlign::FillToItemSet( SfxItemSet& rItemSet, const XclImpFont* pFont, bool bSkipPoolDefs ) const { // horizontal alignment ScfTools::PutItem( rItemSet, SvxHorJustifyItem( GetScHorAlign(), ATTR_HOR_JUSTIFY ), bSkipPoolDefs ); // text wrap (#i74508# always if vertical alignment is justified or distributed) bool bLineBreak = mbLineBreak || (mnVerAlign == EXC_XF_VER_JUSTIFY) || (mnVerAlign == EXC_XF_VER_DISTRIB); ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_LINEBREAK, bLineBreak ), bSkipPoolDefs ); // vertical alignment ScfTools::PutItem( rItemSet, SvxVerJustifyItem( GetScVerAlign(), ATTR_VER_JUSTIFY ), bSkipPoolDefs ); // indent sal_uInt16 nScIndent = mnIndent * 200; // 1 Excel unit == 10 pt == 200 twips ScfTools::PutItem( rItemSet, SfxUInt16Item( ATTR_INDENT, nScIndent ), bSkipPoolDefs ); // shrink to fit ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_SHRINKTOFIT, mbShrink ), bSkipPoolDefs ); // text orientation/rotation (BIFF2-BIFF7 sets mnOrient) sal_uInt8 nXclRot = (mnOrient == EXC_ORIENT_NONE) ? mnRotation : XclTools::GetXclRotFromOrient( mnOrient ); bool bStacked = (nXclRot == EXC_ROT_STACKED); ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_STACKED, bStacked ), bSkipPoolDefs ); ScfTools::PutItem( rItemSet, SvxRotateModeItem( SVX_ROTATE_MODE_STANDARD, ATTR_ROTATE_MODE ), bSkipPoolDefs ); // set an angle in the range from -90 to 90 degrees sal_Int32 nAngle = XclTools::GetScRotation( nXclRot, 0 ); ScfTools::PutItem( rItemSet, SfxInt32Item( ATTR_ROTATE_VALUE, nAngle ), bSkipPoolDefs ); // #105933# set "Use asian vertical layout", if cell is stacked and font contains CKJ characters bool bAsianVert = bStacked && pFont && pFont->HasAsianChars(); ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_VERTICAL_ASIAN, bAsianVert ), bSkipPoolDefs ); // CTL text direction ScfTools::PutItem( rItemSet, SvxFrameDirectionItem( GetScFrameDir(), ATTR_WRITINGDIR ), bSkipPoolDefs ); } // ---------------------------------------------------------------------------- XclImpCellBorder::XclImpCellBorder() { SetUsedFlags( false, false ); } void XclImpCellBorder::SetUsedFlags( bool bOuterUsed, bool bDiagUsed ) { mbLeftUsed = mbRightUsed = mbTopUsed = mbBottomUsed = bOuterUsed; mbDiagUsed = bDiagUsed; } void XclImpCellBorder::FillFromXF2( sal_uInt8 nFlags ) { mnLeftLine = ::get_flagvalue( nFlags, EXC_XF2_LEFTLINE, EXC_LINE_THIN, EXC_LINE_NONE ); mnRightLine = ::get_flagvalue( nFlags, EXC_XF2_RIGHTLINE, EXC_LINE_THIN, EXC_LINE_NONE ); mnTopLine = ::get_flagvalue( nFlags, EXC_XF2_TOPLINE, EXC_LINE_THIN, EXC_LINE_NONE ); mnBottomLine = ::get_flagvalue( nFlags, EXC_XF2_BOTTOMLINE, EXC_LINE_THIN, EXC_LINE_NONE ); mnLeftColor = mnRightColor = mnTopColor = mnBottomColor = EXC_COLOR_BIFF2_BLACK; SetUsedFlags( true, false ); } void XclImpCellBorder::FillFromXF3( sal_uInt32 nBorder ) { mnTopLine = ::extract_value< sal_uInt8 >( nBorder, 0, 3 ); mnLeftLine = ::extract_value< sal_uInt8 >( nBorder, 8, 3 ); mnBottomLine = ::extract_value< sal_uInt8 >( nBorder, 16, 3 ); mnRightLine = ::extract_value< sal_uInt8 >( nBorder, 24, 3 ); mnTopColor = ::extract_value< sal_uInt16 >( nBorder, 3, 5 ); mnLeftColor = ::extract_value< sal_uInt16 >( nBorder, 11, 5 ); mnBottomColor = ::extract_value< sal_uInt16 >( nBorder, 19, 5 ); mnRightColor = ::extract_value< sal_uInt16 >( nBorder, 27, 5 ); SetUsedFlags( true, false ); } void XclImpCellBorder::FillFromXF5( sal_uInt32 nBorder, sal_uInt32 nArea ) { mnTopLine = ::extract_value< sal_uInt8 >( nBorder, 0, 3 ); mnLeftLine = ::extract_value< sal_uInt8 >( nBorder, 3, 3 ); mnBottomLine = ::extract_value< sal_uInt8 >( nArea, 22, 3 ); mnRightLine = ::extract_value< sal_uInt8 >( nBorder, 6, 3 ); mnTopColor = ::extract_value< sal_uInt16 >( nBorder, 9, 7 ); mnLeftColor = ::extract_value< sal_uInt16 >( nBorder, 16, 7 ); mnBottomColor = ::extract_value< sal_uInt16 >( nArea, 25, 7 ); mnRightColor = ::extract_value< sal_uInt16 >( nBorder, 23, 7 ); SetUsedFlags( true, false ); } void XclImpCellBorder::FillFromXF8( sal_uInt32 nBorder1, sal_uInt32 nBorder2 ) { mnLeftLine = ::extract_value< sal_uInt8 >( nBorder1, 0, 4 ); mnRightLine = ::extract_value< sal_uInt8 >( nBorder1, 4, 4 ); mnTopLine = ::extract_value< sal_uInt8 >( nBorder1, 8, 4 ); mnBottomLine = ::extract_value< sal_uInt8 >( nBorder1, 12, 4 ); mnLeftColor = ::extract_value< sal_uInt16 >( nBorder1, 16, 7 ); mnRightColor = ::extract_value< sal_uInt16 >( nBorder1, 23, 7 ); mnTopColor = ::extract_value< sal_uInt16 >( nBorder2, 0, 7 ); mnBottomColor = ::extract_value< sal_uInt16 >( nBorder2, 7, 7 ); mbDiagTLtoBR = ::get_flag( nBorder1, EXC_XF_DIAGONAL_TL_TO_BR ); mbDiagBLtoTR = ::get_flag( nBorder1, EXC_XF_DIAGONAL_BL_TO_TR ); if( mbDiagTLtoBR || mbDiagBLtoTR ) { mnDiagLine = ::extract_value< sal_uInt8 >( nBorder2, 21, 4 ); mnDiagColor = ::extract_value< sal_uInt16 >( nBorder2, 14, 7 ); } SetUsedFlags( true, true ); } void XclImpCellBorder::FillFromCF8( sal_uInt16 nLineStyle, sal_uInt32 nLineColor, sal_uInt32 nFlags ) { mnLeftLine = ::extract_value< sal_uInt8 >( nLineStyle, 0, 4 ); mnRightLine = ::extract_value< sal_uInt8 >( nLineStyle, 4, 4 ); mnTopLine = ::extract_value< sal_uInt8 >( nLineStyle, 8, 4 ); mnBottomLine = ::extract_value< sal_uInt8 >( nLineStyle, 12, 4 ); mnLeftColor = ::extract_value< sal_uInt16 >( nLineColor, 0, 7 ); mnRightColor = ::extract_value< sal_uInt16 >( nLineColor, 7, 7 ); mnTopColor = ::extract_value< sal_uInt16 >( nLineColor, 16, 7 ); mnBottomColor = ::extract_value< sal_uInt16 >( nLineColor, 23, 7 ); mbLeftUsed = !::get_flag( nFlags, EXC_CF_BORDER_LEFT ); mbRightUsed = !::get_flag( nFlags, EXC_CF_BORDER_RIGHT ); mbTopUsed = !::get_flag( nFlags, EXC_CF_BORDER_TOP ); mbBottomUsed = !::get_flag( nFlags, EXC_CF_BORDER_BOTTOM ); mbDiagUsed = false; } namespace { /** Converts the passed line style to a SvxBorderLine, or returns false, if style is "no line". */ bool lclConvertBorderLine( SvxBorderLine& rLine, const XclImpPalette& rPalette, sal_uInt8 nXclLine, sal_uInt16 nXclColor ) { static const sal_uInt16 ppnLineParam[][ 3 ] = { // outer width, inner width, distance { 0, 0, 0 }, // 0 = none { DEF_LINE_WIDTH_1, 0, 0 }, // 1 = thin { DEF_LINE_WIDTH_2, 0, 0 }, // 2 = medium { DEF_LINE_WIDTH_1, 0, 0 }, // 3 = dashed { DEF_LINE_WIDTH_0, 0, 0 }, // 4 = dotted { DEF_LINE_WIDTH_3, 0, 0 }, // 5 = thick { DEF_LINE_WIDTH_1, DEF_LINE_WIDTH_1, DEF_LINE_WIDTH_1 }, // 6 = double { DEF_LINE_WIDTH_0, 0, 0 }, // 7 = hair { DEF_LINE_WIDTH_2, 0, 0 }, // 8 = med dash { DEF_LINE_WIDTH_1, 0, 0 }, // 9 = thin dashdot { DEF_LINE_WIDTH_2, 0, 0 }, // A = med dashdot { DEF_LINE_WIDTH_1, 0, 0 }, // B = thin dashdotdot { DEF_LINE_WIDTH_2, 0, 0 }, // C = med dashdotdot { DEF_LINE_WIDTH_2, 0, 0 } // D = med slant dashdot }; if( nXclLine == EXC_LINE_NONE ) return false; if( nXclLine >= STATIC_TABLE_SIZE( ppnLineParam ) ) nXclLine = EXC_LINE_THIN; rLine.SetColor( rPalette.GetColor( nXclColor ) ); rLine.SetOutWidth( ppnLineParam[ nXclLine ][ 0 ] ); rLine.SetInWidth( ppnLineParam[ nXclLine ][ 1 ] ); rLine.SetDistance( ppnLineParam[ nXclLine ][ 2 ] ); return true; } } // namespace void XclImpCellBorder::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const { if( mbLeftUsed || mbRightUsed || mbTopUsed || mbBottomUsed ) { SvxBoxItem aBoxItem( ATTR_BORDER ); SvxBorderLine aLine; if( mbLeftUsed && lclConvertBorderLine( aLine, rPalette, mnLeftLine, mnLeftColor ) ) aBoxItem.SetLine( &aLine, BOX_LINE_LEFT ); if( mbRightUsed && lclConvertBorderLine( aLine, rPalette, mnRightLine, mnRightColor ) ) aBoxItem.SetLine( &aLine, BOX_LINE_RIGHT ); if( mbTopUsed && lclConvertBorderLine( aLine, rPalette, mnTopLine, mnTopColor ) ) aBoxItem.SetLine( &aLine, BOX_LINE_TOP ); if( mbBottomUsed && lclConvertBorderLine( aLine, rPalette, mnBottomLine, mnBottomColor ) ) aBoxItem.SetLine( &aLine, BOX_LINE_BOTTOM ); ScfTools::PutItem( rItemSet, aBoxItem, bSkipPoolDefs ); } if( mbDiagUsed ) { SvxLineItem aTLBRItem( ATTR_BORDER_TLBR ); SvxLineItem aBLTRItem( ATTR_BORDER_BLTR ); SvxBorderLine aLine; if( lclConvertBorderLine( aLine, rPalette, mnDiagLine, mnDiagColor ) ) { if( mbDiagTLtoBR ) aTLBRItem.SetLine( &aLine ); if( mbDiagBLtoTR ) aBLTRItem.SetLine( &aLine ); } ScfTools::PutItem( rItemSet, aTLBRItem, bSkipPoolDefs ); ScfTools::PutItem( rItemSet, aBLTRItem, bSkipPoolDefs ); } } // ---------------------------------------------------------------------------- XclImpCellArea::XclImpCellArea() { SetUsedFlags( false ); } void XclImpCellArea::SetUsedFlags( bool bUsed ) { mbForeUsed = mbBackUsed = mbPattUsed = bUsed; } void XclImpCellArea::FillFromXF2( sal_uInt8 nFlags ) { mnPattern = ::get_flagvalue( nFlags, EXC_XF2_BACKGROUND, EXC_PATT_12_5_PERC, EXC_PATT_NONE ); mnForeColor = EXC_COLOR_BIFF2_BLACK; mnBackColor = EXC_COLOR_BIFF2_WHITE; SetUsedFlags( true ); } void XclImpCellArea::FillFromXF3( sal_uInt16 nArea ) { mnPattern = ::extract_value< sal_uInt8 >( nArea, 0, 6 ); mnForeColor = ::extract_value< sal_uInt16 >( nArea, 6, 5 ); mnBackColor = ::extract_value< sal_uInt16 >( nArea, 11, 5 ); SetUsedFlags( true ); } void XclImpCellArea::FillFromXF5( sal_uInt32 nArea ) { mnPattern = ::extract_value< sal_uInt8 >( nArea, 16, 6 ); mnForeColor = ::extract_value< sal_uInt16 >( nArea, 0, 7 ); mnBackColor = ::extract_value< sal_uInt16 >( nArea, 7, 7 ); SetUsedFlags( true ); } void XclImpCellArea::FillFromXF8( sal_uInt32 nBorder2, sal_uInt16 nArea ) { mnPattern = ::extract_value< sal_uInt8 >( nBorder2, 26, 6 ); mnForeColor = ::extract_value< sal_uInt16 >( nArea, 0, 7 ); mnBackColor = ::extract_value< sal_uInt16 >( nArea, 7, 7 ); SetUsedFlags( true ); } void XclImpCellArea::FillFromCF8( sal_uInt16 nPattern, sal_uInt16 nColor, sal_uInt32 nFlags ) { mnForeColor = ::extract_value< sal_uInt16 >( nColor, 0, 7 ); mnBackColor = ::extract_value< sal_uInt16 >( nColor, 7, 7 ); mnPattern = ::extract_value< sal_uInt8 >( nPattern, 10, 6 ); mbForeUsed = !::get_flag( nFlags, EXC_CF_AREA_FGCOLOR ); mbBackUsed = !::get_flag( nFlags, EXC_CF_AREA_BGCOLOR ); mbPattUsed = !::get_flag( nFlags, EXC_CF_AREA_PATTERN ); if( mbBackUsed && (!mbPattUsed || (mnPattern == EXC_PATT_SOLID)) ) { mnForeColor = mnBackColor; mnPattern = EXC_PATT_SOLID; mbForeUsed = mbPattUsed = true; } else if( !mbBackUsed && mbPattUsed && (mnPattern == EXC_PATT_SOLID) ) { mbPattUsed = false; } } void XclImpCellArea::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const { if( mbPattUsed ) // colors may be both unused in cond. formats { SvxBrushItem aBrushItem( ATTR_BACKGROUND ); // #108935# do not use IsTransparent() - old Calc filter writes tranparency with different color indexes if( mnPattern == EXC_PATT_NONE ) { aBrushItem.SetColor( Color( COL_TRANSPARENT ) ); } else { Color aFore( rPalette.GetColor( mbForeUsed ? mnForeColor : EXC_COLOR_WINDOWTEXT ) ); Color aBack( rPalette.GetColor( mbBackUsed ? mnBackColor : EXC_COLOR_WINDOWBACK ) ); aBrushItem.SetColor( XclTools::GetPatternColor( aFore, aBack, mnPattern ) ); } ScfTools::PutItem( rItemSet, aBrushItem, bSkipPoolDefs ); } } // ---------------------------------------------------------------------------- XclImpXF::XclImpXF( const XclImpRoot& rRoot ) : XclXFBase( true ), // default is cell XF XclImpRoot( rRoot ), mpStyleSheet( 0 ), mnXclNumFmt( 0 ), mnXclFont( 0 ) { } XclImpXF::~XclImpXF() { } void XclImpXF::ReadXF2( XclImpStream& rStrm ) { sal_uInt8 nReadFont, nReadNumFmt, nFlags; rStrm >> nReadFont; rStrm.Ignore( 1 ); rStrm >> nReadNumFmt >> nFlags; // XF type always cell, no parent, used flags always true SetAllUsedFlags( true ); // attributes maProtection.FillFromXF2( nReadNumFmt ); mnXclFont = nReadFont; mnXclNumFmt = nReadNumFmt & EXC_XF2_VALFMT_MASK; maAlignment.FillFromXF2( nFlags ); maBorder.FillFromXF2( nFlags ); maArea.FillFromXF2( nFlags ); } void XclImpXF::ReadXF3( XclImpStream& rStrm ) { sal_uInt32 nBorder; sal_uInt16 nTypeProt, nAlign, nArea; sal_uInt8 nReadFont, nReadNumFmt; rStrm >> nReadFont >> nReadNumFmt >> nTypeProt >> nAlign >> nArea >> nBorder; // XF type/parent, attribute used flags mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE ); // new in BIFF3 mnParent = ::extract_value< sal_uInt16 >( nAlign, 4, 12 ); // new in BIFF3 SetUsedFlags( ::extract_value< sal_uInt8 >( nTypeProt, 10, 6 ) ); // attributes maProtection.FillFromXF3( nTypeProt ); mnXclFont = nReadFont; mnXclNumFmt = nReadNumFmt; maAlignment.FillFromXF3( nAlign ); maBorder.FillFromXF3( nBorder ); maArea.FillFromXF3( nArea ); // new in BIFF3 } void XclImpXF::ReadXF4( XclImpStream& rStrm ) { sal_uInt32 nBorder; sal_uInt16 nTypeProt, nAlign, nArea; sal_uInt8 nReadFont, nReadNumFmt; rStrm >> nReadFont >> nReadNumFmt >> nTypeProt >> nAlign >> nArea >> nBorder; // XF type/parent, attribute used flags mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE ); mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 ); SetUsedFlags( ::extract_value< sal_uInt8 >( nAlign, 10, 6 ) ); // attributes maProtection.FillFromXF3( nTypeProt ); mnXclFont = nReadFont; mnXclNumFmt = nReadNumFmt; maAlignment.FillFromXF4( nAlign ); maBorder.FillFromXF3( nBorder ); maArea.FillFromXF3( nArea ); } void XclImpXF::ReadXF5( XclImpStream& rStrm ) { sal_uInt32 nArea, nBorder; sal_uInt16 nTypeProt, nAlign; rStrm >> mnXclFont >> mnXclNumFmt >> nTypeProt >> nAlign >> nArea >> nBorder; // XF type/parent, attribute used flags mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE ); mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 ); SetUsedFlags( ::extract_value< sal_uInt8 >( nAlign, 10, 6 ) ); // attributes maProtection.FillFromXF3( nTypeProt ); maAlignment.FillFromXF5( nAlign ); maBorder.FillFromXF5( nBorder, nArea ); maArea.FillFromXF5( nArea ); } void XclImpXF::ReadXF8( XclImpStream& rStrm ) { sal_uInt32 nBorder1, nBorder2; sal_uInt16 nTypeProt, nAlign, nMiscAttrib, nArea; rStrm >> mnXclFont >> mnXclNumFmt >> nTypeProt >> nAlign >> nMiscAttrib >> nBorder1 >> nBorder2 >> nArea; // XF type/parent, attribute used flags mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE ); mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 ); SetUsedFlags( ::extract_value< sal_uInt8 >( nMiscAttrib, 10, 6 ) ); // attributes maProtection.FillFromXF3( nTypeProt ); maAlignment.FillFromXF8( nAlign, nMiscAttrib ); maBorder.FillFromXF8( nBorder1, nBorder2 ); maArea.FillFromXF8( nBorder2, nArea ); } void XclImpXF::ReadXF( XclImpStream& rStrm ) { switch( GetBiff() ) { case EXC_BIFF2: ReadXF2( rStrm ); break; case EXC_BIFF3: ReadXF3( rStrm ); break; case EXC_BIFF4: ReadXF4( rStrm ); break; case EXC_BIFF5: ReadXF5( rStrm ); break; case EXC_BIFF8: ReadXF8( rStrm ); break; default: DBG_ERROR_BIFF(); } } const ScPatternAttr& XclImpXF::CreatePattern( bool bSkipPoolDefs ) { if( mpPattern.get() ) return *mpPattern; // create new pattern attribute set mpPattern.reset( new ScPatternAttr( GetDoc().GetPool() ) ); SfxItemSet& rItemSet = mpPattern->GetItemSet(); // parent cell style if( IsCellXF() && !mpStyleSheet ) { mpStyleSheet = GetXFBuffer().CreateStyleSheet( mnParent ); if( XclImpXF* pParentXF = GetXFBuffer().GetXF( mnParent ) ) UpdateUsedFlags( *pParentXF ); } // cell protection if( mbProtUsed ) maProtection.FillToItemSet( rItemSet, bSkipPoolDefs ); // font if( mbFontUsed ) GetFontBuffer().FillToItemSet( rItemSet, EXC_FONTITEM_CELL, mnXclFont, bSkipPoolDefs ); // value format if( mbFmtUsed ) { GetNumFmtBuffer().FillToItemSet( rItemSet, mnXclNumFmt, bSkipPoolDefs ); // Trace occurrences of Windows date formats GetTracer().TraceDates( mnXclNumFmt ); } // alignment if( mbAlignUsed ) maAlignment.FillToItemSet( rItemSet, GetFontBuffer().GetFont( mnXclFont ), bSkipPoolDefs ); // border if( mbBorderUsed ) { maBorder.FillToItemSet( rItemSet, GetPalette(), bSkipPoolDefs ); GetTracer().TraceBorderLineStyle(maBorder.mnLeftLine > EXC_LINE_HAIR || maBorder.mnRightLine > EXC_LINE_HAIR || maBorder.mnTopLine > EXC_LINE_HAIR || maBorder.mnBottomLine > EXC_LINE_HAIR ); } // area if( mbAreaUsed ) { maArea.FillToItemSet( rItemSet, GetPalette(), bSkipPoolDefs ); GetTracer().TraceFillPattern(maArea.mnPattern != EXC_PATT_NONE && maArea.mnPattern != EXC_PATT_SOLID); } return *mpPattern; } void XclImpXF::ApplyPattern( SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2, SCTAB nScTab, ULONG nForceScNumFmt ) { // force creation of cell style and hard formatting, do it here to have mpStyleSheet const ScPatternAttr& rPattern = CreatePattern(); // insert into document ScDocument& rDoc = GetDoc(); if( IsCellXF() && mpStyleSheet ) rDoc.ApplyStyleAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, *mpStyleSheet ); if( HasUsedFlags() ) rDoc.ApplyPatternAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, rPattern ); // #108770# apply special number format if( nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND ) { ScPatternAttr aPattern( GetDoc().GetPool() ); GetNumFmtBuffer().FillScFmtToItemSet( aPattern.GetItemSet(), nForceScNumFmt ); rDoc.ApplyPatternAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, aPattern ); } } void XclImpXF::SetUsedFlags( sal_uInt8 nUsedFlags ) { /* Notes about finding the mb***Used flags: - In cell XFs a *set* bit means a used attribute. - In style XFs a *cleared* bit means a used attribute. The mb***Used members always store true, if the attribute is used. The "mbCellXF == ::get_flag(...)" construct evaluates to true in both mentioned cases: cell XF and set bit; or style XF and cleared bit. */ mbProtUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_PROT )); mbFontUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_FONT )); mbFmtUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_VALFMT )); mbAlignUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_ALIGN )); mbBorderUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_BORDER )); mbAreaUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_AREA )); } void XclImpXF::UpdateUsedFlags( const XclImpXF& rParentXF ) { /* Enables mb***Used flags, if the formatting attributes differ from the passed XF record. In cell XFs Excel uses the cell attributes, if they differ from the parent style XF. #109899# ...or if the respective flag is not set in parent style XF. */ if( !mbProtUsed ) mbProtUsed = !rParentXF.mbProtUsed || !(maProtection == rParentXF.maProtection); if( !mbFontUsed ) mbFontUsed = !rParentXF.mbFontUsed || (mnXclFont != rParentXF.mnXclFont); if( !mbFmtUsed ) mbFmtUsed = !rParentXF.mbFmtUsed || (mnXclNumFmt != rParentXF.mnXclNumFmt); if( !mbAlignUsed ) mbAlignUsed = !rParentXF.mbAlignUsed || !(maAlignment == rParentXF.maAlignment); if( !mbBorderUsed ) mbBorderUsed = !rParentXF.mbBorderUsed || !(maBorder == rParentXF.maBorder); if( !mbAreaUsed ) mbAreaUsed = !rParentXF.mbAreaUsed || !(maArea == rParentXF.maArea); } // ---------------------------------------------------------------------------- XclImpStyle::XclImpStyle( const XclImpRoot& rRoot ) : XclImpRoot( rRoot ), mnXfId( EXC_XF_NOTFOUND ), mnBuiltinId( EXC_STYLE_USERDEF ), mnLevel( EXC_STYLE_NOLEVEL ), mbBuiltin( false ), mbCustom( false ), mbHidden( false ), mpStyleSheet( 0 ) { } void XclImpStyle::ReadStyle( XclImpStream& rStrm ) { DBG_ASSERT_BIFF( GetBiff() >= EXC_BIFF3 ); sal_uInt16 nXFIndex; rStrm >> nXFIndex; mnXfId = nXFIndex & EXC_STYLE_XFMASK; mbBuiltin = ::get_flag( nXFIndex, EXC_STYLE_BUILTIN ); if( mbBuiltin ) { rStrm >> mnBuiltinId >> mnLevel; } else { maName = (GetBiff() <= EXC_BIFF5) ? rStrm.ReadByteString( false ) : rStrm.ReadUniString(); // #i103281# check if this is a new built-in style introduced in XL2007 if( (GetBiff() == EXC_BIFF8) && (rStrm.GetNextRecId() == EXC_ID_STYLEEXT) && rStrm.StartNextRecord() ) { sal_uInt8 nExtFlags; rStrm.Ignore( 12 ); rStrm >> nExtFlags; mbBuiltin = ::get_flag( nExtFlags, EXC_STYLEEXT_BUILTIN ); mbCustom = ::get_flag( nExtFlags, EXC_STYLEEXT_CUSTOM ); mbHidden = ::get_flag( nExtFlags, EXC_STYLEEXT_HIDDEN ); if( mbBuiltin ) { rStrm.Ignore( 1 ); // category rStrm >> mnBuiltinId >> mnLevel; } } } } ScStyleSheet* XclImpStyle::CreateStyleSheet() { // #i1624# #i1768# ignore unnamed user styles if( !mpStyleSheet && (maFinalName.Len() > 0) ) { bool bCreatePattern = false; XclImpXF* pXF = GetXFBuffer().GetXF( mnXfId ); bool bDefStyle = mbBuiltin && (mnBuiltinId == EXC_STYLE_NORMAL); if( bDefStyle ) { // set all flags to true to get all items in XclImpXF::CreatePattern() if( pXF ) pXF->SetAllUsedFlags( true ); // use existing "Default" style sheet mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find( ScGlobal::GetRscString( STR_STYLENAME_STANDARD ), SFX_STYLE_FAMILY_PARA ) ); DBG_ASSERT( mpStyleSheet, "XclImpStyle::CreateStyleSheet - Default style not found" ); bCreatePattern = true; } else { /* #i103281# do not create another style sheet of the same name, if it exists already. This is needed to prevent that styles pasted from clipboard get duplicated over and over. */ mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find( maFinalName, SFX_STYLE_FAMILY_PARA ) ); if( !mpStyleSheet ) { mpStyleSheet = &static_cast< ScStyleSheet& >( GetStyleSheetPool().Make( maFinalName, SFX_STYLE_FAMILY_PARA, SFXSTYLEBIT_USERDEF ) ); bCreatePattern = true; } } // bDefStyle==true omits default pool items in CreatePattern() if( bCreatePattern && mpStyleSheet && pXF ) mpStyleSheet->GetItemSet().Put( pXF->CreatePattern( bDefStyle ).GetItemSet() ); } return mpStyleSheet; } void XclImpStyle::CreateUserStyle( const String& rFinalName ) { maFinalName = rFinalName; if( !IsBuiltin() || mbCustom ) CreateStyleSheet(); } // ---------------------------------------------------------------------------- XclImpXFBuffer::XclImpXFBuffer( const XclImpRoot& rRoot ) : XclImpRoot( rRoot ) { } void XclImpXFBuffer::Initialize() { maXFList.Clear(); maBuiltinStyles.Clear(); maUserStyles.Clear(); maStylesByXf.clear(); } void XclImpXFBuffer::ReadXF( XclImpStream& rStrm ) { XclImpXF* pXF = new XclImpXF( GetRoot() ); pXF->ReadXF( rStrm ); maXFList.Append( pXF ); } void XclImpXFBuffer::ReadStyle( XclImpStream& rStrm ) { XclImpStyle* pStyle = new XclImpStyle( GetRoot() ); pStyle->ReadStyle( rStrm ); (pStyle->IsBuiltin() ? maBuiltinStyles : maUserStyles).Append( pStyle ); DBG_ASSERT( maStylesByXf.count( pStyle->GetXfId() ) == 0, "XclImpXFBuffer::ReadStyle - multiple styles with equal XF identifier" ); maStylesByXf[ pStyle->GetXfId() ] = pStyle; } sal_uInt16 XclImpXFBuffer::GetFontIndex( sal_uInt16 nXFIndex ) const { const XclImpXF* pXF = GetXF( nXFIndex ); return pXF ? pXF->GetFontIndex() : EXC_FONT_NOTFOUND; } const XclImpFont* XclImpXFBuffer::GetFont( sal_uInt16 nXFIndex ) const { return GetFontBuffer().GetFont( GetFontIndex( nXFIndex ) ); } namespace { /** Functor for case-insensitive string comparison, usable in maps etc. */ struct IgnoreCaseCompare { inline bool operator()( const String& rName1, const String& rName2 ) const { return rName1.CompareIgnoreCaseToAscii( rName2 ) == COMPARE_LESS; } }; } // namespace void XclImpXFBuffer::CreateUserStyles() { // calculate final names of all styles typedef ::std::map< String, XclImpStyle*, IgnoreCaseCompare > CellStyleNameMap; typedef ::std::vector< XclImpStyle* > XclImpStyleVector; CellStyleNameMap aCellStyles; XclImpStyleVector aConflictNameStyles; /* First, reserve style names that are built-in in Calc. This causes that imported cell styles get different unused names and thus do not try to overwrite these built-in styles. For BIFF4 workbooks (which contain a separate list of cell styles per sheet), reserve all existing styles if current sheet is not the first sheet (this styles buffer will be initialized again for every new sheet). This will create unique names for styles in different sheets with the same name. Assuming that the BIFF4W import filter is never used to import from clipboard... */ bool bReserveAll = (GetBiff() == EXC_BIFF4) && (GetCurrScTab() > 0); SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SFX_STYLE_FAMILY_PARA ); String aStandardName = ScGlobal::GetRscString( STR_STYLENAME_STANDARD ); for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() ) if( (pStyleSheet->GetName() != aStandardName) && (bReserveAll || !pStyleSheet->IsUserDefined()) ) if( aCellStyles.count( pStyleSheet->GetName() ) == 0 ) aCellStyles[ pStyleSheet->GetName() ] = 0; /* Calculate names of built-in styles. Store styles with reserved names in the aConflictNameStyles list. */ for( XclImpStyle* pStyle = maBuiltinStyles.First(); pStyle; pStyle = maBuiltinStyles.Next() ) { String aStyleName = XclTools::GetBuiltInStyleName( pStyle->GetBuiltinId(), pStyle->GetName(), pStyle->GetLevel() ); DBG_ASSERT( bReserveAll || (aCellStyles.count( aStyleName ) == 0), "XclImpXFBuffer::CreateUserStyles - multiple styles with equal built-in identifier" ); if( aCellStyles.count( aStyleName ) > 0 ) aConflictNameStyles.push_back( pStyle ); else aCellStyles[ aStyleName ] = pStyle; } /* Calculate names of user defined styles. Store styles with reserved names in the aConflictNameStyles list. */ for( XclImpStyle* pStyle = maUserStyles.First(); pStyle; pStyle = maUserStyles.Next() ) { // #i1624# #i1768# ignore unnamed user styles if( pStyle->GetName().Len() > 0 ) { if( aCellStyles.count( pStyle->GetName() ) > 0 ) aConflictNameStyles.push_back( pStyle ); else aCellStyles[ pStyle->GetName() ] = pStyle; } } // find unused names for all styles with conflicting names for( XclImpStyleVector::iterator aIt = aConflictNameStyles.begin(), aEnd = aConflictNameStyles.end(); aIt != aEnd; ++aIt ) { XclImpStyle* pStyle = *aIt; String aUnusedName; sal_Int32 nIndex = 0; do { aUnusedName.Assign( pStyle->GetName() ).Append( ' ' ).Append( String::CreateFromInt32( ++nIndex ) ); } while( aCellStyles.count( aUnusedName ) > 0 ); aCellStyles[ aUnusedName ] = pStyle; } // set final names and create user-defined and modified built-in cell styles for( CellStyleNameMap::iterator aIt = aCellStyles.begin(), aEnd = aCellStyles.end(); aIt != aEnd; ++aIt ) if( aIt->second ) aIt->second->CreateUserStyle( aIt->first ); } ScStyleSheet* XclImpXFBuffer::CreateStyleSheet( sal_uInt16 nXFIndex ) { XclImpStyleMap::iterator aIt = maStylesByXf.find( nXFIndex ); return (aIt == maStylesByXf.end()) ? 0 : aIt->second->CreateStyleSheet(); } void XclImpXFBuffer::ApplyPattern( SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2, SCTAB nScTab, const XclImpXFIndex& rXFIndex ) { if( XclImpXF* pXF = GetXF( rXFIndex.GetXFIndex() ) ) { // #108770# set 'Standard' number format for all Boolean cells ULONG nForceScNumFmt = rXFIndex.IsBoolCell() ? GetNumFmtBuffer().GetStdScNumFmt() : NUMBERFORMAT_ENTRY_NOT_FOUND; pXF->ApplyPattern( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, nForceScNumFmt ); } } // Buffer for XF indexes in cells ============================================= IMPL_FIXEDMEMPOOL_NEWDEL( XclImpXFRange, 100, 500 ) bool XclImpXFRange::Expand( SCROW nScRow, const XclImpXFIndex& rXFIndex ) { if( maXFIndex != rXFIndex ) return false; if( mnScRow2 + 1 == nScRow ) { ++mnScRow2; return true; } if( mnScRow1 > 0 && (mnScRow1 - 1 == nScRow) ) { --mnScRow1; return true; } return false; } bool XclImpXFRange::Expand( const XclImpXFRange& rNextRange ) { DBG_ASSERT( mnScRow2 < rNextRange.mnScRow1, "XclImpXFRange::Expand - rows out of order" ); if( (maXFIndex == rNextRange.maXFIndex) && (mnScRow2 + 1 == rNextRange.mnScRow1) ) { mnScRow2 = rNextRange.mnScRow2; return true; } return false; } // ---------------------------------------------------------------------------- void XclImpXFRangeColumn::SetDefaultXF( const XclImpXFIndex& rXFIndex ) { // List should be empty when inserting the default column format. // Later explicit SetXF() calls will break up this range. DBG_ASSERT( maIndexList.Empty(), "XclImpXFRangeColumn::SetDefaultXF - Setting Default Column XF is not empty" ); // insert a complete row range with one insert. maIndexList.Append( new XclImpXFRange( 0, MAXROW, rXFIndex ) ); } // ---------------------------------------------------------------------------- void XclImpXFRangeColumn::SetXF( SCROW nScRow, const XclImpXFIndex& rXFIndex ) { XclImpXFRange* pPrevRange; XclImpXFRange* pNextRange; ULONG nNextIndex; Find( pPrevRange, pNextRange, nNextIndex, nScRow ); // previous range: // try to overwrite XF (if row is contained in) or try to expand range if( pPrevRange ) { if( pPrevRange->Contains( nScRow ) ) // overwrite old XF { if( rXFIndex == pPrevRange->maXFIndex ) return; SCROW nFirstScRow = pPrevRange->mnScRow1; SCROW nLastScRow = pPrevRange->mnScRow2; ULONG nIndex = nNextIndex - 1; XclImpXFRange* pThisRange = pPrevRange; pPrevRange = nIndex ? maIndexList.GetObject( nIndex - 1 ) : 0; if( nFirstScRow == nLastScRow ) // replace solely XF { pThisRange->maXFIndex = rXFIndex; TryConcatPrev( nNextIndex ); // try to concat. next with this TryConcatPrev( nIndex ); // try to concat. this with previous } else if( nFirstScRow == nScRow ) // replace first XF { ++(pThisRange->mnScRow1); // try to concatenate with previous of this if( !pPrevRange || !pPrevRange->Expand( nScRow, rXFIndex ) ) maIndexList.Insert( new XclImpXFRange( nScRow, rXFIndex ), nIndex ); } else if( nLastScRow == nScRow ) // replace last XF { --(pThisRange->mnScRow2); if( !pNextRange || !pNextRange->Expand( nScRow, rXFIndex ) ) maIndexList.Insert( new XclImpXFRange( nScRow, rXFIndex ), nNextIndex ); } else // insert in the middle of the range { pThisRange->mnScRow1 = nScRow + 1; // List::Insert() moves entries towards end of list, so insert twice at nIndex maIndexList.Insert( new XclImpXFRange( nScRow, rXFIndex ), nIndex ); maIndexList.Insert( new XclImpXFRange( nFirstScRow, nScRow - 1, pThisRange->maXFIndex ), nIndex ); } return; } else if( pPrevRange->Expand( nScRow, rXFIndex ) ) // try to expand { TryConcatPrev( nNextIndex ); // try to concatenate next with expanded return; } } // try to expand next range if( pNextRange && pNextRange->Expand( nScRow, rXFIndex ) ) return; // create new range maIndexList.Insert( new XclImpXFRange( nScRow, rXFIndex ), nNextIndex ); } void XclImpXFRangeColumn::Find( XclImpXFRange*& rpPrevRange, XclImpXFRange*& rpNextRange, ULONG& rnNextIndex, SCROW nScRow ) const { // test whether list is empty if( maIndexList.Empty() ) { rpPrevRange = rpNextRange = 0; rnNextIndex = 0; return; } rpPrevRange = maIndexList.GetObject( 0 ); rpNextRange = maIndexList.GetObject( maIndexList.Count() - 1 ); // test whether row is at end of list (contained in or behind last range) // rpPrevRange will contain a possible existing row if( rpNextRange->mnScRow1 <= nScRow ) { rpPrevRange = rpNextRange; rpNextRange = 0; rnNextIndex = maIndexList.Count(); return; } // test whether row is at beginning of list (really before first range) if( nScRow < rpPrevRange->mnScRow1 ) { rpNextRange = rpPrevRange; rpPrevRange = 0; rnNextIndex = 0; return; } // loop: find range entries before and after new row // break the loop if there is no more range between first and last -or- // if rpPrevRange contains nScRow (rpNextRange will never contain nScRow) ULONG nPrevIndex = 0; ULONG nMidIndex; rnNextIndex = maIndexList.Count() - 1; XclImpXFRange* pMidRange; while( ((rnNextIndex - nPrevIndex) > 1) && (rpPrevRange->mnScRow2 < nScRow) ) { nMidIndex = (nPrevIndex + rnNextIndex) / 2; pMidRange = maIndexList.GetObject( nMidIndex ); DBG_ASSERT( pMidRange, "XclImpXFRangeColumn::Find - missing XF index range" ); if( nScRow < pMidRange->mnScRow1 ) // row is really before pMidRange { rpNextRange = pMidRange; rnNextIndex = nMidIndex; } else // row is in or after pMidRange { rpPrevRange = pMidRange; nPrevIndex = nMidIndex; } } // find next rpNextRange if rpPrevRange contains nScRow if( nScRow <= rpPrevRange->mnScRow2 ) { rnNextIndex = nPrevIndex + 1; rpNextRange = maIndexList.GetObject( rnNextIndex ); } } void XclImpXFRangeColumn::TryConcatPrev( ULONG nIndex ) { if( !nIndex ) return; XclImpXFRange* pPrevRange = maIndexList.GetObject( nIndex - 1 ); XclImpXFRange* pNextRange = maIndexList.GetObject( nIndex ); if( !pPrevRange || !pNextRange ) return; if( pPrevRange->Expand( *pNextRange ) ) maIndexList.Delete( nIndex ); } // ---------------------------------------------------------------------------- XclImpXFRangeBuffer::XclImpXFRangeBuffer( const XclImpRoot& rRoot ) : XclImpRoot( rRoot ) { } XclImpXFRangeBuffer::~XclImpXFRangeBuffer() { } void XclImpXFRangeBuffer::Initialize() { maColumns.clear(); maHyperlinks.clear(); maMergeList.RemoveAll(); } void XclImpXFRangeBuffer::SetXF( const ScAddress& rScPos, sal_uInt16 nXFIndex, XclImpXFInsertMode eMode ) { SCCOL nScCol = rScPos.Col(); SCROW nScRow = rScPos.Row(); // set cell XF's size_t nIndex = static_cast< size_t >( nScCol ); if( maColumns.size() <= nIndex ) maColumns.resize( nIndex + 1 ); if( !maColumns[ nIndex ] ) maColumns[ nIndex ].reset( new XclImpXFRangeColumn ); // #108770# remember all Boolean cells, they will get 'Standard' number format maColumns[ nIndex ]->SetXF( nScRow, XclImpXFIndex( nXFIndex, eMode == xlXFModeBoolCell ) ); // set "center across selection" and "fill" attribute for all following empty cells // #97130# ignore it on row default XFs if( eMode != xlXFModeRow ) { const XclImpXF* pXF = GetXFBuffer().GetXF( nXFIndex ); if( pXF && ((pXF->GetHorAlign() == EXC_XF_HOR_CENTER_AS) || (pXF->GetHorAlign() == EXC_XF_HOR_FILL)) ) { // expand last merged range if this attribute is set repeatedly ScRange* pRange = maMergeList.Last(); if( pRange && (pRange->aEnd.Row() == nScRow) && (pRange->aEnd.Col() + 1 == nScCol) && (eMode == xlXFModeBlank) ) pRange->aEnd.IncCol(); else if( eMode != xlXFModeBlank ) // #108781# do not merge empty cells SetMerge( nScCol, nScRow ); } } } void XclImpXFRangeBuffer::SetXF( const ScAddress& rScPos, sal_uInt16 nXFIndex ) { SetXF( rScPos, nXFIndex, xlXFModeCell ); } void XclImpXFRangeBuffer::SetBlankXF( const ScAddress& rScPos, sal_uInt16 nXFIndex ) { SetXF( rScPos, nXFIndex, xlXFModeBlank ); } void XclImpXFRangeBuffer::SetBoolXF( const ScAddress& rScPos, sal_uInt16 nXFIndex ) { SetXF( rScPos, nXFIndex, xlXFModeBoolCell ); } void XclImpXFRangeBuffer::SetRowDefXF( SCROW nScRow, sal_uInt16 nXFIndex ) { for( SCCOL nScCol = 0; nScCol <= MAXCOL; ++nScCol ) SetXF( ScAddress( nScCol, nScRow, 0 ), nXFIndex, xlXFModeRow ); } void XclImpXFRangeBuffer::SetColumnDefXF( SCCOL nScCol, sal_uInt16 nXFIndex ) { // our array should not have values when creating the default column format. size_t nIndex = static_cast< size_t >( nScCol ); if( maColumns.size() <= nIndex ) maColumns.resize( nIndex + 1 ); DBG_ASSERT( !maColumns[ nIndex ], "XclImpXFRangeBuffer::SetColumnDefXF - default column of XFs already has values" ); maColumns[ nIndex ].reset( new XclImpXFRangeColumn ); maColumns[ nIndex ]->SetDefaultXF( XclImpXFIndex( nXFIndex ) ); } void XclImpXFRangeBuffer::SetBorderLine( const ScRange& rRange, SCTAB nScTab, USHORT nLine ) { SCCOL nFromScCol = (nLine == BOX_LINE_RIGHT) ? rRange.aEnd.Col() : rRange.aStart.Col(); SCROW nFromScRow = (nLine == BOX_LINE_BOTTOM) ? rRange.aEnd.Row() : rRange.aStart.Row(); ScDocument& rDoc = GetDoc(); const SvxBoxItem* pFromItem = static_cast< const SvxBoxItem* >( rDoc.GetAttr( nFromScCol, nFromScRow, nScTab, ATTR_BORDER ) ); const SvxBoxItem* pToItem = static_cast< const SvxBoxItem* >( rDoc.GetAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, ATTR_BORDER ) ); SvxBoxItem aNewItem( *pToItem ); aNewItem.SetLine( pFromItem->GetLine( nLine ), nLine ); rDoc.ApplyAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, aNewItem ); } void XclImpXFRangeBuffer::SetHyperlink( const XclRange& rXclRange, const String& rUrl ) { maHyperlinks.push_back( XclImpHyperlinkRange( rXclRange, rUrl ) ); } void XclImpXFRangeBuffer::SetMerge( SCCOL nScCol, SCROW nScRow ) { maMergeList.Append( ScRange( nScCol, nScRow, 0 ) ); } void XclImpXFRangeBuffer::SetMerge( SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2 ) { if( (nScCol1 < nScCol2) || (nScRow1 < nScRow2) ) maMergeList.Append( ScRange( nScCol1, nScRow1, 0, nScCol2, nScRow2, 0 ) ); } void XclImpXFRangeBuffer::Finalize() { ScDocument& rDoc = GetDoc(); SCTAB nScTab = GetCurrScTab(); // apply patterns XclImpXFBuffer& rXFBuffer = GetXFBuffer(); for( XclImpXFRangeColumnVec::const_iterator aVBeg = maColumns.begin(), aVEnd = maColumns.end(), aVIt = aVBeg; aVIt != aVEnd; ++aVIt ) { // apply all cell styles of an existing column if( aVIt->is() ) { XclImpXFRangeColumn& rColumn = **aVIt; SCCOL nScCol = static_cast< SCCOL >( aVIt - aVBeg ); for( XclImpXFRange* pStyle = rColumn.First(); pStyle; pStyle = rColumn.Next() ) rXFBuffer.ApplyPattern( nScCol, pStyle->mnScRow1, nScCol, pStyle->mnScRow2, nScTab, pStyle->maXFIndex ); } } // insert hyperlink cells for( XclImpHyperlinkList::const_iterator aLIt = maHyperlinks.begin(), aLEnd = maHyperlinks.end(); aLIt != aLEnd; ++aLIt ) XclImpHyperlink::InsertUrl( GetRoot(), aLIt->first, aLIt->second ); // apply cell merging for( const ScRange* pRange = maMergeList.First(); pRange; pRange = maMergeList.Next() ) { const ScAddress& rStart = pRange->aStart; const ScAddress& rEnd = pRange->aEnd; bool bMultiCol = rStart.Col() != rEnd.Col(); bool bMultiRow = rStart.Row() != rEnd.Row(); // set correct right border if( bMultiCol ) SetBorderLine( *pRange, nScTab, BOX_LINE_RIGHT ); // set correct lower border if( bMultiRow ) SetBorderLine( *pRange, nScTab, BOX_LINE_BOTTOM ); // do merge if( bMultiCol || bMultiRow ) rDoc.DoMerge( nScTab, rStart.Col(), rStart.Row(), rEnd.Col(), rEnd.Row() ); // #i93609# merged range in a single row: test if manual row height is needed if( !bMultiRow ) { bool bTextWrap = static_cast< const SfxBoolItem* >( rDoc.GetAttr( rStart.Col(), rStart.Row(), rStart.Tab(), ATTR_LINEBREAK ) )->GetValue(); if( !bTextWrap && (rDoc.GetCellType( rStart ) == CELLTYPE_EDIT) ) if( const EditTextObject* pEditObj = static_cast< const ScEditCell* >( rDoc.GetCell( rStart ) )->GetData() ) bTextWrap = pEditObj->GetParagraphCount() > 1; if( bTextWrap ) GetOldRoot().pColRowBuff->SetManualRowHeight( rStart.Row() ); } } } // ============================================================================