| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sc.hxx" |
| #include "xistyle.hxx" |
| #include <sfx2/printer.hxx> |
| #include <sfx2/objsh.hxx> |
| #include <svtools/ctrltool.hxx> |
| #include <editeng/editobj.hxx> |
| #include "scitems.hxx" |
| #include <editeng/fontitem.hxx> |
| #include <editeng/fhgtitem.hxx> |
| #include <editeng/wghtitem.hxx> |
| #include <editeng/udlnitem.hxx> |
| #include <editeng/postitem.hxx> |
| #include <editeng/crsditem.hxx> |
| #include <editeng/cntritem.hxx> |
| #include <editeng/shdditem.hxx> |
| #include <editeng/escpitem.hxx> |
| #include <svx/algitem.hxx> |
| #include <editeng/boxitem.hxx> |
| #include <editeng/bolnitem.hxx> |
| #include <svx/rotmodit.hxx> |
| #include <editeng/colritem.hxx> |
| #include <editeng/brshitem.hxx> |
| #include <editeng/frmdiritem.hxx> |
| #include <editeng/eeitem.hxx> |
| #include <editeng/flstitem.hxx> |
| #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 ); |
| } |
| |
| ::com::sun::star::uno::Sequence< sal_Int32 > XclImpPalette::CreateColorSequence() const |
| { |
| sal_Int32 nCount = static_cast< sal_Int32 >( maColorTable.size() ); |
| ::com::sun::star::uno::Sequence< sal_Int32 > aSeq( nCount ); |
| if( nCount > 0 ) |
| { |
| sal_Int32* pnSeqColor = aSeq.getArray(); |
| for( ColorDataVec::const_iterator aIt = maColorTable.begin(), aEnd = maColorTable.end(); aIt != aEnd; ++aIt, ++pnSeqColor ) |
| *pnSeqColor = static_cast< sal_Int32 >( *aIt ); |
| } |
| return aSeq; |
| } |
| |
| 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; |
| |
| //add corresponding pitch for FontFamily |
| FontPitch ePitch = PITCH_DONTKNOW; |
| FontFamily eFtFamily = maData.GetScFamily( GetTextEncoding() ); |
| switch( eFtFamily ) //refer http://msdn.microsoft.com/en-us/library/aa246306(v=VS.60).aspx |
| { |
| case FAMILY_ROMAN: ePitch = PITCH_VARIABLE; break; |
| case FAMILY_SWISS: ePitch = PITCH_VARIABLE; break; |
| case FAMILY_MODERN: ePitch = PITCH_FIXED; break; |
| default: break; |
| } |
| SvxFontItem aFontItem( eFtFamily , maData.maName, EMPTY_STRING, ePitch, 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; |
| } |
| } |
| |
| sal_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 |
| { |
| sal_uLong nScNumFmt = GetScFormat( nXclNumFmt ); |
| if( nScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND ) |
| nScNumFmt = GetStdScNumFmt(); |
| FillScFmtToItemSet( rItemSet, nScNumFmt, bSkipPoolDefs ); |
| } |
| |
| void XclImpNumFmtBuffer::FillScFmtToItemSet( SfxItemSet& rItemSet, sal_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, sal_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 ); |
| // 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; |
| } |
| |
| bool XclImpCellBorder::HasAnyOuterBorder() const |
| { |
| return |
| (mbLeftUsed && (mnLeftLine != EXC_LINE_NONE)) || |
| (mbRightUsed && (mnRightLine != EXC_LINE_NONE)) || |
| (mbTopUsed && (mnTopLine != EXC_LINE_NONE)) || |
| (mbBottomUsed && (mnBottomLine != EXC_LINE_NONE)); |
| } |
| |
| 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_ARRAY_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 ), |
| mpPooledPattern( 0 ), |
| 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(); |
| XclImpXF* pParentXF = IsCellXF() ? GetXFBuffer().GetXF( mnParent ) : 0; |
| |
| // parent cell style |
| if( IsCellXF() && !mpStyleSheet ) |
| { |
| mpStyleSheet = GetXFBuffer().CreateStyleSheet( mnParent ); |
| |
| /* 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( pParentXF ) |
| { |
| if( !mbProtUsed ) |
| mbProtUsed = !pParentXF->mbProtUsed || !(maProtection == pParentXF->maProtection); |
| if( !mbFontUsed ) |
| mbFontUsed = !pParentXF->mbFontUsed || (mnXclFont != pParentXF->mnXclFont); |
| if( !mbFmtUsed ) |
| mbFmtUsed = !pParentXF->mbFmtUsed || (mnXclNumFmt != pParentXF->mnXclNumFmt); |
| if( !mbAlignUsed ) |
| mbAlignUsed = !pParentXF->mbAlignUsed || !(maAlignment == pParentXF->maAlignment); |
| if( !mbBorderUsed ) |
| mbBorderUsed = !pParentXF->mbBorderUsed || !(maBorder == pParentXF->maBorder); |
| if( !mbAreaUsed ) |
| mbAreaUsed = !pParentXF->mbAreaUsed || !(maArea == pParentXF->maArea); |
| } |
| } |
| |
| // 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); |
| } |
| |
| /* #i38709# Decide which rotation reference mode to use. If any outer |
| border line of the cell is set (either explicitly or via cell style), |
| and the cell contents are rotated, set rotation reference to bottom of |
| cell. This causes the borders to be painted rotated with the text. */ |
| if( mbAlignUsed || mbBorderUsed ) |
| { |
| SvxRotateMode eRotateMode = SVX_ROTATE_MODE_STANDARD; |
| const XclImpCellAlign* pAlign = mbAlignUsed ? &maAlignment : (pParentXF ? &pParentXF->maAlignment : 0); |
| const XclImpCellBorder* pBorder = mbBorderUsed ? &maBorder : (pParentXF ? &pParentXF->maBorder : 0); |
| if( pAlign && pBorder && (0 < pAlign->mnRotation) && (pAlign->mnRotation <= 180) && pBorder->HasAnyOuterBorder() ) |
| eRotateMode = SVX_ROTATE_MODE_BOTTOM; |
| ScfTools::PutItem( rItemSet, SvxRotateModeItem( eRotateMode, ATTR_ROTATE_MODE ), bSkipPoolDefs ); |
| } |
| |
| return *mpPattern; |
| } |
| |
| void XclImpXF::ApplyPattern( |
| SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2, |
| SCTAB nScTab, sal_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(); |
| sal_Bool bApplyPattern = sal_False; |
| |
| if (IsCellXF() && mpPooledPattern && mpPooledPattern->GetRefCount()>0 && mpPooledPattern->GetRefCount() <= SFX_ITEMS_MAXREF) |
| { |
| rDoc.ApplyPooledPatternAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, *mpPooledPattern, rPattern ); |
| mpPooledPattern->AddRef(); |
| } |
| else |
| { |
| if( IsCellXF() && mpStyleSheet ) |
| { |
| rDoc.ApplyStyleAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, *mpStyleSheet ); |
| bApplyPattern = sal_True; |
| } |
| if( HasUsedFlags() ) |
| { |
| rDoc.ApplyPatternAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, rPattern ); |
| bApplyPattern = sal_True; |
| } |
| } |
| |
| if (IsCellXF() && !mpPooledPattern && bApplyPattern) |
| { |
| mpPooledPattern = rDoc.GetPattern(nScCol1, nScRow1, nScTab); |
| ScPatternAttr* pPooledPattern = const_cast<ScPatternAttr*>(mpPooledPattern); |
| StartListening(*pPooledPattern); |
| } |
| |
| // #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::Notify(SfxBroadcaster& /* rBC */, const SfxHint& /* rHint */ ) |
| { |
| mpPooledPattern = 0; |
| } |
| |
| /*static*/ void XclImpXF::ApplyPatternForBiff2CellFormat( const XclImpRoot& rRoot, |
| const ScAddress& rScPos, sal_uInt8 nFlags1, sal_uInt8 nFlags2, sal_uInt8 nFlags3 ) |
| { |
| /* Create an XF object and let it do the work. We will have access to its |
| private members here. */ |
| XclImpXF aXF( rRoot ); |
| |
| // no used flags available in BIFF2 (always true) |
| aXF.SetAllUsedFlags( true ); |
| |
| // set the attributes |
| aXF.maProtection.FillFromXF2( nFlags1 ); |
| aXF.maAlignment.FillFromXF2( nFlags3 ); |
| aXF.maBorder.FillFromXF2( nFlags3 ); |
| aXF.maArea.FillFromXF2( nFlags3 ); |
| aXF.mnXclNumFmt = ::extract_value< sal_uInt16 >( nFlags2, 0, 6 ); |
| aXF.mnXclFont = ::extract_value< sal_uInt16 >( nFlags2, 6, 2 ); |
| |
| // write the attributes to the cell |
| aXF.ApplyPattern( rScPos.Col(), rScPos.Row(), rScPos.Col(), rScPos.Row(), rScPos.Tab() ); |
| } |
| |
| 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 )); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| 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 |
| //sal_uLong nForceScNumFmt = rXFIndex.IsBoolCell() ? GetNumFmtBuffer().GetStdScNumFmt() : NUMBERFORMAT_ENTRY_NOT_FOUND; |
| sal_uLong nForceScNumFmt = 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; |
| sal_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; |
| sal_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, |
| sal_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) |
| sal_uLong nPrevIndex = 0; |
| sal_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( sal_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, sal_uInt16 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() ); |
| } |
| } |
| } |
| |
| // ============================================================================ |
| |