1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xetable.cxx,v $
10 * $Revision: 1.18.126.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
33 #include "xestream.hxx"
34 #include "xlsx/xetable.hxx"
37 #include <com/sun/star/i18n/ScriptType.hpp>
38 #include "scitems.hxx"
39 #include <svtools/intitem.hxx>
40 #include "document.hxx"
41 #include "dociter.hxx"
42 #include "olinetab.hxx"
44 #include "patattr.hxx"
46 #include "xehelper.hxx"
47 #include "xecontent.hxx"
48 #include "xeescher.hxx"
50 #include <oox/core/tokens.hxx>
53 using ::rtl::OUString
;
54 using ::rtl::OUStringBuffer
;
56 namespace ApiScriptType
= ::com::sun::star::i18n::ScriptType
;
58 // ============================================================================
59 // Helper records for cell records
60 // ============================================================================
62 XclExpStringRec::XclExpStringRec( const XclExpRoot
& rRoot
, const String
& rResult
) :
63 XclExpRecord( EXC_ID3_STRING
),
64 mxResult( XclExpStringHelper::CreateString( rRoot
, rResult
) )
66 DBG_ASSERT( (rRoot
.GetBiff() <= EXC_BIFF5
) || (mxResult
->Len() > 0),
67 "XclExpStringRec::XclExpStringRec - empty result not allowed in BIFF8+" );
68 SetRecSize( mxResult
->GetSize() );
71 void XclExpStringRec::WriteBody( XclExpStream
& rStrm
)
76 // Additional records for special formula ranges ==============================
78 XclExpRangeFmlaBase::XclExpRangeFmlaBase(
79 sal_uInt16 nRecId
, sal_uInt32 nRecSize
, const ScAddress
& rScPos
) :
80 XclExpRecord( nRecId
, nRecSize
),
81 maXclRange( ScAddress::UNINITIALIZED
),
82 maBaseXclPos( ScAddress::UNINITIALIZED
)
84 maBaseXclPos
.Set( static_cast< sal_uInt16
>( rScPos
.Col() ), static_cast< sal_uInt32
>( rScPos
.Row() ) );
85 maXclRange
.maFirst
= maXclRange
.maLast
= maBaseXclPos
;
88 XclExpRangeFmlaBase::XclExpRangeFmlaBase(
89 sal_uInt16 nRecId
, sal_uInt32 nRecSize
, const ScRange
& rScRange
) :
90 XclExpRecord( nRecId
, nRecSize
),
91 maXclRange( ScAddress::UNINITIALIZED
),
92 maBaseXclPos( ScAddress::UNINITIALIZED
)
95 static_cast< sal_uInt16
>( rScRange
.aStart
.Col() ),
96 static_cast< sal_uInt32
>( rScRange
.aStart
.Row() ),
97 static_cast< sal_uInt16
>( rScRange
.aEnd
.Col() ),
98 static_cast< sal_uInt32
>( rScRange
.aEnd
.Row() ) );
99 maBaseXclPos
= maXclRange
.maFirst
;
102 bool XclExpRangeFmlaBase::IsBasePos( sal_uInt16 nXclCol
, sal_uInt32 nXclRow
) const
104 return (maBaseXclPos
.mnCol
== nXclCol
) && (maBaseXclPos
.mnRow
== nXclRow
);
107 void XclExpRangeFmlaBase::Extend( const ScAddress
& rScPos
)
109 sal_uInt16 nXclCol
= static_cast< sal_uInt16
>( rScPos
.Col() );
110 sal_uInt32 nXclRow
= static_cast< sal_uInt32
>( rScPos
.Row() );
111 maXclRange
.maFirst
.mnCol
= ::std::min( maXclRange
.maFirst
.mnCol
, nXclCol
);
112 maXclRange
.maFirst
.mnRow
= ::std::min( maXclRange
.maFirst
.mnRow
, nXclRow
);
113 maXclRange
.maLast
.mnCol
= ::std::max( maXclRange
.maLast
.mnCol
, nXclCol
);
114 maXclRange
.maLast
.mnRow
= ::std::max( maXclRange
.maLast
.mnRow
, nXclRow
);
117 void XclExpRangeFmlaBase::WriteRangeAddress( XclExpStream
& rStrm
) const
119 maXclRange
.Write( rStrm
, false );
122 // Array formulas =============================================================
124 XclExpArray::XclExpArray( XclTokenArrayRef xTokArr
, const ScRange
& rScRange
) :
125 XclExpRangeFmlaBase( EXC_ID3_ARRAY
, 14 + xTokArr
->GetSize(), rScRange
),
130 XclTokenArrayRef
XclExpArray::CreateCellTokenArray( const XclExpRoot
& rRoot
) const
132 return rRoot
.GetFormulaCompiler().CreateSpecialRefFormula( EXC_TOKID_EXP
, maBaseXclPos
);
135 bool XclExpArray::IsVolatile() const
137 return mxTokArr
->IsVolatile();
140 void XclExpArray::WriteBody( XclExpStream
& rStrm
)
142 WriteRangeAddress( rStrm
);
143 sal_uInt16 nFlags
= EXC_ARRAY_DEFAULTFLAGS
;
144 ::set_flag( nFlags
, EXC_ARRAY_RECALC_ALWAYS
, IsVolatile() );
145 rStrm
<< nFlags
<< sal_uInt32( 0 ) << *mxTokArr
;
148 // ----------------------------------------------------------------------------
150 XclExpArrayBuffer::XclExpArrayBuffer( const XclExpRoot
& rRoot
) :
155 XclExpArrayRef
XclExpArrayBuffer::CreateArray( const ScTokenArray
& rScTokArr
, const ScRange
& rScRange
)
157 const ScAddress
& rScPos
= rScRange
.aStart
;
158 XclTokenArrayRef xTokArr
= GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_MATRIX
, rScTokArr
, &rScPos
);
160 DBG_ASSERT( maRecMap
.find( rScPos
) == maRecMap
.end(), "XclExpArrayBuffer::CreateArray - array exists already" );
161 XclExpArrayRef
& rxRec
= maRecMap
[ rScPos
];
162 rxRec
.reset( new XclExpArray( xTokArr
, rScRange
) );
166 XclExpArrayRef
XclExpArrayBuffer::FindArray( const ScTokenArray
& rScTokArr
) const
169 // try to extract a matrix reference token
170 if( rScTokArr
.GetLen() == 1 )
172 const formula::FormulaToken
* pToken
= rScTokArr
.GetArray()[ 0 ];
173 if( pToken
&& (pToken
->GetOpCode() == ocMatRef
) )
175 const ScSingleRefData
& rRef
= static_cast<const ScToken
*>(pToken
)->GetSingleRef();
176 ScAddress
aBasePos( rRef
.nCol
, rRef
.nRow
, GetCurrScTab() );
177 XclExpArrayMap::const_iterator aIt
= maRecMap
.find( aBasePos
);
178 if( aIt
!= maRecMap
.end() )
185 // Shared formulas ============================================================
187 XclExpShrfmla::XclExpShrfmla( XclTokenArrayRef xTokArr
, const ScAddress
& rScPos
) :
188 XclExpRangeFmlaBase( EXC_ID_SHRFMLA
, 10 + xTokArr
->GetSize(), rScPos
),
194 void XclExpShrfmla::ExtendRange( const ScAddress
& rScPos
)
200 XclTokenArrayRef
XclExpShrfmla::CreateCellTokenArray( const XclExpRoot
& rRoot
) const
202 return rRoot
.GetFormulaCompiler().CreateSpecialRefFormula( EXC_TOKID_EXP
, maBaseXclPos
);
205 bool XclExpShrfmla::IsVolatile() const
207 return mxTokArr
->IsVolatile();
210 void XclExpShrfmla::WriteBody( XclExpStream
& rStrm
)
212 WriteRangeAddress( rStrm
);
213 rStrm
<< sal_uInt8( 0 ) << mnUsedCount
<< *mxTokArr
;
216 // ----------------------------------------------------------------------------
218 XclExpShrfmlaBuffer::XclExpShrfmlaBuffer( const XclExpRoot
& rRoot
) :
223 XclExpShrfmlaRef
XclExpShrfmlaBuffer::CreateOrExtendShrfmla(
224 const ScTokenArray
& rScTokArr
, const ScAddress
& rScPos
)
226 XclExpShrfmlaRef xRec
;
227 if( const ScTokenArray
* pShrdScTokArr
= XclTokenArrayHelper::GetSharedFormula( GetRoot(), rScTokArr
) )
229 XclExpShrfmlaMap::iterator aIt
= maRecMap
.find( pShrdScTokArr
);
230 if( aIt
== maRecMap
.end() )
232 // create a new record
233 XclTokenArrayRef xTokArr
= GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_SHARED
, *pShrdScTokArr
, &rScPos
);
234 xRec
.reset( new XclExpShrfmla( xTokArr
, rScPos
) );
235 maRecMap
[ pShrdScTokArr
] = xRec
;
239 // extend existing record
240 DBG_ASSERT( aIt
->second
, "XclExpShrfmlaBuffer::CreateOrExtendShrfmla - missing record" );
242 xRec
->ExtendRange( rScPos
);
248 // Multiple operations ========================================================
250 XclExpTableop::XclExpTableop( const ScAddress
& rScPos
,
251 const XclMultipleOpRefs
& rRefs
, sal_uInt8 nScMode
) :
252 XclExpRangeFmlaBase( EXC_ID3_TABLEOP
, 16, rScPos
),
253 mnLastAppXclCol( static_cast< sal_uInt16
>( rScPos
.Col() ) ),
254 mnColInpXclCol( static_cast< sal_uInt16
>( rRefs
.maColFirstScPos
.Col() ) ),
255 mnColInpXclRow( static_cast< sal_uInt32
>( rRefs
.maColFirstScPos
.Row() ) ),
256 mnRowInpXclCol( static_cast< sal_uInt16
>( rRefs
.maRowFirstScPos
.Col() ) ),
257 mnRowInpXclRow( static_cast< sal_uInt32
>( rRefs
.maRowFirstScPos
.Row() ) ),
263 bool XclExpTableop::TryExtend( const ScAddress
& rScPos
, const XclMultipleOpRefs
& rRefs
)
265 sal_uInt16 nXclCol
= static_cast< sal_uInt16
>( rScPos
.Col() );
266 sal_uInt32 nXclRow
= static_cast< sal_uInt32
>( rScPos
.Row() );
268 bool bOk
= IsAppendable( nXclCol
, nXclRow
);
271 SCCOL nFirstScCol
= static_cast< SCCOL
>( maXclRange
.maFirst
.mnCol
);
272 SCROW nFirstScRow
= static_cast< SCROW
>( maXclRange
.maFirst
.mnRow
);
273 SCCOL nColInpScCol
= static_cast< SCCOL
>( mnColInpXclCol
);
274 SCROW nColInpScRow
= static_cast< SCROW
>( mnColInpXclRow
);
275 SCCOL nRowInpScCol
= static_cast< SCCOL
>( mnRowInpXclCol
);
276 SCROW nRowInpScRow
= static_cast< SCROW
>( mnRowInpXclRow
);
278 bOk
= ((mnScMode
== 2) == rRefs
.mbDblRefMode
) &&
279 (rScPos
.Tab() == rRefs
.maFmlaScPos
.Tab()) &&
280 (nColInpScCol
== rRefs
.maColFirstScPos
.Col()) &&
281 (nColInpScRow
== rRefs
.maColFirstScPos
.Row()) &&
282 (rScPos
.Tab() == rRefs
.maColFirstScPos
.Tab()) &&
283 (rScPos
.Tab() == rRefs
.maColRelScPos
.Tab());
285 if( bOk
) switch( mnScMode
)
288 bOk
= (rScPos
.Col() == rRefs
.maFmlaScPos
.Col()) &&
289 (nFirstScRow
== rRefs
.maFmlaScPos
.Row() + 1) &&
290 (nFirstScCol
== rRefs
.maColRelScPos
.Col() + 1) &&
291 (rScPos
.Row() == rRefs
.maColRelScPos
.Row());
294 bOk
= (nFirstScCol
== rRefs
.maFmlaScPos
.Col() + 1) &&
295 (rScPos
.Row() == rRefs
.maFmlaScPos
.Row()) &&
296 (rScPos
.Col() == rRefs
.maColRelScPos
.Col()) &&
297 (nFirstScRow
== rRefs
.maColRelScPos
.Row() + 1);
300 bOk
= (nFirstScCol
== rRefs
.maFmlaScPos
.Col() + 1) &&
301 (nFirstScRow
== rRefs
.maFmlaScPos
.Row() + 1) &&
302 (nFirstScCol
== rRefs
.maColRelScPos
.Col() + 1) &&
303 (rScPos
.Row() == rRefs
.maColRelScPos
.Row()) &&
304 (nRowInpScCol
== rRefs
.maRowFirstScPos
.Col()) &&
305 (nRowInpScRow
== rRefs
.maRowFirstScPos
.Row()) &&
306 (rScPos
.Tab() == rRefs
.maRowFirstScPos
.Tab()) &&
307 (rScPos
.Col() == rRefs
.maRowRelScPos
.Col()) &&
308 (nFirstScRow
== rRefs
.maRowRelScPos
.Row() + 1) &&
309 (rScPos
.Tab() == rRefs
.maRowRelScPos
.Tab());
317 // extend the cell range
318 DBG_ASSERT( IsAppendable( nXclCol
, nXclRow
), "XclExpTableop::TryExtend - wrong cell address" );
320 mnLastAppXclCol
= nXclCol
;
327 void XclExpTableop::Finalize()
329 // is the range complete? (last appended cell is in last column)
330 mbValid
= maXclRange
.maLast
.mnCol
== mnLastAppXclCol
;
331 // if last row is incomplete, try to shorten the used range
332 if( !mbValid
&& (maXclRange
.maFirst
.mnRow
< maXclRange
.maLast
.mnRow
) )
334 --maXclRange
.maLast
.mnRow
;
338 // check if referred cells are outside of own range
339 if( mbValid
) switch( mnScMode
)
342 mbValid
= (mnColInpXclCol
+ 1 < maXclRange
.maFirst
.mnCol
) || (mnColInpXclCol
> maXclRange
.maLast
.mnCol
) ||
343 (mnColInpXclRow
< maXclRange
.maFirst
.mnRow
) || (mnColInpXclRow
> maXclRange
.maLast
.mnRow
);
346 mbValid
= (mnColInpXclCol
< maXclRange
.maFirst
.mnCol
) || (mnColInpXclCol
> maXclRange
.maLast
.mnCol
) ||
347 (mnColInpXclRow
+ 1 < maXclRange
.maFirst
.mnRow
) || (mnColInpXclRow
> maXclRange
.maLast
.mnRow
);
350 mbValid
= ((mnColInpXclCol
+ 1 < maXclRange
.maFirst
.mnCol
) || (mnColInpXclCol
> maXclRange
.maLast
.mnCol
) ||
351 (mnColInpXclRow
+ 1 < maXclRange
.maFirst
.mnRow
) || (mnColInpXclRow
> maXclRange
.maLast
.mnRow
)) &&
352 ((mnRowInpXclCol
+ 1 < maXclRange
.maFirst
.mnCol
) || (mnRowInpXclCol
> maXclRange
.maLast
.mnCol
) ||
353 (mnRowInpXclRow
+ 1 < maXclRange
.maFirst
.mnRow
) || (mnRowInpXclRow
> maXclRange
.maLast
.mnRow
));
358 XclTokenArrayRef
XclExpTableop::CreateCellTokenArray( const XclExpRoot
& rRoot
) const
360 XclExpFormulaCompiler
& rFmlaComp
= rRoot
.GetFormulaCompiler();
362 rFmlaComp
.CreateSpecialRefFormula( EXC_TOKID_TBL
, maBaseXclPos
) :
363 rFmlaComp
.CreateErrorFormula( EXC_ERR_NA
);
366 bool XclExpTableop::IsVolatile() const
371 void XclExpTableop::Save( XclExpStream
& rStrm
)
374 XclExpRangeFmlaBase::Save( rStrm
);
377 bool XclExpTableop::IsAppendable( sal_uInt16 nXclCol
, sal_uInt32 nXclRow
) const
379 return ((nXclCol
== mnLastAppXclCol
+ 1) && (nXclRow
== maXclRange
.maFirst
.mnRow
)) ||
380 ((nXclCol
== mnLastAppXclCol
+ 1) && (nXclCol
<= maXclRange
.maLast
.mnCol
) && (nXclRow
== maXclRange
.maLast
.mnRow
)) ||
381 ((mnLastAppXclCol
== maXclRange
.maLast
.mnCol
) && (nXclCol
== maXclRange
.maFirst
.mnCol
) && (nXclRow
== maXclRange
.maLast
.mnRow
+ 1));
384 void XclExpTableop::WriteBody( XclExpStream
& rStrm
)
386 sal_uInt16 nFlags
= EXC_TABLEOP_DEFAULTFLAGS
;
387 ::set_flag( nFlags
, EXC_TABLEOP_RECALC_ALWAYS
, IsVolatile() );
390 case 1: ::set_flag( nFlags
, EXC_TABLEOP_ROW
); break;
391 case 2: ::set_flag( nFlags
, EXC_TABLEOP_BOTH
); break;
394 WriteRangeAddress( rStrm
);
397 rStrm
<< mnRowInpXclRow
<< mnRowInpXclCol
<< mnColInpXclRow
<< mnColInpXclCol
;
399 rStrm
<< mnColInpXclRow
<< mnColInpXclCol
<< sal_uInt32( 0 );
402 // ----------------------------------------------------------------------------
404 XclExpTableopBuffer::XclExpTableopBuffer( const XclExpRoot
& rRoot
) :
409 XclExpTableopRef
XclExpTableopBuffer::CreateOrExtendTableop(
410 const ScTokenArray
& rScTokArr
, const ScAddress
& rScPos
)
412 XclExpTableopRef xRec
;
414 // try to extract cell references of a multiple operations formula
415 XclMultipleOpRefs aRefs
;
416 if( XclTokenArrayHelper::GetMultipleOpRefs( aRefs
, rScTokArr
) )
418 // try to find an existing TABLEOP record for this cell position
419 for( size_t nPos
= 0, nSize
= maTableopList
.GetSize(); !xRec
&& (nPos
< nSize
); ++nPos
)
421 XclExpTableopRef xTempRec
= maTableopList
.GetRecord( nPos
);
422 if( xTempRec
->TryExtend( rScPos
, aRefs
) )
426 // no record found, or found record not extensible
428 xRec
= TryCreate( rScPos
, aRefs
);
434 void XclExpTableopBuffer::Finalize()
436 for( size_t nPos
= 0, nSize
= maTableopList
.GetSize(); nPos
< nSize
; ++nPos
)
437 maTableopList
.GetRecord( nPos
)->Finalize();
440 XclExpTableopRef
XclExpTableopBuffer::TryCreate( const ScAddress
& rScPos
, const XclMultipleOpRefs
& rRefs
)
442 sal_uInt8 nScMode
= 0;
443 bool bOk
= (rScPos
.Tab() == rRefs
.maFmlaScPos
.Tab()) &&
444 (rScPos
.Tab() == rRefs
.maColFirstScPos
.Tab()) &&
445 (rScPos
.Tab() == rRefs
.maColRelScPos
.Tab());
449 if( rRefs
.mbDblRefMode
)
452 bOk
= (rScPos
.Col() == rRefs
.maFmlaScPos
.Col() + 1) &&
453 (rScPos
.Row() == rRefs
.maFmlaScPos
.Row() + 1) &&
454 (rScPos
.Col() == rRefs
.maColRelScPos
.Col() + 1) &&
455 (rScPos
.Row() == rRefs
.maColRelScPos
.Row()) &&
456 (rScPos
.Tab() == rRefs
.maRowFirstScPos
.Tab()) &&
457 (rScPos
.Col() == rRefs
.maRowRelScPos
.Col()) &&
458 (rScPos
.Row() == rRefs
.maRowRelScPos
.Row() + 1) &&
459 (rScPos
.Tab() == rRefs
.maRowRelScPos
.Tab());
461 else if( (rScPos
.Col() == rRefs
.maFmlaScPos
.Col()) &&
462 (rScPos
.Row() == rRefs
.maFmlaScPos
.Row() + 1) &&
463 (rScPos
.Col() == rRefs
.maColRelScPos
.Col() + 1) &&
464 (rScPos
.Row() == rRefs
.maColRelScPos
.Row()) )
468 else if( (rScPos
.Col() == rRefs
.maFmlaScPos
.Col() + 1) &&
469 (rScPos
.Row() == rRefs
.maFmlaScPos
.Row()) &&
470 (rScPos
.Col() == rRefs
.maColRelScPos
.Col()) &&
471 (rScPos
.Row() == rRefs
.maColRelScPos
.Row() + 1) )
481 XclExpTableopRef xRec
;
484 xRec
.reset( new XclExpTableop( rScPos
, rRefs
, nScMode
) );
485 maTableopList
.AppendRecord( xRec
);
491 // ============================================================================
493 // ============================================================================
495 XclExpCellBase::XclExpCellBase(
496 sal_uInt16 nRecId
, sal_Size nContSize
, const XclAddress
& rXclPos
) :
497 XclExpRecord( nRecId
, nContSize
+ 4 ),
502 bool XclExpCellBase::IsMultiLineText() const
507 bool XclExpCellBase::TryMerge( const XclExpCellBase
& /*rCell*/ )
512 void XclExpCellBase::GetBlankXFIndexes( ScfUInt16Vec
& /*rXFIndexes*/ ) const
514 // default: do nothing
517 void XclExpCellBase::RemoveUnusedBlankCells( const ScfUInt16Vec
& /*rXFIndexes*/ )
519 // default: do nothing
522 // Single cell records ========================================================
524 XclExpSingleCellBase::XclExpSingleCellBase(
525 sal_uInt16 nRecId
, sal_Size nContSize
, const XclAddress
& rXclPos
, sal_uInt32 nXFId
) :
526 XclExpCellBase( nRecId
, 2, rXclPos
),
528 mnContSize( nContSize
)
532 XclExpSingleCellBase::XclExpSingleCellBase( const XclExpRoot
& rRoot
,
533 sal_uInt16 nRecId
, sal_Size nContSize
, const XclAddress
& rXclPos
,
534 const ScPatternAttr
* pPattern
, sal_Int16 nScript
, sal_uInt32 nForcedXFId
) :
535 XclExpCellBase( nRecId
, 2, rXclPos
),
536 maXFId( nForcedXFId
),
537 mnContSize( nContSize
)
539 if( GetXFId() == EXC_XFID_NOTFOUND
)
540 SetXFId( rRoot
.GetXFBuffer().Insert( pPattern
, nScript
) );
543 sal_uInt16
XclExpSingleCellBase::GetLastXclCol() const
548 sal_uInt32
XclExpSingleCellBase::GetFirstXFId() const
553 bool XclExpSingleCellBase::IsEmpty() const
558 void XclExpSingleCellBase::ConvertXFIndexes( const XclExpRoot
& rRoot
)
560 maXFId
.ConvertXFIndex( rRoot
);
563 void XclExpSingleCellBase::Save( XclExpStream
& rStrm
)
565 DBG_ASSERT_BIFF( rStrm
.GetRoot().GetBiff() >= EXC_BIFF3
);
566 AddRecSize( mnContSize
);
567 XclExpCellBase::Save( rStrm
);
570 void XclExpSingleCellBase::WriteBody( XclExpStream
& rStrm
)
572 rStrm
<< GetXclRow() << GetXclCol() << maXFId
.mnXFIndex
;
573 WriteContents( rStrm
);
576 // ----------------------------------------------------------------------------
578 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpNumberCell
, 256, 256 )
580 XclExpNumberCell::XclExpNumberCell(
581 const XclExpRoot
& rRoot
, const XclAddress
& rXclPos
,
582 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
, double fValue
) :
583 // #i41210# always use latin script for number cells - may look wrong for special number formats...
584 XclExpSingleCellBase( rRoot
, EXC_ID3_NUMBER
, 8, rXclPos
, pPattern
, ApiScriptType::LATIN
, nForcedXFId
),
589 static OString
lcl_GetStyleId( XclExpXmlStream
& rStrm
, sal_uInt32 nXFIndex
)
591 return OString::valueOf( rStrm
.GetRoot().GetXFBuffer()
592 .GetXmlCellIndex( nXFIndex
) );
595 static OString
lcl_GetStyleId( XclExpXmlStream
& rStrm
, const XclExpCellBase
& rCell
)
597 sal_uInt32 nXFId
= rCell
.GetFirstXFId();
598 sal_uInt16 nXFIndex
= rStrm
.GetRoot().GetXFBuffer().GetXFIndex( nXFId
);
599 return lcl_GetStyleId( rStrm
, nXFIndex
);
602 void XclExpNumberCell::SaveXml( XclExpXmlStream
& rStrm
)
604 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
605 rWorksheet
->startElement( XML_c
,
606 XML_r
, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
607 XML_s
, lcl_GetStyleId( rStrm
, *this ).getStr(),
609 // OOXTODO: XML_cm, XML_vm, XML_ph
611 rWorksheet
->startElement( XML_v
, FSEND
);
612 rWorksheet
->write( mfValue
);
613 rWorksheet
->endElement( XML_v
);
614 rWorksheet
->endElement( XML_c
);
617 void XclExpNumberCell::WriteContents( XclExpStream
& rStrm
)
622 // ----------------------------------------------------------------------------
624 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpBooleanCell
, 256, 256 )
626 XclExpBooleanCell::XclExpBooleanCell(
627 const XclExpRoot rRoot
, const XclAddress
& rXclPos
,
628 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
, bool bValue
) :
629 // #i41210# always use latin script for boolean cells
630 XclExpSingleCellBase( rRoot
, EXC_ID3_BOOLERR
, 2, rXclPos
, pPattern
, ApiScriptType::LATIN
, nForcedXFId
),
635 void XclExpBooleanCell::SaveXml( XclExpXmlStream
& rStrm
)
637 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
638 rWorksheet
->startElement( XML_c
,
639 XML_r
, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
640 XML_s
, lcl_GetStyleId( rStrm
, *this ).getStr(),
642 // OOXTODO: XML_cm, XML_vm, XML_ph
644 rWorksheet
->startElement( XML_v
, FSEND
);
645 rWorksheet
->write( mbValue
? "1" : "0" );
646 rWorksheet
->endElement( XML_v
);
647 rWorksheet
->endElement( XML_c
);
650 void XclExpBooleanCell::WriteContents( XclExpStream
& rStrm
)
652 rStrm
<< sal_uInt16( mbValue
? 1 : 0 ) << EXC_BOOLERR_BOOL
;
655 // ----------------------------------------------------------------------------
657 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpErrorCell
, 256, 256 )
659 XclExpErrorCell::XclExpErrorCell(
660 const XclExpRoot rRoot
, const XclAddress
& rXclPos
,
661 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
, sal_uInt8 nErrCode
) :
662 // #i41210# always use latin script for error cells
663 XclExpSingleCellBase( rRoot
, EXC_ID3_BOOLERR
, 2, rXclPos
, pPattern
, ApiScriptType::LATIN
, nForcedXFId
),
664 mnErrCode( nErrCode
)
668 void XclExpErrorCell::SaveXml( XclExpXmlStream
& rStrm
)
670 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
671 rWorksheet
->startElement( XML_c
,
672 XML_r
, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
673 XML_s
, lcl_GetStyleId( rStrm
, *this ).getStr(),
675 // OOXTODO: XML_cm, XML_vm, XML_ph
677 rWorksheet
->startElement( XML_v
, FSEND
);
678 rWorksheet
->write( (sal_Int32
) mnErrCode
);
679 rWorksheet
->endElement( XML_v
);
680 rWorksheet
->endElement( XML_c
);
683 void XclExpErrorCell::WriteContents( XclExpStream
& rStrm
)
685 rStrm
<< mnErrCode
<< EXC_BOOLERR_ERROR
;
688 // ----------------------------------------------------------------------------
690 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpLabelCell
, 256, 256 )
692 XclExpLabelCell::XclExpLabelCell(
693 const XclExpRoot
& rRoot
, const XclAddress
& rXclPos
,
694 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
, const ScStringCell
& rCell
) :
695 XclExpSingleCellBase( EXC_ID3_LABEL
, 0, rXclPos
, nForcedXFId
)
697 sal_uInt16 nMaxLen
= (rRoot
.GetBiff() == EXC_BIFF8
) ? EXC_STR_MAXLEN
: EXC_LABEL_MAXLEN
;
698 XclExpStringRef xText
= XclExpStringHelper::CreateCellString( rRoot
, rCell
, pPattern
, EXC_STR_DEFAULT
, nMaxLen
);
699 Init( rRoot
, pPattern
, xText
);
702 XclExpLabelCell::XclExpLabelCell(
703 const XclExpRoot
& rRoot
, const XclAddress
& rXclPos
,
704 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
,
705 const ScEditCell
& rCell
, XclExpHyperlinkHelper
& rLinkHelper
) :
706 XclExpSingleCellBase( EXC_ID3_LABEL
, 0, rXclPos
, nForcedXFId
)
708 sal_uInt16 nMaxLen
= (rRoot
.GetBiff() == EXC_BIFF8
) ? EXC_STR_MAXLEN
: EXC_LABEL_MAXLEN
;
709 XclExpStringRef xText
= XclExpStringHelper::CreateCellString( rRoot
, rCell
, pPattern
, rLinkHelper
, EXC_STR_DEFAULT
, nMaxLen
);
710 Init( rRoot
, pPattern
, xText
);
713 bool XclExpLabelCell::IsMultiLineText() const
715 return mbLineBreak
|| mxText
->IsWrapped();
718 void XclExpLabelCell::Init( const XclExpRoot
& rRoot
,
719 const ScPatternAttr
* pPattern
, XclExpStringRef xText
)
721 DBG_ASSERT( xText
.is() && xText
->Len(), "XclExpLabelCell::XclExpLabelCell - empty string passed" );
725 // create the cell format
726 sal_uInt16 nXclFont
= mxText
->RemoveLeadingFont();
727 if( GetXFId() == EXC_XFID_NOTFOUND
)
729 DBG_ASSERT( nXclFont
!= EXC_FONT_NOTFOUND
, "XclExpLabelCell::Init - leading font not found" );
730 bool bForceLineBreak
= mxText
->IsWrapped();
731 SetXFId( rRoot
.GetXFBuffer().InsertWithFont( pPattern
, ApiScriptType::WEAK
, nXclFont
, bForceLineBreak
) );
734 // get auto-wrap attribute from cell format
735 const XclExpXF
* pXF
= rRoot
.GetXFBuffer().GetXFById( GetXFId() );
736 mbLineBreak
= pXF
&& pXF
->GetAlignmentData().mbLineBreak
;
738 // initialize the record contents
739 switch( rRoot
.GetBiff() )
742 // BIFF5-BIFF7: create a LABEL or RSTRING record
743 DBG_ASSERT( mxText
->Len() <= EXC_LABEL_MAXLEN
, "XclExpLabelCell::XclExpLabelCell - string too long" );
744 SetContSize( mxText
->GetSize() );
745 // formatted string is exported in an RSTRING record
746 if( mxText
->IsRich() )
748 DBG_ASSERT( mxText
->GetFormatsCount() <= EXC_LABEL_MAXLEN
, "XclExpLabelCell::WriteContents - too many formats" );
749 mxText
->LimitFormatCount( EXC_LABEL_MAXLEN
);
750 SetRecId( EXC_ID_RSTRING
);
751 SetContSize( GetContSize() + 1 + 2 * mxText
->GetFormatsCount() );
755 // BIFF8+: create a LABELSST record
756 mnSstIndex
= rRoot
.GetSst().Insert( xText
);
757 SetRecId( EXC_ID_LABELSST
);
760 default: DBG_ERROR_BIFF();
764 void XclExpLabelCell::SaveXml( XclExpXmlStream
& rStrm
)
766 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
767 rWorksheet
->startElement( XML_c
,
768 XML_r
, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
769 XML_s
, lcl_GetStyleId( rStrm
, *this ).getStr(),
771 // OOXTODO: XML_cm, XML_vm, XML_ph
773 rWorksheet
->startElement( XML_v
, FSEND
);
774 rWorksheet
->write( (sal_Int32
) mnSstIndex
);
775 rWorksheet
->endElement( XML_v
);
776 rWorksheet
->endElement( XML_c
);
779 void XclExpLabelCell::WriteContents( XclExpStream
& rStrm
)
781 switch( rStrm
.GetRoot().GetBiff() )
785 if( mxText
->IsRich() )
787 rStrm
<< static_cast< sal_uInt8
>( mxText
->GetFormatsCount() );
788 mxText
->WriteFormats( rStrm
);
794 default: DBG_ERROR_BIFF();
798 // ----------------------------------------------------------------------------
800 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpFormulaCell
, 256, 256 )
802 XclExpFormulaCell::XclExpFormulaCell(
803 const XclExpRoot
& rRoot
, const XclAddress
& rXclPos
,
804 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
,
805 const ScFormulaCell
& rScFmlaCell
,
806 XclExpArrayBuffer
& rArrayBfr
,
807 XclExpShrfmlaBuffer
& rShrfmlaBfr
,
808 XclExpTableopBuffer
& rTableopBfr
) :
809 XclExpSingleCellBase( EXC_ID2_FORMULA
, 0, rXclPos
, nForcedXFId
),
810 mrScFmlaCell( const_cast< ScFormulaCell
& >( rScFmlaCell
) )
812 // *** Find result number format overwriting cell number format *** -------
814 if( GetXFId() == EXC_XFID_NOTFOUND
)
816 SvNumberFormatter
& rFormatter
= rRoot
.GetFormatter();
817 XclExpNumFmtBuffer
& rNumFmtBfr
= rRoot
.GetNumFmtBuffer();
819 // current cell number format
820 ULONG nScNumFmt
= pPattern
?
821 GETITEMVALUE( pPattern
->GetItemSet(), SfxUInt32Item
, ATTR_VALUE_FORMAT
, ULONG
) :
822 rNumFmtBfr
.GetStandardFormat();
824 // alternative number format passed to XF buffer
825 ULONG nAltScNumFmt
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
826 /* #73420# Xcl doesn't know Boolean number formats, we write
827 "TRUE";"FALSE" (language dependent). Don't do it for automatic
828 formula formats, because Excel gets them right. */
829 /* #i8640# Don't set text format, if we have string results. */
830 short nFormatType
= mrScFmlaCell
.GetFormatType();
831 if( ((nScNumFmt
% SV_COUNTRY_LANGUAGE_OFFSET
) == 0) &&
832 (nFormatType
!= NUMBERFORMAT_LOGICAL
) &&
833 (nFormatType
!= NUMBERFORMAT_TEXT
) )
834 nAltScNumFmt
= mrScFmlaCell
.GetStandardFormat( rFormatter
, nScNumFmt
);
835 /* #73420# If cell number format is Boolean and automatic formula
836 format is Boolean don't write that ugly special format. */
837 else if( (nFormatType
== NUMBERFORMAT_LOGICAL
) &&
838 (rFormatter
.GetType( nScNumFmt
) == NUMBERFORMAT_LOGICAL
) )
839 nAltScNumFmt
= rNumFmtBfr
.GetStandardFormat();
841 // #i41420# find script type according to result type (always latin for numeric results)
842 sal_Int16 nScript
= ApiScriptType::LATIN
;
843 bool bForceLineBreak
= false;
844 if( nFormatType
== NUMBERFORMAT_TEXT
)
847 mrScFmlaCell
.GetString( aResult
);
848 bForceLineBreak
= mrScFmlaCell
.IsMultilineResult();
849 nScript
= XclExpStringHelper::GetLeadingScriptType( rRoot
, aResult
);
851 SetXFId( rRoot
.GetXFBuffer().InsertWithNumFmt( pPattern
, nScript
, nAltScNumFmt
, bForceLineBreak
) );
854 // *** Convert the formula token array *** --------------------------------
856 ScAddress
aScPos( static_cast< SCCOL
>( rXclPos
.mnCol
), static_cast< SCROW
>( rXclPos
.mnRow
), rRoot
.GetCurrScTab() );
857 const ScTokenArray
& rScTokArr
= *mrScFmlaCell
.GetCode();
859 // first try to create multiple operations
860 mxAddRec
= rTableopBfr
.CreateOrExtendTableop( rScTokArr
, aScPos
);
862 // no multiple operation found - try to create matrix formula
863 if( !mxAddRec
) switch( static_cast< ScMatrixMode
>( mrScFmlaCell
.GetMatrixFlag() ) )
867 // origin of the matrix - find the used matrix range
870 mrScFmlaCell
.GetMatColsRows( nMatWidth
, nMatHeight
);
871 DBG_ASSERT( nMatWidth
&& nMatHeight
, "XclExpFormulaCell::XclExpFormulaCell - empty matrix" );
872 ScRange
aMatScRange( aScPos
);
873 ScAddress
& rMatEnd
= aMatScRange
.aEnd
;
874 rMatEnd
.IncCol( static_cast< SCsCOL
>( nMatWidth
- 1 ) );
875 rMatEnd
.IncRow( static_cast< SCsROW
>( nMatHeight
- 1 ) );
876 // reduce to valid range (range keeps valid, because start position IS valid)
877 rRoot
.GetAddressConverter().ValidateRange( aMatScRange
, true );
878 // create the ARRAY record
879 mxAddRec
= rArrayBfr
.CreateArray( rScTokArr
, aMatScRange
);
884 // other formula cell covered by a matrix - find the ARRAY record
885 mxAddRec
= rArrayBfr
.FindArray( rScTokArr
);
886 // should always be found, if Calc document is not broken
887 DBG_ASSERT( mxAddRec
.is(), "XclExpFormulaCell::XclExpFormulaCell - no matrix found" );
893 // no matrix found - try to create shared formula
895 mxAddRec
= rShrfmlaBfr
.CreateOrExtendShrfmla( rScTokArr
, aScPos
);
897 // no shared formula found - create a simple cell formula
898 if( !mxAddRec
|| ! mxTokArr
)
899 mxTokArr
= rRoot
.GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CELL
, rScTokArr
, &aScPos
);
902 void XclExpFormulaCell::Save( XclExpStream
& rStrm
)
904 // create token array for FORMULA cells with additional record
906 mxTokArr
= mxAddRec
->CreateCellTokenArray( rStrm
.GetRoot() );
908 // FORMULA record itself
909 DBG_ASSERT( mxTokArr
.is(), "XclExpFormulaCell::Save - missing token array" );
911 mxTokArr
= rStrm
.GetRoot().GetFormulaCompiler().CreateErrorFormula( EXC_ERR_NA
);
912 SetContSize( 16 + mxTokArr
->GetSize() );
913 XclExpSingleCellBase::Save( rStrm
);
915 // additional record (ARRAY, SHRFMLA, or TABLEOP), only for first FORMULA record
916 if( mxAddRec
.is() && mxAddRec
->IsBasePos( GetXclCol(), GetXclRow() ) )
917 mxAddRec
->Save( rStrm
);
919 // STRING record for string result
920 if( mxStringRec
.is() )
921 mxStringRec
->Save( rStrm
);
924 void XclExpFormulaCell::SaveXml( XclExpXmlStream
& rStrm
)
926 const char* sType
= NULL
;
929 XclXmlUtils::GetFormulaTypeAndValue( mrScFmlaCell
, sType
, sValue
);
930 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
931 rWorksheet
->startElement( XML_c
,
932 XML_r
, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
933 XML_s
, lcl_GetStyleId( rStrm
, *this ).getStr(),
935 // OOXTODO: XML_cm, XML_vm, XML_ph
938 rWorksheet
->startElement( XML_f
,
939 // OOXTODO: XML_t, ST_CellFormulaType
940 XML_aca
, XclXmlUtils::ToPsz( mxTokArr
->IsVolatile() || (mxAddRec
.is() && mxAddRec
->IsVolatile()) ),
941 // OOXTODO: XML_ref, ST_Ref
942 // OOXTODO: XML_dt2D, bool
943 // OOXTODO: XML_dtr, bool
944 // OOXTODO: XML_del1, bool
945 // OOXTODO: XML_del2, bool
946 // OOXTODO: XML_r1, ST_CellRef
947 // OOXTODO: XML_r2, ST_CellRef
948 // OOXTODO: XML_ca, bool
949 // OOXTODO: XML_si, uint
950 // OOXTODO: XML_bx bool
952 rWorksheet
->writeEscaped( XclXmlUtils::ToOUString( *mrScFmlaCell
.GetDocument(), mrScFmlaCell
.aPos
, mrScFmlaCell
.GetCode() ) );
953 rWorksheet
->endElement( XML_f
);
954 if( strcmp( sType
, "inlineStr" ) == 0 )
956 rWorksheet
->startElement( XML_is
, FSEND
);
957 rWorksheet
->startElement( XML_t
, FSEND
);
958 rWorksheet
->writeEscaped( sValue
);
959 rWorksheet
->endElement( XML_t
);
960 rWorksheet
->endElement( XML_is
);
964 rWorksheet
->startElement( XML_v
, FSEND
);
965 rWorksheet
->writeEscaped( sValue
);
966 rWorksheet
->endElement( XML_v
);
968 rWorksheet
->endElement( XML_c
);
971 void XclExpFormulaCell::WriteContents( XclExpStream
& rStrm
)
973 // result of the formula
974 switch( mrScFmlaCell
.GetFormatType() )
976 case NUMBERFORMAT_NUMBER
:
978 // either value or error code
979 USHORT nScErrCode
= mrScFmlaCell
.GetErrCode();
981 rStrm
<< EXC_FORMULA_RES_ERROR
<< sal_uInt8( 0 )
982 << XclTools::GetXclErrorCode( nScErrCode
)
983 << sal_uInt8( 0 ) << sal_uInt16( 0 )
984 << sal_uInt16( 0xFFFF );
986 rStrm
<< mrScFmlaCell
.GetValue();
990 case NUMBERFORMAT_TEXT
:
993 mrScFmlaCell
.GetString( aResult
);
994 if( aResult
.Len() || (rStrm
.GetRoot().GetBiff() <= EXC_BIFF5
) )
996 rStrm
<< EXC_FORMULA_RES_STRING
;
997 mxStringRec
.reset( new XclExpStringRec( rStrm
.GetRoot(), aResult
) );
1000 rStrm
<< EXC_FORMULA_RES_EMPTY
; // BIFF8 only
1001 rStrm
<< sal_uInt8( 0 ) << sal_uInt32( 0 ) << sal_uInt16( 0xFFFF );
1005 case NUMBERFORMAT_LOGICAL
:
1007 sal_uInt8 nXclValue
= (mrScFmlaCell
.GetValue() == 0.0) ? 0 : 1;
1008 rStrm
<< EXC_FORMULA_RES_BOOL
<< sal_uInt8( 0 )
1009 << nXclValue
<< sal_uInt8( 0 ) << sal_uInt16( 0 )
1010 << sal_uInt16( 0xFFFF );
1015 rStrm
<< mrScFmlaCell
.GetValue();
1018 // flags and formula token array
1019 sal_uInt16 nFlags
= EXC_FORMULA_DEFAULTFLAGS
;
1020 ::set_flag( nFlags
, EXC_FORMULA_RECALC_ALWAYS
, mxTokArr
->IsVolatile() || (mxAddRec
.is() && mxAddRec
->IsVolatile()) );
1021 ::set_flag( nFlags
, EXC_FORMULA_SHARED
, mxAddRec
.is() && (mxAddRec
->GetRecId() == EXC_ID_SHRFMLA
) );
1022 rStrm
<< nFlags
<< sal_uInt32( 0 ) << *mxTokArr
;
1025 // Multiple cell records ======================================================
1027 XclExpMultiCellBase::XclExpMultiCellBase(
1028 sal_uInt16 nRecId
, sal_uInt16 nMulRecId
, sal_Size nContSize
, const XclAddress
& rXclPos
) :
1029 XclExpCellBase( nRecId
, 0, rXclPos
),
1030 mnMulRecId( nMulRecId
),
1031 mnContSize( nContSize
)
1035 sal_uInt16
XclExpMultiCellBase::GetLastXclCol() const
1037 return GetXclCol() + GetCellCount() - 1;
1040 sal_uInt32
XclExpMultiCellBase::GetFirstXFId() const
1042 return maXFIds
.empty() ? XclExpXFBuffer::GetDefCellXFId() : maXFIds
.front().mnXFId
;
1045 bool XclExpMultiCellBase::IsEmpty() const
1047 return maXFIds
.empty();
1050 void XclExpMultiCellBase::ConvertXFIndexes( const XclExpRoot
& rRoot
)
1052 for( XclExpMultiXFIdDeq::iterator aIt
= maXFIds
.begin(), aEnd
= maXFIds
.end(); aIt
!= aEnd
; ++aIt
)
1053 aIt
->ConvertXFIndex( rRoot
);
1056 void XclExpMultiCellBase::Save( XclExpStream
& rStrm
)
1058 DBG_ASSERT_BIFF( rStrm
.GetRoot().GetBiff() >= EXC_BIFF3
);
1060 XclExpMultiXFIdDeq::const_iterator aEnd
= maXFIds
.end();
1061 XclExpMultiXFIdDeq::const_iterator aRangeBeg
= maXFIds
.begin();
1062 XclExpMultiXFIdDeq::const_iterator aRangeEnd
= aRangeBeg
;
1063 sal_uInt16 nBegXclCol
= GetXclCol();
1064 sal_uInt16 nEndXclCol
= nBegXclCol
;
1066 while( aRangeEnd
!= aEnd
)
1068 // find begin of next used XF range
1069 aRangeBeg
= aRangeEnd
;
1070 nBegXclCol
= nEndXclCol
;
1071 while( (aRangeBeg
!= aEnd
) && (aRangeBeg
->mnXFIndex
== EXC_XF_NOTFOUND
) )
1073 nBegXclCol
= nBegXclCol
+ aRangeBeg
->mnCount
;
1076 // find end of next used XF range
1077 aRangeEnd
= aRangeBeg
;
1078 nEndXclCol
= nBegXclCol
;
1079 while( (aRangeEnd
!= aEnd
) && (aRangeEnd
->mnXFIndex
!= EXC_XF_NOTFOUND
) )
1081 nEndXclCol
= nEndXclCol
+ aRangeEnd
->mnCount
;
1085 // export this range as a record
1086 if( aRangeBeg
!= aRangeEnd
)
1088 sal_uInt16 nCount
= nEndXclCol
- nBegXclCol
;
1089 bool bIsMulti
= nCount
> 1;
1090 sal_Size nTotalSize
= GetRecSize() + (2 + mnContSize
) * nCount
;
1091 if( bIsMulti
) nTotalSize
+= 2;
1093 rStrm
.StartRecord( bIsMulti
? mnMulRecId
: GetRecId(), nTotalSize
);
1094 rStrm
<< GetXclRow() << nBegXclCol
;
1096 sal_uInt16 nRelCol
= nBegXclCol
- GetXclCol();
1097 for( XclExpMultiXFIdDeq::const_iterator aIt
= aRangeBeg
; aIt
!= aRangeEnd
; ++aIt
)
1099 for( sal_uInt16 nIdx
= 0; nIdx
< aIt
->mnCount
; ++nIdx
)
1101 rStrm
<< aIt
->mnXFIndex
;
1102 WriteContents( rStrm
, nRelCol
);
1107 rStrm
<< static_cast< sal_uInt16
>( nEndXclCol
- 1 );
1113 void XclExpMultiCellBase::SaveXml( XclExpXmlStream
& rStrm
)
1115 XclExpMultiXFIdDeq::const_iterator aEnd
= maXFIds
.end();
1116 XclExpMultiXFIdDeq::const_iterator aRangeBeg
= maXFIds
.begin();
1117 XclExpMultiXFIdDeq::const_iterator aRangeEnd
= aRangeBeg
;
1118 sal_uInt16 nBegXclCol
= GetXclCol();
1119 sal_uInt16 nEndXclCol
= nBegXclCol
;
1121 while( aRangeEnd
!= aEnd
)
1123 // find begin of next used XF range
1124 aRangeBeg
= aRangeEnd
;
1125 nBegXclCol
= nEndXclCol
;
1126 while( (aRangeBeg
!= aEnd
) && (aRangeBeg
->mnXFIndex
== EXC_XF_NOTFOUND
) )
1128 nBegXclCol
= nBegXclCol
+ aRangeBeg
->mnCount
;
1131 // find end of next used XF range
1132 aRangeEnd
= aRangeBeg
;
1133 nEndXclCol
= nBegXclCol
;
1134 while( (aRangeEnd
!= aEnd
) && (aRangeEnd
->mnXFIndex
!= EXC_XF_NOTFOUND
) )
1136 nEndXclCol
= nEndXclCol
+ aRangeEnd
->mnCount
;
1140 // export this range as a record
1141 if( aRangeBeg
!= aRangeEnd
)
1143 sal_uInt16 nRelColIdx
= nBegXclCol
- GetXclCol();
1144 sal_Int32 nRelCol
= 0;
1145 for( XclExpMultiXFIdDeq::const_iterator aIt
= aRangeBeg
; aIt
!= aRangeEnd
; ++aIt
)
1147 for( sal_uInt16 nIdx
= 0; nIdx
< aIt
->mnCount
; ++nIdx
)
1151 XclAddress( static_cast<sal_uInt16
>(nBegXclCol
+ nRelCol
), GetXclRow() ),
1162 sal_uInt16
XclExpMultiCellBase::GetCellCount() const
1164 sal_uInt16 nCount
= 0;
1165 for( XclExpMultiXFIdDeq::const_iterator aIt
= maXFIds
.begin(), aEnd
= maXFIds
.end(); aIt
!= aEnd
; ++aIt
)
1166 nCount
= nCount
+ aIt
->mnCount
;
1170 void XclExpMultiCellBase::AppendXFId( const XclExpMultiXFId
& rXFId
)
1172 if( maXFIds
.empty() || (maXFIds
.back().mnXFId
!= rXFId
.mnXFId
) )
1173 maXFIds
.push_back( rXFId
);
1175 maXFIds
.back().mnCount
= maXFIds
.back().mnCount
+ rXFId
.mnCount
;
1178 void XclExpMultiCellBase::AppendXFId( const XclExpRoot
& rRoot
,
1179 const ScPatternAttr
* pPattern
, sal_uInt16 nScript
, sal_uInt32 nForcedXFId
, sal_uInt16 nCount
)
1181 sal_uInt32 nXFId
= (nForcedXFId
== EXC_XFID_NOTFOUND
) ?
1182 rRoot
.GetXFBuffer().Insert( pPattern
, nScript
) : nForcedXFId
;
1183 AppendXFId( XclExpMultiXFId( nXFId
, nCount
) );
1186 bool XclExpMultiCellBase::TryMergeXFIds( const XclExpMultiCellBase
& rCell
)
1188 if( GetLastXclCol() + 1 == rCell
.GetXclCol() )
1190 maXFIds
.insert( maXFIds
.end(), rCell
.maXFIds
.begin(), rCell
.maXFIds
.end() );
1196 void XclExpMultiCellBase::GetXFIndexes( ScfUInt16Vec
& rXFIndexes
) const
1198 DBG_ASSERT( GetLastXclCol() < rXFIndexes
.size(), "XclExpMultiCellBase::GetXFIndexes - vector too small" );
1199 ScfUInt16Vec::iterator aDestIt
= rXFIndexes
.begin() + GetXclCol();
1200 for( XclExpMultiXFIdDeq::const_iterator aIt
= maXFIds
.begin(), aEnd
= maXFIds
.end(); aIt
!= aEnd
; ++aIt
)
1202 ::std::fill( aDestIt
, aDestIt
+ aIt
->mnCount
, aIt
->mnXFIndex
);
1203 aDestIt
+= aIt
->mnCount
;
1207 void XclExpMultiCellBase::RemoveUnusedXFIndexes( const ScfUInt16Vec
& rXFIndexes
)
1209 // save last column before calling maXFIds.clear()
1210 sal_uInt16 nLastXclCol
= GetLastXclCol();
1211 DBG_ASSERT( nLastXclCol
< rXFIndexes
.size(), "XclExpMultiCellBase::RemoveUnusedXFIndexes - XF index vector too small" );
1213 // build new XF index vector, containing passed XF indexes
1215 XclExpMultiXFId
aXFId( 0 );
1216 for( ScfUInt16Vec::const_iterator aIt
= rXFIndexes
.begin() + GetXclCol(), aEnd
= rXFIndexes
.begin() + nLastXclCol
+ 1; aIt
!= aEnd
; ++aIt
)
1218 // AppendXFId() tests XclExpXFIndex::mnXFId, set it too
1219 aXFId
.mnXFId
= aXFId
.mnXFIndex
= *aIt
;
1220 AppendXFId( aXFId
);
1223 // remove leading and trailing unused XF indexes
1224 if( !maXFIds
.empty() && (maXFIds
.front().mnXFIndex
== EXC_XF_NOTFOUND
) )
1226 SetXclCol( GetXclCol() + maXFIds
.front().mnCount
);
1227 maXFIds
.pop_front();
1229 if( !maXFIds
.empty() && (maXFIds
.back().mnXFIndex
== EXC_XF_NOTFOUND
) )
1232 // The Save() function will skip all XF indexes equal to EXC_XF_NOTFOUND.
1235 // ----------------------------------------------------------------------------
1237 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpBlankCell
, 256, 256 )
1239 XclExpBlankCell::XclExpBlankCell( const XclAddress
& rXclPos
, const XclExpMultiXFId
& rXFId
) :
1240 XclExpMultiCellBase( EXC_ID3_BLANK
, EXC_ID_MULBLANK
, 0, rXclPos
)
1242 DBG_ASSERT( rXFId
.mnCount
> 0, "XclExpBlankCell::XclExpBlankCell - invalid count" );
1243 AppendXFId( rXFId
);
1246 XclExpBlankCell::XclExpBlankCell(
1247 const XclExpRoot
& rRoot
, const XclAddress
& rXclPos
, sal_uInt16 nLastXclCol
,
1248 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
) :
1249 XclExpMultiCellBase( EXC_ID3_BLANK
, EXC_ID_MULBLANK
, 0, rXclPos
)
1251 DBG_ASSERT( rXclPos
.mnCol
<= nLastXclCol
, "XclExpBlankCell::XclExpBlankCell - invalid column range" );
1252 // #i46627# use default script type instead of ApiScriptType::WEAK
1253 AppendXFId( rRoot
, pPattern
, rRoot
.GetDefApiScript(), nForcedXFId
, nLastXclCol
- rXclPos
.mnCol
+ 1 );
1256 bool XclExpBlankCell::TryMerge( const XclExpCellBase
& rCell
)
1258 const XclExpBlankCell
* pBlankCell
= dynamic_cast< const XclExpBlankCell
* >( &rCell
);
1259 return pBlankCell
&& TryMergeXFIds( *pBlankCell
);
1262 void XclExpBlankCell::GetBlankXFIndexes( ScfUInt16Vec
& rXFIndexes
) const
1264 GetXFIndexes( rXFIndexes
);
1267 void XclExpBlankCell::RemoveUnusedBlankCells( const ScfUInt16Vec
& rXFIndexes
)
1269 RemoveUnusedXFIndexes( rXFIndexes
);
1272 void XclExpBlankCell::WriteContents( XclExpStream
& /*rStrm*/, sal_uInt16
/*nRelCol*/ )
1276 void XclExpBlankCell::WriteXmlContents( XclExpXmlStream
& rStrm
, const XclAddress
& rAddress
, sal_uInt32 nXFId
, sal_uInt16
/* nRelCol */ )
1278 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1279 rWorksheet
->singleElement( XML_c
,
1280 XML_r
, XclXmlUtils::ToOString( rAddress
).getStr(),
1281 XML_s
, lcl_GetStyleId( rStrm
, nXFId
).getStr(),
1285 // ----------------------------------------------------------------------------
1287 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpRkCell
, 256, 256 )
1289 XclExpRkCell::XclExpRkCell(
1290 const XclExpRoot
& rRoot
, const XclAddress
& rXclPos
,
1291 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
, sal_Int32 nRkValue
) :
1292 XclExpMultiCellBase( EXC_ID_RK
, EXC_ID_MULRK
, 4, rXclPos
)
1294 // #i41210# always use latin script for number cells - may look wrong for special number formats...
1295 AppendXFId( rRoot
, pPattern
, ApiScriptType::LATIN
, nForcedXFId
);
1296 maRkValues
.push_back( nRkValue
);
1299 bool XclExpRkCell::TryMerge( const XclExpCellBase
& rCell
)
1301 const XclExpRkCell
* pRkCell
= dynamic_cast< const XclExpRkCell
* >( &rCell
);
1302 if( pRkCell
&& TryMergeXFIds( *pRkCell
) )
1304 maRkValues
.insert( maRkValues
.end(), pRkCell
->maRkValues
.begin(), pRkCell
->maRkValues
.end() );
1310 void XclExpRkCell::WriteXmlContents( XclExpXmlStream
& rStrm
, const XclAddress
& rAddress
, sal_uInt32 nXFId
, sal_uInt16 nRelCol
)
1312 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1313 rWorksheet
->startElement( XML_c
,
1314 XML_r
, XclXmlUtils::ToOString( rAddress
).getStr(),
1315 XML_s
, lcl_GetStyleId( rStrm
, nXFId
).getStr(),
1317 // OOXTODO: XML_cm, XML_vm, XML_ph
1319 rWorksheet
->startElement( XML_v
, FSEND
);
1320 rWorksheet
->write( XclTools::GetDoubleFromRK( maRkValues
[ nRelCol
] ) );
1321 rWorksheet
->endElement( XML_v
);
1322 rWorksheet
->endElement( XML_c
);
1325 void XclExpRkCell::WriteContents( XclExpStream
& rStrm
, sal_uInt16 nRelCol
)
1327 DBG_ASSERT( nRelCol
< maRkValues
.size(), "XclExpRkCell::WriteContents - overflow error" );
1328 rStrm
<< maRkValues
[ nRelCol
];
1331 // ============================================================================
1333 // ============================================================================
1335 XclExpOutlineBuffer::XclExpOutlineBuffer( const XclExpRoot
& rRoot
, bool bRows
) :
1337 maLevelInfos( SC_OL_MAXDEPTH
),
1339 mbCurrCollapse( false )
1341 if( const ScOutlineTable
* pOutlineTable
= rRoot
.GetDoc().GetOutlineTable( rRoot
.GetCurrScTab() ) )
1342 mpScOLArray
= bRows
? pOutlineTable
->GetRowArray() : pOutlineTable
->GetColArray();
1345 for( USHORT nLevel
= 0; nLevel
< SC_OL_MAXDEPTH
; ++nLevel
)
1346 if( ScOutlineEntry
* pEntry
= mpScOLArray
->GetEntryByPos( nLevel
, 0 ) )
1347 maLevelInfos
[ nLevel
].mnScEndPos
= pEntry
->GetEnd();
1350 void XclExpOutlineBuffer::UpdateColRow( SCCOLROW nScPos
)
1354 // find open level index for passed position
1355 USHORT nNewOpenScLevel
= 0; // new open level (0-based Calc index)
1356 sal_uInt8 nNewLevel
= 0; // new open level (1-based Excel index)
1358 if( mpScOLArray
->FindTouchedLevel( nScPos
, nScPos
, nNewOpenScLevel
) )
1359 nNewLevel
= static_cast< sal_uInt8
>( nNewOpenScLevel
+ 1 );
1360 // else nNewLevel keeps 0 to show that there are no groups
1362 mbCurrCollapse
= false;
1363 if( nNewLevel
>= mnCurrLevel
)
1365 // new level(s) opened, or no level closed - update all level infos
1366 for( USHORT nScLevel
= 0; nScLevel
<= nNewOpenScLevel
; ++nScLevel
)
1368 /* In each level: check if a new group is started (there may be
1369 neighbored groups without gap - therefore check ALL levels). */
1370 if( maLevelInfos
[ nScLevel
].mnScEndPos
< nScPos
)
1372 if( ScOutlineEntry
* pEntry
= mpScOLArray
->GetEntryByPos( nScLevel
, nScPos
) )
1374 maLevelInfos
[ nScLevel
].mnScEndPos
= pEntry
->GetEnd();
1375 maLevelInfos
[ nScLevel
].mbHidden
= pEntry
->IsHidden();
1382 // level(s) closed - check if any of the closed levels are collapsed
1383 // Calc uses 0-based level indexes
1384 USHORT nOldOpenScLevel
= mnCurrLevel
- 1;
1385 for( USHORT nScLevel
= nNewOpenScLevel
+ 1; !mbCurrCollapse
&& (nScLevel
<= nOldOpenScLevel
); ++nScLevel
)
1386 mbCurrCollapse
= maLevelInfos
[ nScLevel
].mbHidden
;
1389 // cache new opened level
1390 mnCurrLevel
= nNewLevel
;
1394 // ----------------------------------------------------------------------------
1396 XclExpGuts::XclExpGuts( const XclExpRoot
& rRoot
) :
1397 XclExpRecord( EXC_ID_GUTS
, 8 ),
1403 if( const ScOutlineTable
* pOutlineTable
= rRoot
.GetDoc().GetOutlineTable( rRoot
.GetCurrScTab() ) )
1405 // column outline groups
1406 if( const ScOutlineArray
* pColArray
= pOutlineTable
->GetColArray() )
1407 mnColLevels
= ulimit_cast
< sal_uInt16
>( pColArray
->GetDepth(), EXC_OUTLINE_MAX
);
1411 mnColWidth
= 12 * mnColLevels
+ 5;
1414 // row outline groups
1415 if( const ScOutlineArray
* pRowArray
= pOutlineTable
->GetRowArray() )
1416 mnRowLevels
= ulimit_cast
< sal_uInt16
>( pRowArray
->GetDepth(), EXC_OUTLINE_MAX
);
1420 mnRowWidth
= 12 * mnRowLevels
+ 5;
1425 void XclExpGuts::WriteBody( XclExpStream
& rStrm
)
1427 rStrm
<< mnRowWidth
<< mnColWidth
<< mnRowLevels
<< mnColLevels
;
1430 // ----------------------------------------------------------------------------
1432 XclExpDimensions::XclExpDimensions( const XclExpRoot
& rRoot
) :
1433 mnFirstUsedXclRow( 0 ),
1434 mnFirstFreeXclRow( 0 ),
1435 mnFirstUsedXclCol( 0 ),
1436 mnFirstFreeXclCol( 0 )
1438 switch( rRoot
.GetBiff() )
1440 case EXC_BIFF2
: SetRecHeader( EXC_ID2_DIMENSIONS
, 8 ); break;
1443 case EXC_BIFF5
: SetRecHeader( EXC_ID3_DIMENSIONS
, 10 ); break;
1444 case EXC_BIFF8
: SetRecHeader( EXC_ID3_DIMENSIONS
, 14 ); break;
1445 default: DBG_ERROR_BIFF();
1449 void XclExpDimensions::SetDimensions(
1450 sal_uInt16 nFirstUsedXclCol
, sal_uInt32 nFirstUsedXclRow
,
1451 sal_uInt16 nFirstFreeXclCol
, sal_uInt32 nFirstFreeXclRow
)
1453 mnFirstUsedXclRow
= nFirstUsedXclRow
;
1454 mnFirstFreeXclRow
= nFirstFreeXclRow
;
1455 mnFirstUsedXclCol
= nFirstUsedXclCol
;
1456 mnFirstFreeXclCol
= nFirstFreeXclCol
;
1459 void XclExpDimensions::SaveXml( XclExpXmlStream
& rStrm
)
1462 aRange
.aStart
.SetRow( (SCROW
) mnFirstUsedXclRow
);
1463 aRange
.aStart
.SetCol( (SCCOL
) mnFirstUsedXclCol
);
1465 if( mnFirstFreeXclRow
!= mnFirstUsedXclRow
&& mnFirstFreeXclCol
!= mnFirstUsedXclCol
)
1467 aRange
.aEnd
.SetRow( (SCROW
) (mnFirstFreeXclRow
-1) );
1468 aRange
.aEnd
.SetCol( (SCCOL
) (mnFirstFreeXclCol
-1) );
1471 rStrm
.GetCurrentStream()->singleElement( XML_dimension
,
1472 XML_ref
, XclXmlUtils::ToOString( aRange
).getStr(),
1476 void XclExpDimensions::WriteBody( XclExpStream
& rStrm
)
1478 XclBiff eBiff
= rStrm
.GetRoot().GetBiff();
1479 if( eBiff
== EXC_BIFF8
)
1480 rStrm
<< mnFirstUsedXclRow
<< mnFirstFreeXclRow
;
1482 rStrm
<< static_cast< sal_uInt16
>( mnFirstUsedXclRow
) << static_cast< sal_uInt16
>( mnFirstFreeXclRow
);
1483 rStrm
<< mnFirstUsedXclCol
<< mnFirstFreeXclCol
;
1484 if( eBiff
>= EXC_BIFF3
)
1485 rStrm
<< sal_uInt16( 0 );
1488 // ============================================================================
1492 double lclGetCorrectedColWidth( const XclExpRoot
& rRoot
, sal_uInt16 nXclColWidth
)
1494 long nFontHt
= rRoot
.GetFontBuffer().GetAppFontData().mnHeight
;
1495 return nXclColWidth
- XclTools::GetXclDefColWidthCorrection( nFontHt
);
1500 // ----------------------------------------------------------------------------
1502 XclExpDefcolwidth::XclExpDefcolwidth( const XclExpRoot
& rRoot
) :
1503 XclExpUInt16Record( EXC_ID_DEFCOLWIDTH
, EXC_DEFCOLWIDTH_DEF
),
1508 bool XclExpDefcolwidth::IsDefWidth( sal_uInt16 nXclColWidth
) const
1510 double fNewColWidth
= lclGetCorrectedColWidth( GetRoot(), nXclColWidth
);
1511 // exactly matched, if difference is less than 1/16 of a character to the left or to the right
1512 return Abs( static_cast< long >( GetValue() * 256.0 - fNewColWidth
+ 0.5 ) ) < 16;
1515 void XclExpDefcolwidth::SetDefWidth( sal_uInt16 nXclColWidth
)
1517 double fNewColWidth
= lclGetCorrectedColWidth( GetRoot(), nXclColWidth
);
1518 SetValue( limit_cast
< sal_uInt16
>( fNewColWidth
/ 256.0 + 0.5 ) );
1521 // ----------------------------------------------------------------------------
1523 XclExpColinfo::XclExpColinfo( const XclExpRoot
& rRoot
,
1524 SCCOL nScCol
, SCROW nLastScRow
, XclExpColOutlineBuffer
& rOutlineBfr
) :
1525 XclExpRecord( EXC_ID_COLINFO
, 12 ),
1526 XclExpRoot( rRoot
),
1529 mnFirstXclCol( static_cast< sal_uInt16
>( nScCol
) ),
1530 mnLastXclCol( static_cast< sal_uInt16
>( nScCol
) )
1532 ScDocument
& rDoc
= GetDoc();
1533 SCTAB nScTab
= GetCurrScTab();
1535 // column default format
1536 maXFId
.mnXFId
= GetXFBuffer().Insert(
1537 rDoc
.GetMostUsedPattern( nScCol
, 0, nLastScRow
, nScTab
), GetDefApiScript() );
1540 USHORT nScWidth
= rDoc
.GetColWidth( nScCol
, nScTab
);
1541 mnWidth
= XclTools::GetXclColumnWidth( nScWidth
, GetCharWidth() );
1544 ::set_flag( mnFlags
, EXC_COLINFO_HIDDEN
, rDoc
.ColHidden(nScCol
, nScTab
) );
1547 rOutlineBfr
.Update( nScCol
);
1548 ::set_flag( mnFlags
, EXC_COLINFO_COLLAPSED
, rOutlineBfr
.IsCollapsed() );
1549 ::insert_value( mnFlags
, rOutlineBfr
.GetLevel(), 8, 3 );
1552 sal_uInt16
XclExpColinfo::ConvertXFIndexes()
1554 maXFId
.ConvertXFIndex( GetRoot() );
1555 return maXFId
.mnXFIndex
;
1558 bool XclExpColinfo::IsDefault( const XclExpDefcolwidth
& rDefColWidth
) const
1560 return (maXFId
.mnXFIndex
== EXC_XF_DEFAULTCELL
) && (mnFlags
== 0) && rDefColWidth
.IsDefWidth( mnWidth
);
1563 bool XclExpColinfo::TryMerge( const XclExpColinfo
& rColInfo
)
1565 if( (maXFId
.mnXFIndex
== rColInfo
.maXFId
.mnXFIndex
) &&
1566 (mnWidth
== rColInfo
.mnWidth
) &&
1567 (mnFlags
== rColInfo
.mnFlags
) &&
1568 (mnLastXclCol
+ 1 == rColInfo
.mnFirstXclCol
) )
1570 mnLastXclCol
= rColInfo
.mnLastXclCol
;
1576 void XclExpColinfo::WriteBody( XclExpStream
& rStrm
)
1578 // if last column is equal to last possible column, Excel adds one more
1579 sal_uInt16 nLastXclCol
= mnLastXclCol
;
1580 if( nLastXclCol
== static_cast< sal_uInt16
>( rStrm
.GetRoot().GetMaxPos().Col() ) )
1583 rStrm
<< mnFirstXclCol
1591 void XclExpColinfo::SaveXml( XclExpXmlStream
& rStrm
)
1593 // if last column is equal to last possible column, Excel adds one more
1594 sal_uInt16 nLastXclCol
= mnLastXclCol
;
1595 if( nLastXclCol
== static_cast< sal_uInt16
>( rStrm
.GetRoot().GetMaxPos().Col() ) )
1598 rStrm
.GetCurrentStream()->singleElement( XML_col
,
1599 // OOXTODO: XML_bestFit,
1600 XML_collapsed
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_COLINFO_COLLAPSED
) ),
1601 // OOXTODO: XML_customWidth,
1602 XML_hidden
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_COLINFO_HIDDEN
) ),
1603 XML_max
, OString::valueOf( (sal_Int32
) (nLastXclCol
+1) ).getStr(),
1604 XML_min
, OString::valueOf( (sal_Int32
) (mnFirstXclCol
+1) ).getStr(),
1605 // OOXTODO: XML_outlineLevel,
1606 // OOXTODO: XML_phonetic,
1607 XML_style
, lcl_GetStyleId( rStrm
, maXFId
.mnXFIndex
).getStr(),
1608 XML_width
, OString::valueOf( (double) (mnWidth
/ 255.0) ).getStr(),
1612 // ----------------------------------------------------------------------------
1614 XclExpColinfoBuffer::XclExpColinfoBuffer( const XclExpRoot
& rRoot
) :
1615 XclExpRoot( rRoot
),
1616 maDefcolwidth( rRoot
),
1617 maOutlineBfr( rRoot
)
1621 void XclExpColinfoBuffer::Initialize( SCROW nLastScRow
)
1624 for( sal_uInt16 nScCol
= 0, nLastScCol
= GetMaxPos().Col(); nScCol
<= nLastScCol
; ++nScCol
)
1625 maColInfos
.AppendNewRecord( new XclExpColinfo( GetRoot(), nScCol
, nLastScRow
, maOutlineBfr
) );
1628 void XclExpColinfoBuffer::Finalize( ScfUInt16Vec
& rXFIndexes
)
1631 rXFIndexes
.reserve( maColInfos
.GetSize() );
1635 // do not cache the record list size, it may change in the loop
1636 for( nPos
= 0; nPos
< maColInfos
.GetSize(); ++nPos
)
1638 XclExpColinfoRef xRec
= maColInfos
.GetRecord( nPos
);
1639 xRec
->ConvertXFIndexes();
1641 // try to merge with previous record
1644 XclExpColinfoRef xPrevRec
= maColInfos
.GetRecord( nPos
- 1 );
1645 if( xPrevRec
->TryMerge( *xRec
) )
1646 // adjust nPos to get the next COLINFO record at the same position
1647 maColInfos
.RemoveRecord( nPos
-- );
1651 // put XF indexes into passed vector, collect use count of all different widths
1652 typedef ::std::map
< sal_uInt16
, sal_uInt16
> XclExpWidthMap
;
1653 XclExpWidthMap aWidthMap
;
1654 sal_uInt16 nMaxColCount
= 0;
1655 sal_uInt16 nMaxUsedWidth
= 0;
1656 for( nPos
= 0, nSize
= maColInfos
.GetSize(); nPos
< nSize
; ++nPos
)
1658 XclExpColinfoRef xRec
= maColInfos
.GetRecord( nPos
);
1659 sal_uInt16 nColCount
= xRec
->GetColCount();
1661 // add XF index to passed vector
1662 rXFIndexes
.resize( rXFIndexes
.size() + nColCount
, xRec
->GetXFIndex() );
1664 // collect use count of column width
1665 sal_uInt16 nWidth
= xRec
->GetColWidth();
1666 sal_uInt16
& rnMapCount
= aWidthMap
[ nWidth
];
1667 rnMapCount
= rnMapCount
+ nColCount
;
1668 if( rnMapCount
> nMaxColCount
)
1670 nMaxColCount
= rnMapCount
;
1671 nMaxUsedWidth
= nWidth
;
1674 maDefcolwidth
.SetDefWidth( nMaxUsedWidth
);
1676 // remove all default COLINFO records
1678 while( nPos
< maColInfos
.GetSize() )
1680 XclExpColinfoRef xRec
= maColInfos
.GetRecord( nPos
);
1681 if( xRec
->IsDefault( maDefcolwidth
) )
1682 maColInfos
.RemoveRecord( nPos
);
1688 void XclExpColinfoBuffer::Save( XclExpStream
& rStrm
)
1691 maDefcolwidth
.Save( rStrm
);
1693 maColInfos
.Save( rStrm
);
1696 void XclExpColinfoBuffer::SaveXml( XclExpXmlStream
& rStrm
)
1698 if( maColInfos
.IsEmpty() )
1701 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1702 rWorksheet
->startElement( XML_cols
,
1704 maColInfos
.SaveXml( rStrm
);
1705 rWorksheet
->endElement( XML_cols
);
1708 // ============================================================================
1710 XclExpDefaultRowData::XclExpDefaultRowData() :
1711 mnFlags( EXC_DEFROW_DEFAULTFLAGS
),
1712 mnHeight( EXC_DEFROW_DEFAULTHEIGHT
)
1716 XclExpDefaultRowData::XclExpDefaultRowData( const XclExpRow
& rRow
) :
1717 mnFlags( EXC_DEFROW_DEFAULTFLAGS
),
1718 mnHeight( rRow
.GetHeight() )
1720 ::set_flag( mnFlags
, EXC_DEFROW_HIDDEN
, rRow
.IsHidden() );
1721 ::set_flag( mnFlags
, EXC_DEFROW_UNSYNCED
, rRow
.IsUnsynced() );
1724 bool operator<( const XclExpDefaultRowData
& rLeft
, const XclExpDefaultRowData
& rRight
)
1726 return (rLeft
.mnHeight
< rRight
.mnHeight
) ||
1727 ((rLeft
.mnHeight
== rRight
.mnHeight
) && (rLeft
.mnFlags
< rRight
.mnFlags
));
1730 // ----------------------------------------------------------------------------
1732 XclExpDefrowheight::XclExpDefrowheight() :
1733 XclExpRecord( EXC_ID3_DEFROWHEIGHT
, 4 )
1737 void XclExpDefrowheight::SetDefaultData( const XclExpDefaultRowData
& rDefData
)
1739 maDefData
= rDefData
;
1742 void XclExpDefrowheight::WriteBody( XclExpStream
& rStrm
)
1744 DBG_ASSERT_BIFF( rStrm
.GetRoot().GetBiff() >= EXC_BIFF3
);
1745 rStrm
<< maDefData
.mnFlags
<< maDefData
.mnHeight
;
1748 // ----------------------------------------------------------------------------
1750 XclExpRow::XclExpRow( const XclExpRoot
& rRoot
, sal_uInt32 nXclRow
,
1751 XclExpRowOutlineBuffer
& rOutlineBfr
, bool bAlwaysEmpty
) :
1752 XclExpRecord( EXC_ID3_ROW
, 16 ),
1753 XclExpRoot( rRoot
),
1754 mnXclRow( nXclRow
),
1756 mnFlags( EXC_ROW_DEFAULTFLAGS
),
1757 mnXFIndex( EXC_XF_DEFAULTCELL
),
1758 mnOutlineLevel( 0 ),
1759 mbAlwaysEmpty( bAlwaysEmpty
),
1762 SCTAB nScTab
= GetCurrScTab();
1763 SCROW nScRow
= static_cast< SCROW
>( mnXclRow
);
1765 // *** Row flags *** ------------------------------------------------------
1767 BYTE nRowFlags
= GetDoc().GetRowFlags( nScRow
, nScTab
);
1768 bool bUserHeight
= ::get_flag
< BYTE
>( nRowFlags
, CR_MANUALSIZE
);
1769 bool bHidden
= GetDoc().RowHidden(nScRow
, nScTab
);
1770 ::set_flag( mnFlags
, EXC_ROW_UNSYNCED
, bUserHeight
);
1771 ::set_flag( mnFlags
, EXC_ROW_HIDDEN
, bHidden
);
1773 // *** Row height *** -----------------------------------------------------
1775 USHORT nScHeight
= GetDoc().GetRowHeight( nScRow
, nScTab
);
1776 if( nScHeight
== 0 )
1778 ::set_flag( mnFlags
, EXC_ROW_HIDDEN
);
1779 mnHeight
= EXC_ROW_DEFAULTHEIGHT
;
1783 // Calc and Excel use twips
1784 mnHeight
= static_cast< sal_uInt16
>( nScHeight
);
1786 // #76250# not usable in Applix
1787 // ::set_flag( mnHeight, EXC_ROW_FLAGDEFHEIGHT, !bUserHeight );
1789 // *** Outline data *** ---------------------------------------------------
1791 rOutlineBfr
.Update( nScRow
);
1792 ::set_flag( mnFlags
, EXC_ROW_COLLAPSED
, rOutlineBfr
.IsCollapsed() );
1793 ::insert_value( mnFlags
, rOutlineBfr
.GetLevel(), 0, 3 );
1794 mnOutlineLevel
= rOutlineBfr
.GetLevel();
1796 // *** Progress bar *** ---------------------------------------------------
1798 XclExpProgressBar
& rProgress
= GetProgressBar();
1799 rProgress
.IncRowRecordCount();
1800 rProgress
.Progress();
1803 void XclExpRow::AppendCell( XclExpCellRef xCell
, bool bIsMergedBase
)
1805 DBG_ASSERT( !mbAlwaysEmpty
, "XclExpRow::AppendCell - row is marked to be always empty" );
1806 // try to merge with last existing cell
1807 InsertCell( xCell
, maCellList
.GetSize(), bIsMergedBase
);
1810 void XclExpRow::Finalize( const ScfUInt16Vec
& rColXFIndexes
)
1814 // *** Convert XF identifiers *** -----------------------------------------
1816 // additionally collect the blank XF indexes
1817 size_t nColCount
= GetMaxPos().Col() + 1;
1818 DBG_ASSERT( rColXFIndexes
.size() == nColCount
, "XclExpRow::Finalize - wrong column XF index count" );
1820 ScfUInt16Vec
aXFIndexes( nColCount
, EXC_XF_NOTFOUND
);
1821 for( nPos
= 0, nSize
= maCellList
.GetSize(); nPos
< nSize
; ++nPos
)
1823 XclExpCellRef xCell
= maCellList
.GetRecord( nPos
);
1824 xCell
->ConvertXFIndexes( GetRoot() );
1825 xCell
->GetBlankXFIndexes( aXFIndexes
);
1828 // *** Fill gaps with BLANK/MULBLANK cell records *** ---------------------
1830 /* This is needed because nonexistant cells in Calc are not formatted at all,
1831 but in Excel they would have the column default format. Blank cells that
1832 are equal to the respective column default are removed later in this function. */
1833 if( !mbAlwaysEmpty
)
1835 // XF identifier representing default cell XF
1836 XclExpMultiXFId
aXFId( XclExpXFBuffer::GetDefCellXFId() );
1837 aXFId
.ConvertXFIndex( GetRoot() );
1840 while( nPos
<= maCellList
.GetSize() ) // don't cache list size, may change in the loop
1842 // get column index that follows previous cell
1843 sal_uInt16 nFirstFreeXclCol
= (nPos
> 0) ? (maCellList
.GetRecord( nPos
- 1 )->GetLastXclCol() + 1) : 0;
1844 // get own column index
1845 sal_uInt16 nNextUsedXclCol
= (nPos
< maCellList
.GetSize()) ? maCellList
.GetRecord( nPos
)->GetXclCol() : (GetMaxPos().Col() + 1);
1848 if( nFirstFreeXclCol
< nNextUsedXclCol
)
1850 aXFId
.mnCount
= nNextUsedXclCol
- nFirstFreeXclCol
;
1851 XclExpCellRef
xNewCell( new XclExpBlankCell( XclAddress( nFirstFreeXclCol
, mnXclRow
), aXFId
) );
1852 // insert the cell, InsertCell() may merge it with existing BLANK records
1853 InsertCell( xNewCell
, nPos
, false );
1854 // insert default XF indexes into aXFIndexes
1855 ::std::fill( aXFIndexes
.begin() + nFirstFreeXclCol
,
1856 aXFIndexes
.begin() + nNextUsedXclCol
, aXFId
.mnXFIndex
);
1857 // don't step forward with nPos, InsertCell() may remove records
1864 // *** Find default row format *** ----------------------------------------
1866 ScfUInt16Vec::iterator aCellBeg
= aXFIndexes
.begin(), aCellEnd
= aXFIndexes
.end(), aCellIt
;
1867 ScfUInt16Vec::const_iterator aColBeg
= rColXFIndexes
.begin(), aColIt
;
1869 // find most used XF index in the row
1870 typedef ::std::map
< sal_uInt16
, size_t > XclExpXFIndexMap
;
1871 XclExpXFIndexMap aIndexMap
;
1872 sal_uInt16 nRowXFIndex
= EXC_XF_DEFAULTCELL
;
1873 size_t nMaxXFCount
= 0;
1874 for( aCellIt
= aCellBeg
; aCellIt
!= aCellEnd
; ++aCellIt
)
1876 if( *aCellIt
!= EXC_XF_NOTFOUND
)
1878 size_t& rnCount
= aIndexMap
[ *aCellIt
];
1880 if( rnCount
> nMaxXFCount
)
1882 nRowXFIndex
= *aCellIt
;
1883 nMaxXFCount
= rnCount
;
1888 // decide whether to use the row default XF index or column default XF indexes
1889 bool bUseColDefXFs
= nRowXFIndex
== EXC_XF_DEFAULTCELL
;
1890 if( !bUseColDefXFs
)
1892 // count needed XF indexes for blank cells with and without row default XF index
1893 size_t nXFCountWithRowDefXF
= 0;
1894 size_t nXFCountWithoutRowDefXF
= 0;
1895 for( aCellIt
= aCellBeg
, aColIt
= aColBeg
; aCellIt
!= aCellEnd
; ++aCellIt
, ++aColIt
)
1897 sal_uInt16 nXFIndex
= *aCellIt
;
1898 if( nXFIndex
!= EXC_XF_NOTFOUND
)
1900 if( nXFIndex
!= nRowXFIndex
)
1901 ++nXFCountWithRowDefXF
; // with row default XF index
1902 if( nXFIndex
!= *aColIt
)
1903 ++nXFCountWithoutRowDefXF
; // without row default XF index
1907 // use column XF indexes if this would cause less or equal number of BLANK records
1908 bUseColDefXFs
= nXFCountWithoutRowDefXF
<= nXFCountWithRowDefXF
;
1911 // *** Remove unused BLANK cell records *** -------------------------------
1915 // use column default XF indexes
1916 // #i194#: remove cell XF indexes equal to column default XF indexes
1917 for( aCellIt
= aCellBeg
, aColIt
= aColBeg
; aCellIt
!= aCellEnd
; ++aCellIt
, ++aColIt
)
1918 if( *aCellIt
== *aColIt
)
1919 *aCellIt
= EXC_XF_NOTFOUND
;
1923 // use row default XF index
1924 mnXFIndex
= nRowXFIndex
;
1925 ::set_flag( mnFlags
, EXC_ROW_USEDEFXF
);
1926 // #98133#, #i194#, #i27407#: remove cell XF indexes equal to row default XF index
1927 for( aCellIt
= aCellBeg
; aCellIt
!= aCellEnd
; ++aCellIt
)
1928 if( *aCellIt
== nRowXFIndex
)
1929 *aCellIt
= EXC_XF_NOTFOUND
;
1932 // remove unused parts of BLANK/MULBLANK cell records
1934 while( nPos
< maCellList
.GetSize() ) // do not cache list size, may change in the loop
1936 XclExpCellRef xCell
= maCellList
.GetRecord( nPos
);
1937 xCell
->RemoveUnusedBlankCells( aXFIndexes
);
1938 if( xCell
->IsEmpty() )
1939 maCellList
.RemoveRecord( nPos
);
1944 // progress bar includes disabled rows
1945 GetProgressBar().Progress();
1948 sal_uInt16
XclExpRow::GetFirstUsedXclCol() const
1950 return maCellList
.IsEmpty() ? 0 : maCellList
.GetFirstRecord()->GetXclCol();
1953 sal_uInt16
XclExpRow::GetFirstFreeXclCol() const
1955 return maCellList
.IsEmpty() ? 0 : (maCellList
.GetLastRecord()->GetLastXclCol() + 1);
1958 bool XclExpRow::IsDefaultable() const
1960 const sal_uInt16 nAllowedFlags
= EXC_ROW_DEFAULTFLAGS
| EXC_ROW_HIDDEN
| EXC_ROW_UNSYNCED
;
1961 return !::get_flag( mnFlags
, static_cast< sal_uInt16
>( ~nAllowedFlags
) ) && IsEmpty();
1964 void XclExpRow::DisableIfDefault( const XclExpDefaultRowData
& rDefRowData
)
1966 mbEnabled
= !IsDefaultable() ||
1967 (mnHeight
!= rDefRowData
.mnHeight
) ||
1968 (IsHidden() != rDefRowData
.IsHidden()) ||
1969 (IsUnsynced() != rDefRowData
.IsUnsynced());
1972 void XclExpRow::WriteCellList( XclExpStream
& rStrm
)
1974 DBG_ASSERT( mbEnabled
|| maCellList
.IsEmpty(), "XclExpRow::WriteCellList - cells in disabled row" );
1975 maCellList
.Save( rStrm
);
1978 void XclExpRow::Save( XclExpStream
& rStrm
)
1981 XclExpRecord::Save( rStrm
);
1984 void XclExpRow::InsertCell( XclExpCellRef xCell
, size_t nPos
, bool bIsMergedBase
)
1986 DBG_ASSERT( xCell
.is(), "XclExpRow::InsertCell - missing cell" );
1988 /* #109751# If we have a multi-line text in a merged cell, and the resulting
1989 row height has not been confirmed, we need to force the EXC_ROW_UNSYNCED
1990 flag to be true to ensure Excel works correctly. */
1991 if( bIsMergedBase
&& xCell
->IsMultiLineText() )
1992 ::set_flag( mnFlags
, EXC_ROW_UNSYNCED
);
1994 // try to merge with previous cell, insert the new cell if not successful
1995 XclExpCellRef xPrevCell
= maCellList
.GetRecord( nPos
- 1 );
1996 if( xPrevCell
.is() && xPrevCell
->TryMerge( *xCell
) )
1999 maCellList
.InsertRecord( xCell
, nPos
++ );
2000 // nPos points now to following cell
2002 // try to merge with following cell, remove it if successful
2003 XclExpCellRef xNextCell
= maCellList
.GetRecord( nPos
);
2004 if( xNextCell
.is() && xCell
->TryMerge( *xNextCell
) )
2005 maCellList
.RemoveRecord( nPos
);
2008 void XclExpRow::WriteBody( XclExpStream
& rStrm
)
2011 << GetFirstUsedXclCol()
2012 << GetFirstFreeXclCol()
2019 void XclExpRow::SaveXml( XclExpXmlStream
& rStrm
)
2023 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
2024 bool haveFormat
= ::get_flag( mnFlags
, EXC_ROW_USEDEFXF
);
2025 rWorksheet
->startElement( XML_row
,
2026 XML_r
, OString::valueOf( (sal_Int32
) (mnXclRow
+1) ).getStr(),
2027 // OOXTODO: XML_spans, optional
2028 XML_s
, haveFormat
? lcl_GetStyleId( rStrm
, mnXFIndex
).getStr() : NULL
,
2029 XML_customFormat
, XclXmlUtils::ToPsz( haveFormat
),
2030 XML_ht
, OString::valueOf( (double) mnHeight
/ 20.0 ).getStr(),
2031 XML_hidden
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_ROW_HIDDEN
) ),
2032 XML_customHeight
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_ROW_UNSYNCED
) ),
2033 XML_outlineLevel
, OString::valueOf( (sal_Int32
) mnOutlineLevel
).getStr(),
2034 XML_collapsed
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_ROW_COLLAPSED
) ),
2035 // OOXTODO: XML_thickTop, bool
2036 // OOXTODO: XML_thickBot, bool
2037 // OOXTODO: XML_ph, bool
2039 // OOXTODO: XML_extLst
2040 maCellList
.SaveXml( rStrm
);
2041 rWorksheet
->endElement( XML_row
);
2044 // ----------------------------------------------------------------------------
2046 XclExpRowBuffer::XclExpRowBuffer( const XclExpRoot
& rRoot
) :
2047 XclExpRoot( rRoot
),
2048 maOutlineBfr( rRoot
),
2049 maDimensions( rRoot
),
2051 mnLastUsedXclRow( 0 )
2055 void XclExpRowBuffer::AppendCell( XclExpCellRef xCell
, bool bIsMergedBase
)
2057 DBG_ASSERT( xCell
.is(), "XclExpRowBuffer::AppendCell - missing cell" );
2058 GetOrCreateRow( xCell
->GetXclRow(), false ).AppendCell( xCell
, bIsMergedBase
);
2061 void XclExpRowBuffer::CreateRows( SCROW nFirstFreeScRow
)
2063 if( nFirstFreeScRow
> 0 )
2064 GetOrCreateRow( static_cast< sal_uInt32
>( nFirstFreeScRow
- 1 ), true );
2067 void XclExpRowBuffer::Finalize( XclExpDefaultRowData
& rDefRowData
, const ScfUInt16Vec
& rColXFIndexes
)
2071 // *** Finalize all rows *** ----------------------------------------------
2073 GetProgressBar().ActivateFinalRowsSegment();
2075 // unused blank cell records will be removed
2076 for( nPos
= 0, nSize
= maRowList
.GetSize(); nPos
< nSize
; ++nPos
)
2077 maRowList
.GetRecord( nPos
)->Finalize( rColXFIndexes
);
2079 // *** Default row format *** ---------------------------------------------
2081 typedef ::std::map
< XclExpDefaultRowData
, size_t > XclExpDefRowDataMap
;
2082 XclExpDefRowDataMap aDefRowMap
;
2084 // find default row format for rows beyond used area
2085 sal_uInt32 nDefaultXclRow
= maRowList
.IsEmpty() ? 0 : (maRowList
.GetLastRecord()->GetXclRow() + 1);
2086 XclExpDefaultRowData aMaxDefData
;
2087 size_t nMaxDefCount
= 0;
2088 /* #i30411# Files saved with SO7/OOo1.x with nonstandard default column
2089 formatting cause big Excel files, because all rows from row 1 to row
2090 32000 are exported. Now, if the used area goes exactly to row 32000,
2091 ignore all rows >32000.
2092 #i59220# Tolerance of +-128 rows for inserted/removed rows. */
2093 if( (nDefaultXclRow
< 31872) || (nDefaultXclRow
> 32128) )
2095 sal_uInt32 nLastXclRow
= static_cast< sal_uInt32
>( GetMaxPos().Row() );
2096 if( nDefaultXclRow
<= nLastXclRow
)
2098 // create a dummy ROW record and fill aMaxDefData
2099 XclExpRowOutlineBuffer
aOutlineBfr( GetRoot() );
2100 XclExpRow
aRow( GetRoot(), nLastXclRow
, aOutlineBfr
, true );
2101 aMaxDefData
= XclExpDefaultRowData( aRow
);
2102 aDefRowMap
[ aMaxDefData
] = nMaxDefCount
=
2103 static_cast< size_t >( nLastXclRow
- nDefaultXclRow
+ 1 );
2107 // only look for default format in existing rows, if there are more than unused
2108 nSize
= maRowList
.GetSize();
2109 if( nMaxDefCount
< nSize
)
2111 for( nPos
= 0; nPos
< nSize
; ++nPos
)
2113 XclExpRowRef xRow
= maRowList
.GetRecord( nPos
);
2114 /* Collect formats of unused rows (rows without cells), which are able
2115 to be defaulted (i.e. no explicit format or outline level). */
2116 if( xRow
->IsDefaultable() )
2118 XclExpDefaultRowData
aDefData( *xRow
);
2119 size_t& rnDefCount
= aDefRowMap
[ aDefData
];
2121 if( rnDefCount
> nMaxDefCount
)
2123 nMaxDefCount
= rnDefCount
;
2124 aMaxDefData
= aDefData
;
2130 // return the default row format to caller
2131 rDefRowData
= aMaxDefData
;
2133 // *** Disable unused ROW records, find used area *** ---------------------
2135 sal_uInt16 nFirstUsedXclCol
= SAL_MAX_UINT16
;
2136 sal_uInt16 nFirstFreeXclCol
= 0;
2137 sal_uInt32 nFirstUsedXclRow
= SAL_MAX_UINT32
;
2138 sal_uInt32 nFirstFreeXclRow
= 0;
2140 for( nPos
= 0, nSize
= maRowList
.GetSize(); nPos
< nSize
; ++nPos
)
2142 XclExpRowRef xRow
= maRowList
.GetRecord( nPos
);
2144 // disable unused rows
2145 xRow
->DisableIfDefault( aMaxDefData
);
2147 // find used column range
2148 if( !xRow
->IsEmpty() ) // empty rows return (0...0) as used range
2150 nFirstUsedXclCol
= ::std::min( nFirstUsedXclCol
, xRow
->GetFirstUsedXclCol() );
2151 nFirstFreeXclCol
= ::std::max( nFirstFreeXclCol
, xRow
->GetFirstFreeXclCol() );
2154 // find used row range
2155 if( xRow
->IsEnabled() )
2157 sal_uInt32 nXclRow
= xRow
->GetXclRow();
2158 nFirstUsedXclRow
= ::std::min
< sal_uInt32
>( nFirstUsedXclRow
, nXclRow
);
2159 nFirstFreeXclRow
= ::std::max
< sal_uInt32
>( nFirstFreeXclRow
, nXclRow
+ 1 );
2163 // adjust start position, if there are no or only empty/disabled ROW records
2164 nFirstUsedXclCol
= ::std::min( nFirstUsedXclCol
, nFirstFreeXclCol
);
2165 nFirstUsedXclRow
= ::std::min( nFirstUsedXclRow
, nFirstFreeXclRow
);
2167 // initialize the DIMENSIONS record
2168 maDimensions
.SetDimensions(
2169 nFirstUsedXclCol
, nFirstUsedXclRow
, nFirstFreeXclCol
, nFirstFreeXclRow
);
2172 void XclExpRowBuffer::Save( XclExpStream
& rStrm
)
2174 // DIMENSIONS record
2175 maDimensions
.Save( rStrm
);
2177 // save in blocks of 32 rows, each block contains first all ROWs, then all cells
2178 size_t nSize
= maRowList
.GetSize();
2179 size_t nBlockStart
= 0;
2180 sal_uInt32 nStartXclRow
= (nSize
== 0) ? 0 : maRowList
.GetRecord( 0 )->GetXclRow();
2182 while( nBlockStart
< nSize
)
2184 // find end of row block
2185 size_t nBlockEnd
= nBlockStart
+ 1;
2186 while( (nBlockEnd
< nSize
) && (maRowList
.GetRecord( nBlockEnd
)->GetXclRow() - nStartXclRow
< EXC_ROW_ROWBLOCKSIZE
) )
2189 // write the ROW records
2191 for( nPos
= nBlockStart
; nPos
< nBlockEnd
; ++nPos
)
2192 maRowList
.GetRecord( nPos
)->Save( rStrm
);
2194 // write the cell records
2195 for( nPos
= nBlockStart
; nPos
< nBlockEnd
; ++nPos
)
2196 maRowList
.GetRecord( nPos
)->WriteCellList( rStrm
);
2198 nBlockStart
= nBlockEnd
;
2199 nStartXclRow
+= EXC_ROW_ROWBLOCKSIZE
;
2203 void XclExpRowBuffer::SaveXml( XclExpXmlStream
& rStrm
)
2205 sal_Int32 nNonEmpty
= 0;
2207 size_t nRows
= maRowList
.GetSize();
2208 for( size_t i
= 0; i
< nRows
; ++i
)
2209 if( maRowList
.GetRecord( i
)->IsEnabled() )
2212 if( nNonEmpty
== 0 )
2214 rStrm
.GetCurrentStream()->singleElement( XML_sheetData
, FSEND
);
2218 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
2219 rWorksheet
->startElement( XML_sheetData
, FSEND
);
2220 maRowList
.SaveXml( rStrm
);
2221 rWorksheet
->endElement( XML_sheetData
);
2225 XclExpDimensions
* XclExpRowBuffer::GetDimensions()
2227 return &maDimensions
;
2230 XclExpRow
& XclExpRowBuffer::GetOrCreateRow( sal_uInt32 nXclRow
, bool bRowAlwaysEmpty
)
2232 if( !mpLastUsedRow
|| (mnLastUsedXclRow
!= nXclRow
) )
2234 // fill up missing ROW records
2235 // do not use sal_uInt16 for nFirstFreeXclRow, would cause loop in full sheets
2236 for( size_t nFirstFreeXclRow
= maRowList
.GetSize(); nFirstFreeXclRow
<= nXclRow
; ++nFirstFreeXclRow
)
2237 maRowList
.AppendNewRecord( new XclExpRow(
2238 GetRoot(), static_cast< sal_uInt32
>( nFirstFreeXclRow
), maOutlineBfr
, bRowAlwaysEmpty
) );
2240 mpLastUsedRow
= maRowList
.GetRecord( nXclRow
).get();
2241 mnLastUsedXclRow
= nXclRow
;
2243 return *mpLastUsedRow
;
2246 // ============================================================================
2248 // ============================================================================
2250 XclExpCellTable::XclExpCellTable( const XclExpRoot
& rRoot
) :
2251 XclExpRoot( rRoot
),
2252 maColInfoBfr( rRoot
),
2254 maArrayBfr( rRoot
),
2255 maShrfmlaBfr( rRoot
),
2256 maTableopBfr( rRoot
),
2257 mxDefrowheight( new XclExpDefrowheight
),
2258 mxGuts( new XclExpGuts( rRoot
) ),
2259 mxNoteList( new XclExpNoteList
),
2260 mxMergedcells( new XclExpMergedcells( rRoot
) ),
2261 mxHyperlinkList( new XclExpHyperlinkList
),
2262 mxDval( new XclExpDval( rRoot
) )
2264 ScDocument
& rDoc
= GetDoc();
2265 SCTAB nScTab
= GetCurrScTab();
2266 SvNumberFormatter
& rFormatter
= GetFormatter();
2268 // maximum sheet limits
2269 SCCOL nMaxScCol
= GetMaxPos().Col();
2270 SCROW nMaxScRow
= GetMaxPos().Row();
2272 // find used area (non-empty cells)
2273 SCCOL nLastUsedScCol
;
2274 SCROW nLastUsedScRow
;
2275 rDoc
.GetTableArea( nScTab
, nLastUsedScCol
, nLastUsedScRow
);
2277 ScRange
aUsedRange( 0, 0, nScTab
, nLastUsedScCol
, nLastUsedScRow
, nScTab
);
2278 GetAddressConverter().ValidateRange( aUsedRange
, true );
2279 nLastUsedScCol
= aUsedRange
.aEnd
.Col();
2280 nLastUsedScRow
= aUsedRange
.aEnd
.Row();
2282 // first row without any set attributes (height/hidden/...)
2283 SCROW nFirstUnflaggedScRow
= rDoc
.GetLastFlaggedRow( nScTab
) + 1;
2285 // find range of outlines
2286 SCROW nFirstUngroupedScRow
= 0;
2287 if( const ScOutlineTable
* pOutlineTable
= rDoc
.GetOutlineTable( nScTab
) )
2289 SCCOLROW nScStartPos
, nScEndPos
;
2290 if( const ScOutlineArray
* pRowArray
= pOutlineTable
->GetRowArray() )
2292 pRowArray
->GetRange( nScStartPos
, nScEndPos
);
2293 // +1 because open/close button is in next row in Excel, +1 for "end->first unused"
2294 nFirstUngroupedScRow
= static_cast< SCROW
>( nScEndPos
+ 2 );
2299 /* #i30411# Files saved with SO7/OOo1.x with nonstandard default column
2300 formatting cause big Excel files, because all rows from row 1 to row
2301 32000 are exported. Now, if the used area goes exactly to row 32000,
2302 use this row as default and ignore all rows >32000.
2303 #i59220# Tolerance of +-128 rows for inserted/removed rows. */
2304 if( (31871 <= nLastUsedScRow
) && (nLastUsedScRow
<= 32127) && (nFirstUnflaggedScRow
< nLastUsedScRow
) && (nFirstUngroupedScRow
<= nLastUsedScRow
) )
2305 nMaxScRow
= nLastUsedScRow
;
2306 maColInfoBfr
.Initialize( nMaxScRow
);
2308 // range for cell iterator
2309 SCCOL nLastIterScCol
= nMaxScCol
;
2310 SCROW nLastIterScRow
= ulimit_cast
< SCROW
>( nLastUsedScRow
+ 128, nMaxScRow
);
2311 ScUsedAreaIterator
aIt( &rDoc
, nScTab
, 0, 0, nLastIterScCol
, nLastIterScRow
);
2313 // activate the correct segment and sub segment at the progress bar
2314 GetProgressBar().ActivateCreateRowsSegment();
2316 for( bool bIt
= aIt
.GetNext(); bIt
; bIt
= aIt
.GetNext() )
2318 SCCOL nScCol
= aIt
.GetStartCol();
2319 SCROW nScRow
= aIt
.GetRow();
2320 SCCOL nLastScCol
= aIt
.GetEndCol();
2321 ScAddress
aScPos( nScCol
, nScRow
, nScTab
);
2323 XclAddress
aXclPos( static_cast< sal_uInt16
>( nScCol
), static_cast< sal_uInt32
>( nScRow
) );
2324 sal_uInt16 nLastXclCol
= static_cast< sal_uInt16
>( nLastScCol
);
2326 const ScBaseCell
* pScCell
= aIt
.GetCell();
2327 XclExpCellRef xCell
;
2329 const ScPatternAttr
* pPattern
= aIt
.GetPattern();
2331 // handle overlapped merged cells before creating the cell record
2332 sal_uInt32 nMergeBaseXFId
= EXC_XFID_NOTFOUND
;
2333 bool bIsMergedBase
= false;
2336 const SfxItemSet
& rItemSet
= pPattern
->GetItemSet();
2337 // base cell in a merged range
2338 const ScMergeAttr
& rMergeItem
= GETITEM( rItemSet
, ScMergeAttr
, ATTR_MERGE
);
2339 bIsMergedBase
= rMergeItem
.IsMerged();
2340 /* overlapped cell in a merged range; in Excel all merged cells
2341 must contain same XF index, for correct border */
2342 const ScMergeFlagAttr
& rMergeFlagItem
= GETITEM( rItemSet
, ScMergeFlagAttr
, ATTR_MERGE_FLAG
);
2343 if( rMergeFlagItem
.IsOverlapped() )
2344 nMergeBaseXFId
= mxMergedcells
->GetBaseXFId( aScPos
);
2347 String aAddNoteText
; // additional text to be appended to a note
2349 CellType eCellType
= pScCell
? pScCell
->GetCellType() : CELLTYPE_NONE
;
2352 case CELLTYPE_VALUE
:
2354 double fValue
= static_cast< const ScValueCell
* >( pScCell
)->GetValue();
2356 // try to create a Boolean cell
2357 if( pPattern
&& ((fValue
== 0.0) || (fValue
== 1.0)) )
2359 ULONG nScNumFmt
= GETITEMVALUE( pPattern
->GetItemSet(), SfxUInt32Item
, ATTR_VALUE_FORMAT
, ULONG
);
2360 if( rFormatter
.GetType( nScNumFmt
) == NUMBERFORMAT_LOGICAL
)
2361 xCell
.reset( new XclExpBooleanCell(
2362 GetRoot(), aXclPos
, pPattern
, nMergeBaseXFId
, fValue
!= 0.0 ) );
2365 // try to create an RK value (compressed floating-point number)
2367 if( !xCell
&& XclTools::GetRKFromDouble( nRkValue
, fValue
) )
2368 xCell
.reset( new XclExpRkCell(
2369 GetRoot(), aXclPos
, pPattern
, nMergeBaseXFId
, nRkValue
) );
2371 // else: simple floating-point number cell
2373 xCell
.reset( new XclExpNumberCell(
2374 GetRoot(), aXclPos
, pPattern
, nMergeBaseXFId
, fValue
) );
2378 case CELLTYPE_STRING
:
2380 const ScStringCell
& rScStrCell
= *static_cast< const ScStringCell
* >( pScCell
);
2381 xCell
.reset( new XclExpLabelCell(
2382 GetRoot(), aXclPos
, pPattern
, nMergeBaseXFId
, rScStrCell
) );
2388 const ScEditCell
& rScEditCell
= *static_cast< const ScEditCell
* >( pScCell
);
2389 XclExpHyperlinkHelper
aLinkHelper( GetRoot(), aScPos
);
2390 xCell
.reset( new XclExpLabelCell(
2391 GetRoot(), aXclPos
, pPattern
, nMergeBaseXFId
, rScEditCell
, aLinkHelper
) );
2393 // add a single created HLINK record to the record list
2394 if( aLinkHelper
.HasLinkRecord() )
2395 mxHyperlinkList
->AppendRecord( aLinkHelper
.GetLinkRecord() );
2396 // add list of multiple URLs to the additional cell note text
2397 if( aLinkHelper
.HasMultipleUrls() )
2398 ScGlobal::AddToken( aAddNoteText
, aLinkHelper
.GetUrlList(), '\n', 2 );
2402 case CELLTYPE_FORMULA
:
2404 const ScFormulaCell
& rScFmlaCell
= *static_cast< const ScFormulaCell
* >( pScCell
);
2405 xCell
.reset( new XclExpFormulaCell(
2406 GetRoot(), aXclPos
, pPattern
, nMergeBaseXFId
,
2407 rScFmlaCell
, maArrayBfr
, maShrfmlaBfr
, maTableopBfr
) );
2412 DBG_ERRORFILE( "XclExpCellTable::XclExpCellTable - unknown cell type" );
2417 xCell
.reset( new XclExpBlankCell(
2418 GetRoot(), aXclPos
, nLastXclCol
, pPattern
, nMergeBaseXFId
) );
2423 // insert the cell into the current row
2425 maRowBfr
.AppendCell( xCell
, bIsMergedBase
);
2428 const ScPostIt
* pScNote
= pScCell
? pScCell
->GetNote() : 0;
2429 if( pScNote
|| (aAddNoteText
.Len() > 0) )
2430 mxNoteList
->AppendNewRecord( new XclExpNote( GetRoot(), aScPos
, pScNote
, aAddNoteText
) );
2432 // other sheet contents
2435 const SfxItemSet
& rItemSet
= pPattern
->GetItemSet();
2437 // base cell in a merged range
2440 const ScMergeAttr
& rMergeItem
= GETITEM( rItemSet
, ScMergeAttr
, ATTR_MERGE
);
2441 ScRange
aScRange( aScPos
);
2442 aScRange
.aEnd
.IncCol( rMergeItem
.GetColMerge() - 1 );
2443 aScRange
.aEnd
.IncRow( rMergeItem
.GetRowMerge() - 1 );
2444 sal_uInt32 nXFId
= xCell
.is() ? xCell
->GetFirstXFId() : EXC_XFID_NOTFOUND
;
2445 // #120156# blank cells merged vertically may occur repeatedly
2446 DBG_ASSERT( (aScRange
.aStart
.Col() == aScRange
.aEnd
.Col()) || (nScCol
== nLastScCol
),
2447 "XclExpCellTable::XclExpCellTable - invalid repeated blank merged cell" );
2448 for( SCCOL nIndex
= nScCol
; nIndex
<= nLastScCol
; ++nIndex
)
2450 mxMergedcells
->AppendRange( aScRange
, nXFId
);
2451 aScRange
.aStart
.IncCol();
2452 aScRange
.aEnd
.IncCol();
2457 if( ScfTools::CheckItem( rItemSet
, ATTR_VALIDDATA
, false ) )
2459 ULONG nScHandle
= GETITEMVALUE( rItemSet
, SfxUInt32Item
, ATTR_VALIDDATA
, ULONG
);
2460 ScRange
aScRange( aScPos
);
2461 aScRange
.aEnd
.SetCol( nLastScCol
);
2462 mxDval
->InsertCellRange( aScRange
, nScHandle
);
2467 // create missing row settings for rows anyhow flagged or with outlines
2468 maRowBfr
.CreateRows( ::std::max( nFirstUnflaggedScRow
, nFirstUngroupedScRow
) );
2471 void XclExpCellTable::Finalize()
2473 // Finalize multiple operations.
2474 maTableopBfr
.Finalize();
2476 /* Finalize column buffer. This calculates column default XF indexes from
2477 the XF identifiers and fills a vector with these XF indexes. */
2478 ScfUInt16Vec aColXFIndexes
;
2479 maColInfoBfr
.Finalize( aColXFIndexes
);
2481 /* Finalize row buffer. This calculates all cell XF indexes from the XF
2482 identifiers. Then the XF index vector aColXFIndexes (filled above) is
2483 used to calculate the row default formats. With this, all unneeded blank
2484 cell records (equal to row default or column default) will be removed.
2485 The function returns the (most used) default row format in aDefRowData. */
2486 XclExpDefaultRowData aDefRowData
;
2487 maRowBfr
.Finalize( aDefRowData
, aColXFIndexes
);
2489 // Initialize the DEFROWHEIGHT record.
2490 mxDefrowheight
->SetDefaultData( aDefRowData
);
2493 XclExpRecordRef
XclExpCellTable::CreateRecord( sal_uInt16 nRecId
) const
2495 XclExpRecordRef xRec
;
2498 case EXC_ID3_DIMENSIONS
: xRec
.reset( new XclExpDelegatingRecord( const_cast<XclExpRowBuffer
*>(&maRowBfr
)->GetDimensions() ) ); break;
2499 case EXC_ID2_DEFROWHEIGHT
: xRec
= mxDefrowheight
; break;
2500 case EXC_ID_GUTS
: xRec
= mxGuts
; break;
2501 case EXC_ID_NOTE
: xRec
= mxNoteList
; break;
2502 case EXC_ID_MERGEDCELLS
: xRec
= mxMergedcells
; break;
2503 case EXC_ID_HLINK
: xRec
= mxHyperlinkList
; break;
2504 case EXC_ID_DVAL
: xRec
= mxDval
; break;
2505 default: DBG_ERRORFILE( "XclExpCellTable::CreateRecord - unknown record id" );
2510 void XclExpCellTable::Save( XclExpStream
& rStrm
)
2512 // DEFCOLWIDTH and COLINFOs
2513 maColInfoBfr
.Save( rStrm
);
2514 // ROWs and cell records
2515 maRowBfr
.Save( rStrm
);
2518 void XclExpCellTable::SaveXml( XclExpXmlStream
& rStrm
)
2520 maColInfoBfr
.SaveXml( rStrm
);
2521 maRowBfr
.SaveXml( rStrm
);
2524 // ============================================================================